Closed AmirSalahY closed 1 year ago
Hey @AmirSalahY - can you please share a mobileToken
and how you invoke the SDK?
Hi @AmirSalahY, thanks for the report. However, we need way more context to figure out what could cause your issue and to reproduce it. OS, simulator or device, hardware, dev environment, frameworks & tools used, what are you doing in the code exactly, and so on.
package com.reactnativedatatrans;
import android.app.Activity;
import android.content.Context;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import org.jetbrains.annotations.NotNull;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import ch.datatrans.payment.api.Transaction;
import ch.datatrans.payment.api.TransactionListener;
import ch.datatrans.payment.api.TransactionRegistry;
import ch.datatrans.payment.api.TransactionSuccess;
import ch.datatrans.payment.api.tokenization.PCIPCardInfo;
import ch.datatrans.payment.exception.TransactionException;
import ch.datatrans.payment.paymentmethods.Card;
import ch.datatrans.payment.paymentmethods.CardExpiryDate;
import ch.datatrans.payment.paymentmethods.PaymentMethodType;
import ch.datatrans.payment.paymentmethods.SavedCard;
import ch.datatrans.payment.paymentmethods.SavedPaymentMethod;
public class DatatransModule extends ReactContextBaseJavaModule{
public static final String NAME = "Datatrans";
private Context mActivityContext;
private final String CALLBACK_TYPE_SUCCESS = "success";
private final String CALLBACK_TYPE_ERROR = "error";
private final String CALLBACK_TYPE_CANCEL = "cancel";
private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
private JSONArray jsonarray;
private JSONObject jsonobject;
private WritableMap mapObj;
//private Callback mTokenCallback;
private Promise mPromise;
public DatatransModule(ReactApplicationContext reactContext) {
super(reactContext);
// mActivityContext = activityContext;
}
@Override
@NonNull
public String getName() {
return NAME;
}
@ReactMethod
public void logData(String name, String text) {
Log.d("CalendarModule", "Create event called with name: " + name
+ " and location: " + text);
}
// Example method
// See https://reactnative.dev/docs/native-modules-android
@ReactMethod
public void transaction(String mobileToken, ReadableMap options, final Promise promise) {
ReactApplicationContext context = getReactApplicationContext();
Activity activity = getCurrentActivity();
mPromise = promise;
if (activity == null) {
WritableMap map = Arguments.createMap();
map.putString("message", "Activity doesn't exist");
consumeCallback(E_ACTIVITY_DOES_NOT_EXIST, map);
return;
}
//aliasPaymentMethods
if (activity != null) {
//Intent intent = new Intent(context, ExternalProcessRelayActivity.class);
// activity.startActivity(intent);
Transaction transaction;
try {
Collection paymentCollection= new ArrayList();
ReadableArray aliasPaymentMethods;//=new ArrayList<>();
aliasPaymentMethods=options.getArray("aliasPaymentMethods");
//aliasPaymentMethods.get
// List<PaymentMethodType> paymentMethodTypes = new ArrayList<>();
List<SavedPaymentMethod> paymentMethodTypes = new ArrayList<>();
//Log.d("myTag", aliasPaymentMethods.toString());
for(int i = 0; i < aliasPaymentMethods.size(); i++)
{
ReadableMap apm;
apm=aliasPaymentMethods.getMap(i);
//playersObjects[i] = new PlayerScores(); //make the object so we can access it
//playersObjects[i].playerNameSet(name variable);
//PaymentMethodType.valueOf(apm.getString("paymentMethods"));
// PaymentMethodType pmtype=new PaymentMethodType(aliasPaymentMethods.getString("paymentMethods"));
//pmtype=aliasPaymentMethods.getString("paymentMethods");
CardExpiryDate ced=new CardExpiryDate(apm.getInt("expiryMonth"),apm.getInt("expiryYear"));
// PaymentMethodType.VISA.getIdentifier();
// Log.d("Visssssss",PaymentMethodType.VISA.toString());
// Log.d("fromIdentifier", PaymentMethodType.fromIdentifier(apm.getString("paymentMethods")).toString());
// CardToken ct=new CardToken(PaymentMethodType.fromIdentifier(apm.getString("paymentMethods")),apm.getString("alias"),ced,apm.getString("ccNumber"),"");
SavedCard ct=new SavedCard(PaymentMethodType.fromIdentifier(apm.getString("paymentMethods")),apm.getString("alias"),ced,apm.getString("ccNumber"),"");
paymentMethodTypes.add(ct);
// SavedPaymentMethod spm = new SavedPaymentMethod(PaymentMethodType.fromIdentifier(apm.getString("paymentMethods")),apm.getString("alias"));
// paymentMethodTypes.add(spm);
}
//modules.add(new DatatransModule(reactContext));
if(paymentMethodTypes.size()>0) {
transaction = new Transaction(mobileToken, (List<? extends SavedPaymentMethod>) paymentMethodTypes);
}
else{
transaction = new Transaction(mobileToken);
}
// transaction = new Transaction(mobileToken);
TransactionListener transactionListener= new TransactionListener() {
@Override
public void onTransactionCancel() {
WritableMap map = Arguments.createMap();
WritableMap data = Arguments.createMap();
map.putMap("data",data);
map.putString("action","Cancel");
Toast.makeText(getReactApplicationContext(), "Cancel", Toast.LENGTH_LONG).show();
mapObj=map;
consumeCallback(CALLBACK_TYPE_CANCEL, map);
}
@Override
public void onTransactionError(@NotNull TransactionException e) {
WritableMap map = Arguments.createMap();
WritableMap data = Arguments.createMap();
data.putString("transactionId", e.getTransactionId());
data.putString("message", e.getMessage());
data.putString("paymentMethodType", e.getPaymentMethodType().getIdentifier());
map.putMap("data",data);
map.putString("action","Error");
Toast.makeText(getReactApplicationContext(), "Error", Toast.LENGTH_LONG).show();
mapObj=map;
consumeCallback(CALLBACK_TYPE_ERROR, map);
}
@Override
public void onTransactionSuccess(@NotNull TransactionSuccess transactionSuccess) {
WritableMap map = Arguments.createMap();
WritableMap data = Arguments.createMap();
data.putString("transactionId", transactionSuccess.getTransactionId());
data.putString("paymentMethodToken",""); //transactionSuccess.getPaymentMethodToken().toString()
data.putString("paymentMethodType", transactionSuccess.getPaymentMethodType().getIdentifier());
map.putMap("data",data);
map.putString("action","Finish");
Toast.makeText(getReactApplicationContext(), "Success", Toast.LENGTH_LONG).show();
mapObj=map;
consumeCallback(CALLBACK_TYPE_SUCCESS, map);
}
};
transaction.setListener(transactionListener); // this refers to Android's Activity
transaction.getOptions().setAppCallbackScheme(options.getString("appCallbackScheme"));
transaction.getOptions().setTesting(options.getBoolean("isTesting") );
transaction.getOptions().setUseCertificatePinning(options.getBoolean("isUseCertificatePinning"));
TransactionRegistry.INSTANCE.startTransaction(activity, transaction);
} catch (Exception e) {
promise.reject(e);
}
}
}
private void consumeCallback(String type, WritableMap map) {
if (mPromise != null) {
map.putString("type", type);
map.putString("provider", "ct-datatrans");
mPromise.resolve(map);
mPromise = null;
}
}
@ReactMethod
public void multiply(int a, int b, Promise promise) {
promise.resolve(a * b);
}
public static native int nativeMultiply(int a, int b);
}
OR THIS
package com.reactnativedatatrans;
import android.app.Activity;
import android.util.Log;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import ch.datatrans.payment.api.Transaction;
import ch.datatrans.payment.api.TransactionListener;
import ch.datatrans.payment.api.TransactionRegistry;
import ch.datatrans.payment.api.TransactionSuccess;
import ch.datatrans.payment.api.tokenization.PCIPCardInfo;
import ch.datatrans.payment.exception.TransactionException;
import ch.datatrans.payment.paymentmethods.Card;
import ch.datatrans.payment.paymentmethods.CardExpiryDate;
import ch.datatrans.payment.paymentmethods.PaymentMethodType;
public class DatatransModule extends ReactContextBaseJavaModule implements TransactionListener {
DatatransModule(ReactApplicationContext context) {
super(context);
}
private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
private Promise mPromise;
@NonNull
@Override
public String getName() {
return "DatatransModule";
}
@ReactMethod
public void logData(String name, String text) {
Log.d("CalendarModule", "Create event called with name: " + name
+ " and location: " + text);
}
@ReactMethod
public void initDatatrans( final Promise promise){
Activity activity = getCurrentActivity();
if (activity == null) {
WritableMap map = Arguments.createMap();
map.putString("message", "Activity doesn't exist");
consumeCallback(E_ACTIVITY_DOES_NOT_EXIST, map);
return;
}
try {
Transaction transaction = new Transaction("8b26a173484a7fbfe82f7009d6e859f7033352e5efe77416");
transaction.setListener(this); // this refers to Android's Activity
transaction.getOptions().setTesting(true);
transaction.getOptions().setUseCertificatePinning(true);
TransactionRegistry.INSTANCE.startTransaction(activity, transaction);
}catch (Exception e) {
mPromise.reject(e);
}
// return transaction;
}
@Override
public void onTransactionCancel() {
Log.d("canceled","onTransaction Canceled");
}
@Override
public void onTransactionError(@NonNull TransactionException e) {
Log.d("error","onTransaction error");
}
@Override
public void onTransactionSuccess(@NonNull TransactionSuccess transactionSuccess) {
Log.d("success","onTransaction succeed ");
}
private void consumeCallback(String type, WritableMap map) {
if (mPromise != null) {
map.putString("type", type);
map.putString("provider", "ct-datatrans");
mPromise.resolve(map);
mPromise = null;
}
}
}
Hello @AmirSalahY,
I will need the full stacktrace.
For the 8b26a173484a7fbfe82f7009d6e859f7033352e5efe77416
mobile token you are not setting the appCallbackScheme. When you use PAP you must define one.
Can you also tell me which is your appCallbackScheme? Note that it must comply with RFC 3986.
Thanks @luiscosta for your answer is there any reference u suggest to create one for android and one for ios?
Hello again @AmirSalahY,
If you are asking about the reference for the RFC 3986, you can follow the documentation at: https://datatracker.ietf.org/doc/html/rfc3986#autoid-18
@AmirSalahY, can you please post the full stack trace? We suspect there may be a configuration error as @luiscosta mentioned. The fact that the dialog is shown means the SDK is invoked, so the React Native bridge is working. We need to see where that error is thrown.
which stack exactly do u need
@AmirSalahY In the initial message you posted an image of an SDK error screen. This means that your app will receive a notification onTransactionError
with an object of type TransactionException
(link). Exceptions in Java have a concept called stack trace and something called exception chaining. We need the full stack trace of the exception chain. You can log it by adding the exception to your Log command. (The TransactionException
is a Throwable
.)
sorry for being late
2023-06-25 11:14:05.964 28942-28942 System.err com.datatransexample W ----------from onTransactionError : kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
2023-06-25 11:14:05.964 28942-28942 System.err com.datatransexample W ----------from onTransactionError : kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:104)
2023-06-25 11:14:05.964 28942-28942 System.err com.datatransexample W ----------from onTransactionError : android.os.Handler.handleCallback(Handler.java:958)
2023-06-25 11:14:05.964 28942-28942 System.err com.datatransexample W ----------from onTransactionError : android.os.Handler.dispatchMessage(Handler.java:99)
2023-06-25 11:14:05.964 28942-28942 System.err com.datatransexample W ----------from onTransactionError : android.os.Looper.loopOnce(Looper.java:205)
2023-06-25 11:14:05.964 28942-28942 System.err com.datatransexample W ----------from onTransactionError : android.os.Looper.loop(Looper.java:294)
2023-06-25 11:14:05.964 28942-28942 System.err com.datatransexample W ----------from onTransactionError : android.app.ActivityThread.main(ActivityThread.java:8176)
2023-06-25 11:14:05.965 28942-28942 System.err com.datatransexample W ----------from onTransactionError : java.lang.reflect.Method.invoke(Native Method)
2023-06-25 11:14:05.965 28942-28942 System.err com.datatransexample W ----------from onTransactionError : com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552)
2023-06-25 11:14:05.965 28942-28942 System.err com.datatransexample W ----------from onTransactionError : com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971)
i use these credentials
{
"currency": "CHF",
"refno": "Test-1234",
"amount": 5,
"paymentMethods": ["ECA","VIS","BON","REK"],
"option": {
"returnMobileToken": true
}
}
Hello again @AmirSalahY,
Unfortunately, the stacktrace log you sent on your message is not the error we want to see.
Can you change your onTransactionError
method to something like:
@Override
public void onTransactionError(@NonNull TransactionException e) {
Log.e("error","onTransaction error", e);
}
This should give you the SDK error we want.
Thank you!
@AmirSalahY any updates on this?
Unclear status, likely misconfiguration. Closing the ticket.
When triggering the Transaction function with the token it shows me this error
Unable to match the desired swap behavior.
expectations: to show the forms correctly