API – Developers Docs API – Developers Docs
  • Addon Payments
  • Pagos integrados en TPV
  • InglésCambiar a Inglés
API – Developers Docs API – Developers Docs
API – Developers Docs
  • Addon Payments
  • Pagos integrados en TPV
  • InglésCambiar a Inglés
Pagos integrados en TPV
  • Folder icon closed Folder open iconPago integrado con TPV Android
    • InStore Payment API Android
    • InStore Payment API Windows
    • InStore Payment REST API
  • Folder icon closed Folder open iconPago integrado con Smartphone TPV
    • Integración de pago con Smartphone TPV (iOS)
    • Integración de pago con Smartphone TPV (Android)
  • Folder icon closed Folder open iconPagos integrados en TPV
    • Transacciones
      • Tokenización
    • Reportes
    • Dispositivo
  • Folder icon closed Folder open iconIntegración Host2Host – Protocolo POI-Switch
  • Folder icon closed Folder open iconFichas Técnicas TPVs

Integración de pago con Smartphone TPV (Android)

  • Versión: 1.1.18

La estimación para completar una integración con la solución de Comercia 2.0 es de 21 días. Nuestro equipo de soporte está totalmente disponible para ayudarte durante este proceso de desarrollo y garantizar el éxito de la implementación.

Introducción – Sobre la integración de Smartphone TPV

Con la integración Smartphone TPV Integrada (Android), puedes realizar tu pago con el importe y la información de registro que envíes a la aplicación Smartphone TPV sin necesidad de añadir ninguna biblioteca de pagos a tu aplicación.

IMPORTANTE: Sólo es compatible con dispositivos Android versión 9.0 o superior, 64bits y con lectura NFC (lector de tarjetas).

El intercambio de datos entre aplicaciones se realiza mediante la creación de un canal con Messenger Service.

La conexión al servicio de mensajería no se establecerá correctamente si la aplicación del comercio no está incluida en la lista de aplicaciones válidas (permitted) (hashes). 

Este mecanismo de autorización funciona según el hash SHA-256 de la clave de firma que se utiliza al firmar la aplicación. Se puede conseguir mediante este comando:
keytool -alias yourKeyAlias -keystore yourKeysore.jks -list -v

Una vez se ejecuta el comando, los valores hash se mostrarán así:
Huellas digitales del certificado:

  • SHA1: C5:79:8C:79:C2:D1:CC:E6:F2:3F:34:29:10:28:7E:31:09:3E:2B:A4
  • SHA256: 6D:86:64:D3:84:3A:64:50:66:07:0E:7B:B8:71:DA:9E:2C:83:DE:EF:FD:D1:25:24:8D:D1:ED:B5:6D:0E:70:62

Importante: Este paso es imprescindible para continuar con el resto de la integración. Después de obtener el valor SHA-256, debes compartirlo con el equipo de Comercia a este correo. De esta forma, se añadirá a la lista de permitidos. También se entregará una nueva APK con el valor hash en la lista de permitidos.

Diagrama de la comunicación

Flujo del proceso de pago

Preparación del AndroidManifest

Se requiere permiso para MessengerService para crear canales e intercambiar datos entre la aplicación de ventas y la aplicación de pago Smartphone TPV. Las aplicaciones que no tengan esta declaración y uso de permisos no podrán establecer comunicación con la aplicación Smartphone TPV, debido a la falta de los mismos para comunicarse e intercambiar datos. El nombre del permiso es modificable, aunque el valor exacto de la string «android:name» es correcto.

Los permisos de NFC, localización e internet ya han sido solicitados en la aplicación de Smartphone TPV. 

  1. Añade permisos: 
				
					<permission
    android:name="com.softpos.app2app.permission.MESSAGING_SERVICE"
    android:protectionLevel="normal" />
    
<uses-permission android:name="com.softpos.app2app.permission.MESSAGING_SERVICE" />
				
			
Debes agregar servicios; de lo contrario, se producirá un error ya que no hemos creado el MessengerService.
				
					<application
...
<service
    android:name=".MessengerService"
    android:exported="true"
    android:permission="com.comercia.app2app.permission.MESSAGING_SERVICE" />

<queries>
    <intent>
        <action android:name="android.intent.action.MAIN" />
    </intent>
</queries>

<activity....
<intent-filter>
    <action android:name="android.intent.action.MAIN"/>
</intent-filter>
<activity>

</application>
				
			

* Modifícalo según tus necesidades

Crea la clase MessengerService

Sigue estos pasos: 

  1. La clase MessengerService debe extenderse desde Service:
				
					public class MessengerService extends Service
				
			

Variables: 

VariablesDescripción
serverHandlerRequerido para mandar y recibir mensajes.
mMessengerRequerido para enlazar.
handShakeListenerPara comprobar el handshake

2. Implementa el método onBind, onBind devuelve el binder del mensajero a la actividad.

				
					@Nullable
@Override
public IBinder onBind(Intent intent) {
    return mMessenger.getBinder();
}
				
			

3. Añádelo a la clase de MessengerService:

				
					public MessengerService() {
super();
    HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
    handlerThread.start();
    Looper looper = handlerThread.getLooper();

    serverHandler = new ServerHandler(looper);
    mMessenger = new Messenger(serverHandler);
}
				
			

4. Añade ServerHandler a MessengerService.class. ServerHandler es el responsable de manejar todos los mensajes de la aplicación de Smartphone TPV.

				
					public class ServerHandler extends Handler {
    private Messenger replyTo;
    public ServerHandler(Looper looper) {
        super(looper);
    }
    public Messenger getReplyTo() {
        return replyTo;
    }
    public void setReplyTo(Messenger replyTo) {
        this.replyTo = replyTo;
    }
    
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what) {
            case 0: //to reply to incoming handShake
                setReplyTo(msg.replyTo);
                sendHandShake()
                if (handShakeListener != null)
                    handShakeListener.onHandShaked();
                handShakeListener = null;
                break;
            case 1: //Send message to client app
                Message serviceMessage = Message.obtain();
                serviceMessage.setData(msg.getData());
                serviceMessage.what = 1;
                serviceMessage.replyTo = mMessenger;
                try {
                    getReplyTo().send(serviceMessage);
                } catch (RemoteException e) {
                    throw new RuntimeException("No messenger binded...", e);
                }
                break;
            case 2: //to see the incoming response
                setReplyTo(msg.replyTo);
                Bundle bundle = msg.getData();
                bundle.setClassLoader(getClass().getClassLoader());
                Log.e("response", msg.getData().getString("appResponse", "null"));
                break;
        }
    }
    
    //to send a handshake
    private void sendHandShake() {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        serviceBundle.putBoolean("appHandshake", true);
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    //Requests the last transaction information from SoftPos application
    public void getLastTxnApp(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject lastTxnData = new JSONObject();
        lastTxnData.put("appLastTxn", "1");
        lastTxnData.put("registerParameters", registerParameters);
        serviceBundle.putString("appLastTxn", String.valueOf(lastTxnData));
        Log.e("lastTxn", String.valueOf(lastTxnData));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    //Sends register information, amount and menu items to SoftPos application
    public void sendPayment(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject configParameters = new JSONObject();
        configParameters.put("drawerMenu", paymentDataRequest.getDrawerMenu());
        configParameters.put("salesButton", paymentDataRequest.getSalesButton());
        configParameters.put("voidButton", paymentDataRequest.getVoidButton());
        configParameters.put("refundButton", paymentDataRequest.getRefundButton());
        configParameters.put("historyButton", paymentDataRequest.getHistoryButton());
        configParameters.put("settingsButton", paymentDataRequest.getSettingsButton());
        configParameters.put("tipScreen", paymentDataRequest.getTipScreen());
        configParameters.put("userPhoto", paymentDataRequest.getUserPhoto());
        
        JSONObject paymentData = new JSONObject();
        if (!paymentDataRequest.getTransactionType().equals("200")) { // if not sale
            paymentData.put("transactionId", paymentDataRequest.getTransactionId());
        }
        paymentData.put("amount", paymentDataRequest.getAmount());
        paymentData.put("transactionType", paymentDataRequest.getTransactionType());
        paymentData.put("configParameters", configParameters);
        paymentData.put("registerParameters", registerParameters); //registerParameters optional. If you send t
        
        //*** customMessage optional. ****
        paymentData.put("customMessage", paymentDataRequest.getCustomMessage());
        //*** customMessage optional. ****
        
        serviceBundle.putString("paymentData", String.valueOf(paymentData));
        Log.e("paymentData", String.valueOf(paymentData));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    public void gotoList(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject configParameters = new JSONObject();
        configParameters.put("drawerMenu", paymentDataRequest.getDrawerMenu());
        configParameters.put("salesButton", paymentDataRequest.getSalesButton());
        configParameters.put("voidButton", paymentDataRequest.getVoidButton());
        configParameters.put("refundButton", paymentDataRequest.getRefundButton());
        configParameters.put("historyButton", paymentDataRequest.getHistoryButton());
        configParameters.put("settingsButton", paymentDataRequest.getSettingsButton());
        configParameters.put("tipScreen", paymentDataRequest.getTipScreen());
        configParameters.put("userPhoto", paymentDataRequest.getUserPhoto());
        JSONObject goToListData = new JSONObject();
        goToListData.put("listType", paymentDataRequest.getListType());
        goToListData.put("configParameters", configParameters);
        goToListData.put("registerParameters", registerParameters);
        /*if(StateClass.isRegisterList())
        goToListData.put("registerParameters",registerParameters);*/
        serviceBundle.putString("gotoList", String.valueOf(goToListData));
        Log.e("gotoList", String.valueOf(goToListData));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    public void gotoManuelSettlement(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject configParameters = new JSONObject();
        configParameters.put("drawerMenu", paymentDataRequest.getDrawerMenu());
        configParameters.put("salesButton", paymentDataRequest.getSalesButton());
        configParameters.put("voidButton", paymentDataRequest.getVoidButton());
        configParameters.put("refundButton", paymentDataRequest.getRefundButton());
        configParameters.put("historyButton", paymentDataRequest.getHistoryButton());
        configParameters.put("settingsButton", paymentDataRequest.getSettingsButton());
        configParameters.put("settlementButton", paymentDataRequest.getSettlementButton());
        configParameters.put("tipScreen", paymentDataRequest.getTipScreen());
        configParameters.put("userPhoto", paymentDataRequest.getUserPhoto());
        JSONObject goToManuelSettlement = new JSONObject();
        goToManuelSettlement.put("configParameters", configParameters);
        goToManuelSettlement.put("registerParameters", registerParameters);
        if (StateClass.isRegisterGotoList())
            goToManuelSettlement.put("registerParameters", registerParameters);
        serviceBundle.putString("gotoManuelSettlement", String.valueOf(goToManuelSettlement));
        Log.e("gotoManuelSettlement", String.valueOf(goToManuelSettlement));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
    
    public void onlyRegister(PaymentDataRequest paymentDataRequest) throws JSONException {
        Message serviceMessage = new Message();
        Bundle serviceBundle = new Bundle();
        JSONObject registerParameters = new JSONObject();
        registerParameters.put("terminalId", paymentDataRequest.getTerminalId());
        registerParameters.put("merchantId", paymentDataRequest.getMerchantId());
        registerParameters.put("activationCode", paymentDataRequest.getActivationCode());
        JSONObject onlyRegister = new JSONObject();
        onlyRegister.put("registerParameters", registerParameters);
        serviceBundle.putString("appRegister", String.valueOf(onlyRegister));
        Log.e("onlyRegister", String.valueOf(onlyRegister));
        serviceMessage.setData(serviceBundle);
        serviceMessage.what = 1;
        handleMessage(serviceMessage);
    }
}
				
			

5. Añade este método para obtener la última transacción:

				
					public static void getLastTxn(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.getLastTxnApp(paymentDataRequest);
}
				
			

6. Añade este método para enviar un mensaje:

				
					public static void sendPayment(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.sendPayment(paymentDataRequest);
}
				
			

7. Añade este método para obtener la lista de anulaciones, devoluciones e historial: 

				
					public static void gotoList(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.gotoList(paymentDataRequest);
}
				
			

8. Añade este método para el registro:

				
					public static void onlyRegister(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.onlyRegister(paymentDataRequest);
}
				
			

9. Añade HandshakeListener dentro de MessengerService.class:

				
					interface HandShakeListener {
    void onHandShaked();
}
				
			

10. Para establecer el handshake: 

				
					public static void setHandshake(HandShakeListener handShakeListener_){
    handShakeListener = handShakeListener_;
}
				
			

11. Añade este método para el cierre manual:

				
					public static void gotoManuelSettlement(PaymentDataRequest paymentDataRequest) throws RemoteException, JSONException {
    serverHandler.gotoManuelSettlement(paymentDataRequest);
}
				
			

Crea la clase SoftposAppLoader

Sigue estos pasos:

  1. Añade variables y constructores:
VariablesDescripción
appNameNombre de la aplicación Softpos.
packageNameNombre del paquete de la aplicación Softpos.
				
					private static Context context;
static String appName = "DESTINATION APP NAME example: Smartphone TPV";
static String packageName = "DESTINATION PACKAGNAME example: com.comercia.app";
SoftposAppLoader(Context context){
    this.context = context;
}
				
			

2. Comprueba si están instalados: 

				
					private static boolean isAppInstalled() {
    PackageManager pm = context.getPackageManager();
    List<PackageInfo> packageInfos = pm.getInstalledPackages(0);
    for (PackageInfo packageInfo : packageInfos) {
        
        if (packageInfo.packageName.equalsIgnoreCase(context.getPackageName())) {
            return true;
        }
    }
    return false;
}
				
			

3. Comprueba si están habilitados: 

				
					private static boolean isAppEnabled() {
    boolean appStatus = false;
    try {
        PackageManager pm = context.getPackageManager();
        List<PackageInfo> packageInfos = pm.getInstalledPackages(0);
        for (PackageInfo packageInfo : packageInfos) {
            if (packageInfo.applicationInfo.enabled) {
                appStatus = true;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
    return appStatus;
}
				
			

4. Para llamar a la última transacción: 

				
					public static void getLastTxn(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", BuildConfig.APPLICATION_ID)
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.getLastTxn(paymentDataRequest);
                            } catch (RemoteException e) {
                                e.printStackTrace();
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

5. Para abrir la aplicación de Smartphone TPV para pagos: 

				
					public static void getPayment(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", BuildConfig.APPLICATION_ID)
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.sendPayment(paymentDataRequest);
                            } catch (RemoteException | JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

6. La aplicación de Softpos se abre y se lleva a la pantalla de listado: 

				
					public static void goToList(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", BuildConfig.APPLICATION_ID)
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.gotoList(paymentDataRequest);
                            } catch (RemoteException | JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

7. La aplicación de Smartphone TPV se abre y lleva a la pantalla de registro: 

				
					public static void getOnlyRegister(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", BuildConfig.APPLICATION_ID)
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.onlyRegister(paymentDataRequest);
                            } catch (RemoteException | JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

8. La aplicación de Smartphone TPV se abre y el cierre manual está hecho: 

				
					public static void gotoManuelSettlement(final PaymentDataRequest paymentDataRequest) {
    if (isAppInstalled())
        if (isAppEnabled()) {
            Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
            launchIntent.putExtra("app2appPackageName", "com.example.opendemoapp")
                .putExtra("app2appMessengerServiceClassPath", MessengerService.class.getCanonicalName());
            context.startActivity(launchIntent);
            MessengerService.handShakeListener = null;
            MessengerService.setHandshake(new MessengerService.HandShakeListener() {
                @Override
                public void onHandShaked() {
                    new Handler().post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                MessengerService.gotoManuelSettlement(paymentDataRequest);
                            } catch (RemoteException | JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    });
                }
            });
        }
        else Toast.makeText(context, appName + " app is not enabled.", Toast.LENGTH_SHORT).show();
    else Toast.makeText(context, appName + " app is not installed.", Toast.LENGTH_SHORT).show();
}
				
			

Utilizando el PaymentDataRequest

Sigue estos pasos:

  1. Puedes iniciar la acción de pago con el siguiente fragmento de código para la transacción de venta. El código siguiente es un ejemplo, debes ajustarlo a tus necesidades. Debes registrar el transactionId y el monto devuelto de la venta. Será necesario para la anulación y devoluciones. 

				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId("YOUR MERCHANT ID TO REGISTER");
paymentDataRequest.setTerminalId("YOUR TERMINAL ID TO REGISTER ");
paymentDataRequest.setActivationCode("ACTIVATION CODE");
paymentDataRequest.setAmount("1400"); //-> YOUR AMOUNT VALUE
paymentDataRequest.setTransactionType("200"); //-> TRANSATION TYPE (FOR SALE -> "200" )
paymentDataRequest.setOrderId("12345"); //-> YOUR ORDER ID OF TRANSACTION
paymentDataRequest.setDrawerMenu("1"); //-> FOR DRAWER MENU OPEN/CLOSE
paymentDataRequest.setSalesButton("1"); //-> FOR SALE MENU VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setVoidButton("1"); //-> FOR BUTTON VOID VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setRefundButton("1"); //-> FOR REFUND BUTTON VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setHistoryButton("1"); //-> FOR HISTORY BUTTON VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setSettingsButton("0"); //-> FOR SETTING BUTTON VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setTipScreen("0"); //-> FOR TIP MENU VISIBLE = 1 /UNVISIBLE =0
paymentDataRequest.setUserPhoto("1"); //-> FOR USER PHOTO VISIBLE = 1 /UNVISIBLE =0


/////// OPTIONAL PART ////////////
Map<String, String> customMessage = new HashMap<>();
customMessage.put("courierId", "YOUR COURIER ID");
customMessage.put("subMID","YOUR EXTERNAL MERCHANT ID"); //-> FOR SUB MERCHANT-ID TO DELIVER PAYMENT AMOUNT
customMessage.put("subTID","YOUR EXTERNAL TERMINAL ID"); //-> FOR SUB TERMINAL-ID TO DELIVER PAYMENT AMOUNT
paymentDataRequest.setCustomMessage(new JSONObject(customMessage).toString());
/////// OPTIONAL PART ////////////
SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.getPayment(paymentDataRequest);
				
			

1.a: Tipos de transacciones:

setTransactionTypeDescripción
200Ventas
300Devoluciones
400Anulaciones
700MoneyAdd

1.b: ConfigParameters:

Debes enviar 1 o 0 para realizar la personalización dentro de la aplicación. Por ejemplo:
paymentDataRequest.setRefundButton("1"); 

2. Puedes usarlo en cualquier actividad de la siguiente manera para Anular o Reembolsar un pago.

Puedes anular/reembolsar con el transactionId que se obtiene de la venta. Además, para iniciar la anulación o el reembolso, puedes usar dos métodos:

  • Envía una solicitud de lista y abre la pantalla de lista de anulaciones, luego haz clic en el botón.
  • Envía directamente la solicitud de pago como ANULACIÓN.

Si envías una solicitud de lista, no podrán obtener una respuesta de anulación de pago, pero esa es la diferencia. Luego, el reembolso ocurre de la misma manera.

Este es un código de ejemplo para una anulación: 

				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId("MERCHANT ID TO REGISTER");
paymentDataRequest.setTerminalId("TERMINAL ID TO REGISTER");
paymentDataRequest.setActivationCode("ACTIVATION CODE");
paymentDataRequest.setAmount("1300");
paymentDataRequest.setTransactionType("400"); // or setTransactionType("300") for refund
paymentData.setTransactionId("123456");
paymentDataRequest.setDrawerMenu("1");
paymentDataRequest.setSalesButton("1");
paymentDataRequest.setVoidButton("1");
paymentDataRequest.setRefundButton("1");
paymentDataRequest.setHistoryButton("1");
paymentDataRequest.setSettingsButton("0");
paymentDataRequest.setTipScreen("0");
paymentDataRequest.setUserPhoto("1");

SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.getPayment(paymentDataRequest);
				
			

3. Puedes usarlo como se muestra a continuación para ver la última transacción. Este es un código de ejemplo: 

				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId("YOUR MERCHANT ID TO REGISTER");
paymentDataRequest.setTerminalId("YOUR TERMINAL ID TO REGISTER");
paymentDataRequest.setActivationCode("ACTIVATION CODE");

SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.getLastTxn(paymentDataRequest);
				
			

4. Puedes usarlo como se muestra a continuación para ver la última transacción: 

setTransactionTypeDescripción
3000Lista de devoluciones
4000Lista de anulaciones
5000Lista de historial
				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId("MERCHANT ID TO REGISTER");
paymentDataRequest.setTerminalId("TERMINAL ID TO REGISTER");
paymentDataRequest.setActivationCode("ACTIVATION CODE");
paymentDataRequest.setListType("3000");
paymentDataRequest.setDrawerMenu("1");
paymentDataRequest.setSalesButton("1");
paymentDataRequest.setVoidButton("1");
paymentDataRequest.setRefundButton("1");
paymentDataRequest.setHistoryButton("1");
paymentDataRequest.setSettingsButton("0");
paymentDataRequest.setTipScreen("0");
paymentDataRequest.setUserPhoto("1");

SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.gotoList(paymentDataRequest);
				
			

5. Puedes usarlo como se muestra a continuación para el registro: 

				
					PaymentDataRequest paymentDataRequest = new PaymentDataRequest();
paymentDataRequest.setMerchantId(((EditText)findViewById(R.id.merchantId)).getText().toString());
paymentDataRequest.setTerminalId(((EditText)findViewById(R.id.terminalId)).getText().toString());
paymentDataRequest.setActivationCode(((EditText)findViewById(R.id.activationCode)).getText().toString());

SoftposAppLoader softposAppLoader = new SoftposAppLoader(getApplicationContext());
softposAppLoader.getOnlyRegister(paymentDataRequest);
				
			

Ejemplos de mensajes entrantes y salientes

En esta sección tienes varios ejemplos de mensajes en distintas situaciones.

Registros de transacciones de pago

1.a: Mensaje enviado desde la aplicación de tu comercio para pagos: 

				
					appData - > 
{
    "amount": "1400",
    "transactionType": "200",
    "configParameters": {
        "drawerMenu": "1",
        "salesButton": "1",
        "voidButton": "1",
        "refundButton": "1",
        "historyButton": "1",
        "settingsButton": "1",
        "tipScreen": "0",
        "userPhoto": "1"
    },
    "registerParameters": {
        "terminalId": "16010129",
        "merchantId": "000000009041042",
        "activationCode": "testCode"
    },
    "customMessage": "{\"courierId\":\"17823678\",\
    "subMID\":\"MID123456\",\
    "subTID\":\"TID123456\",\
    "installmentCount\":\"3\"}"
}
				
			
El parámetro CustomMessage se envía directamente al host.

Si se proporcionan las informaciones de subMID y subTID, el sistema backend de la aplicación de Smartphone TPV reemplaza el MID (Identificador de Comerciante) y el TID (Identificador de Terminal) actuales justo antes de enviar los datos de la transacción al host externo del cliente. La transacción se finaliza con respecto a la información del comerciante reemplazada (subTID, subMID) en el lado del host del cliente, pero la transacción se almacena en la base de datos con el MID/TID original. Aquí tienes un ejemplo de escenario:

  1. Hay un terminal registrado en el sistema backend de la aplicación de Smartphone TPV con MID: 1 y TID: 1.
  2. Se ha iniciado una transacción y se ha proporcionado subMID: 2 y subTID: 2 en el campo customMessage.
  3. Se envía el customMessage al backend de la aplicación de Smartphone TPV.
  4. El sistema backend verifica el campo customMessage, extrae la información de subMID/subTID y los reemplaza en los datos de la transacción sobre los originales justo antes de enviar la transacción a través de la pasarela del adquirente.
  5. Cuando se recibe la respuesta, el backend vuelve a reemplazar la información de comercio de vuelta al original: MID:1 TID:1.
  6. La transacción se almacena en la Base de Datos con MID:1 TID:1.
  7. Se envía una respuesta a la aplicación de Smartphone TPV con MID: 1 y TID: 1. 

Este mecanismo permite al cliente realizar una transacción utilizando diferentes identificadores de comerciante (MID) y de terminal (TID) para transferir dinero a la cuenta de otro comerciante. Sin embargo, ten en cuenta que las transacciones se mostrarán en el historial del MID/TID registrado originalmente.

Otros puntos a tener en cuenta:

  • Si no se envía subMID ni subTID, la transacción continuará de forma ordinaria. 
  • Si se proporciona información sobre el installmentCount en el mensaje personalizado (custom message), el backend la tomará del mensaje personalizado y la enviará directamente al host en el campo ISO relevante (o en otro tipo de integración).
  • Si no se proporciona en el mensaje personalizado (custom message), el backend aplicará el flujo predeterminado para ello. Por ejemplo, si no se proporciona installmentCount, el backend puede enviarlo como 1 por defecto.

1.b: Registro de mensajes devueltos para el pago:

El campo «transactionStatus» puede ser:

  • success: La transacción de pago se ha completado exitosamente.
  • decline: La transacción de pago ha fallado o expirado. 
				
					response:
{"transactionType":"200",
"appVersion":"1.2.10",
"amount":"5000",
"maskedPan":"**** **** **** 0516",
"transactionStatus":"success",
"customMessage":"{\"isoStan\":\"001017\"}",
"refusalCode":"00",
"transactionDate":"29-11-2022 15:47:24",
"transactionId":"233394301141"}
				
			

Obtén los últimos registros de transacciones

				
					appLastTxn->
    {
        "appLastTxn":"1",
        "registerParameters": {
            "terminalId": "00192118",
            "merchantId": "000000009041042",
            "activationCode": "testCode"
        }
    }
				
			
				
					response:

{"appLastTxn":
"{\"transaction_id\":\"302684069304\",
\"transaction_date\":\"230126\",
\"amount\":\"700\",
\"approvalCode\":\"00\",
\"card_number\":\"0516\",
\"orderId\":\"167471801514\",
\"authorizationId\":\"00\",\
"approvedStatus\":\"1\",
\"transactionType\":\"200\",
\"stan\":\"00\",\
"txnMti\":\"00\",
\"transaction_time\":\"102726\",
\"batchNumber\":\"00\"}"}
				
			

Para obtener la lista del historial de transacciones

Este es el mensaje enviado desde tu aplicación de comercio: 

				
					{
    "listType": "3000",
    "configParameters": {
        "drawerMenu": "1",
        "salesButton": "0",
        "voidButton": "1",
        "refundButton": "1",
        "historyButton": "1",
        "settingsButton":"1",
        "tipScreen": "0",
        "userPhoto": "1"
    }
}
				
			

Otros mensajes que puedes recibir desde la app de Smartphone TPV

4.a: Mensaje de respuesta de ejemplo: 

				
					{
    "response":
    {
        "a2aCode":"1003",
        "a2aMessage":"Register error : Server Error please contact with your administrator"
        "errorCode":"104",
        "errorMainCode":"9",
        "errorSubCode":"32"errorCode
    }
}
				
			
				
					{
    "response":
    {
        "a2aCode":"1010",
        "a2aMessage":"SoftposApp Stoped"
    }
}
				
			

Los parámetros y su descripción: 

ParámetrosDescripción
a2aCodeEl código de respuesta ha sido creado en la aplicación SoftPos.
a2aMessagea2aMessage es el mensaje correspondiente al a2aCode. El mensaje del backend se puede agregar en la continuación.
errorCodeerrorCode se devuelve desde el backend. Si se recibe un código de error del backend, el errorCode no será nulo.
errorMainCodeerrorMainCode que se devuelve desde el backend. Todos los códigos de error y explicaciones están disponibles en el documento de SDK de SoftPos.
errorSubCodeerrorSubCode que se devuelve desde el backend.

4.b: Otros mensajes y códigos:

ParámetrosMensaje de respuestaDescripción
1003Register error :Se encontró un error durante el registro. El mensaje del backend se puede agregar a la continuación. Por ejemplo: Error de registro: Error del servidor, por favor, contacta con tu administrador.
1004unregister ERROR, please try againSi se envía registerParameter, la aplicación SoftPos se anulará y luego se registrará. Mensaje durante la desinscripción.
1005Error de inicialización :Si se recibe un error durante la inicialización, se devolverá este código y mensaje. El mensaje del backend se puede agregar a la continuación.
1006JsonParse error :Si el mensaje de la aplicación del comerciante no es adecuado para la estructura JSON, se devolverá este código y mensaje.
1007Amount cannot be alphanumeric characters, null, 0La cantidad no puede contener caracteres alfanuméricos, nulos o 0. Relacionado con la cantidad enviada.
1008transaction size = 0Si no hay transacción y deseas ver la última transacción (appLastTxn), se devolverá este mensaje.
1009Registration SuccessfulRegistro exitoso.
1010SoftposApp StopedLa app de Softpos se ha detenido.
1011The application was closed because
application was opened
standalone
La aplicación se cerró porque se abrió de forma independiente.
1012Connection Error Se devuelve este error cuando hay un problema con la conexión.
1013Manual Settlement SuccessfulLiquidación manual exitosa. Se devuelve esta respuesta cuando se completa el proceso de liquidación manual.
1014Registration NeededRegistro necesario. Se devuelve este error si no existe el registro necesario.

Liquidación manual

Petición:

				
					{
    "configParameters": {
        "drawerMenu": "1",
        "salesButton": "0",
        "voidButton": "1",
        "refundButton": "1",
        "historyButton": "1",
        "settingsButton": "1",
        "settlementButton": "0",
        "tipScreen": "0",
        "userPhoto": "1"
    },
    "registerParameters": {
        "terminalId": "00000001",
        "merchantId": "000000000000011",
        "activationCode": "1"
    }
}
				
			
				
					{
    "settlementResult": true,
    "settlementResultMessage": "ACQUIRER_SETTLEMENT_SUCCESS",
    "settlementSaleCount": null,
    "settlementSaleAmount": null,
    "settlementVoidCount": null,
    "settlementVoidAmount": null,
    "batchNumber": "1713"
}
				
			
				
					{
    "errorCode": "E104",
    "internalErrorCode": 0,
    "internalErrorSubCode": 0
}
				
			

Desactivar el registro en cada pago

Si en las peticiones se envían los siguientes parámetros se intentará realizar el registro de manera automática. Para desactivar el registro en cada pago no envíes estos campos. Mándalos sólo en las circunstancias requeridas.

  • configParameters
  • registerParameters

Aunque esté vacíos, si están estos campos presentes el Smartphone TPV intentará registrar, reemplazando cualquier información ya registrada. 

El registro en Smartphone TPV debe enviarse únicamente en las siguientes circunstacias:

  • Primer pago: En casos donde la app no está registrada previamente.
  • Error 104: Indica que la APP no está registrada. Este error puede ocurrir por una instalación reciente, un borrado de datos o una reinstalación de la APP.

Ejemplo de la integración de la aplicación de Smartphone TPV (Android)

En la página de inicio de esta sección puedes encontrar ejemplos.

Comparte este documento

Integración de pago con Smartphone TPV (Android)

Copiar el enlace

Clipboard Icon
Tabla de Contenidos

Productos

  • Addon Payments
  • Pagos integrados en TPV
  • Universal Pay
  • Addon 1 - XML API Integration

Ventas

Cuéntanos cómo es tu negocio para ofrecerte la mejor solución.

Contacta con un experto

Soporte técnico

¿Ya eres cliente y necesitas ayuda? Contacta con nosotros, estamos a tu disposición.

Ayuda

Socios

Trabajamos con los mejores partners de soluciones in-store y eCommerce. ¿Quieres unirte?

Únete a nosotros

© Comercia Global Payments

Política de privacidad
Ejercicio de Derechos
Información a Clientes
Canal de denuncia
Aviso Legal
Política de cookies
Pregúntale a la IA
Escribe tu pregunta. Por ejemplo: ¿Cómo creo un enlace de pago?
La SmartWiki puede omitir datos. Verifica la información o contacta con soporte.

SmartWiki, Impulsada por IA

API - Developers Docs
Gestionar el consentimiento de las cookies
Para ofrecer las mejores experiencias, utilizamos tecnologías como las cookies para almacenar y/o acceder a la información del dispositivo. El consentimiento de estas tecnologías nos permitirá procesar datos como el comportamiento de navegación o las identificaciones únicas en este sitio. No consentir o retirar el consentimiento, puede afectar negativamente a ciertas características y funciones.
Funcional Siempre activo
El almacenamiento o acceso técnico es estrictamente necesario para el propósito legítimo de permitir el uso de un servicio específico explícitamente solicitado por el abonado o usuario, o con el único propósito de llevar a cabo la transmisión de una comunicación a través de una red de comunicaciones electrónicas
Preferencias
El almacenamiento o acceso técnico es necesario para la finalidad legítima de almacenar preferencias no solicitadas por el abonado o usuario
Estadísticas
El almacenamiento o acceso técnico que es utilizado exclusivamente con fines estadísticos. El almacenamiento o acceso técnico es necesario para la finalidad legítima de almacenar preferencias no solicitadas por el abonado o usuario
Marketing
El almacenamiento o acceso técnico es necesario para crear perfiles de usuario para enviar publicidad, o para rastrear al usuario en una web o en varias web con fines de marketing similares.
Administrar opciones Gestionar los servicios Gestionar {vendor_count} proveedores Leer más sobre estos propósitos
Ver preferencias
{title} {title} {title}

Consulta la documentación de las distintas secciones de integraciones:

Comienza a integrar

undraw_add_to_cart_re_wrdo 1 (1) (1)

Plugins para CMS

Complementa la integración

SDKs

Métodos de pago

Herramientas

Addon Payments

Consulta la documentación de Addon Payments. Aquí tienes las distintas secciones:

Integraciones

Consultas frecuentes

Portal Backoffice

Cyberpac

Consulta la documentación de Cyberpac. Aquí tienes las distintas secciones:

Canales

Módulos de integración

Integraciones a medida

Pagos integrados en TPV

Crea una solución que te ayudará a automatizar procesos. Incluso, podrás agregar procesos de pago en terminales físicos.

Pago integrado con TPV Android

Pago integrado con Smartphone TPV

Fichas Técnicas TPVs

Addon Payments

Comercia Global Payments has several integration options so you can choose the most efficient one for you.

Integrations

Frequently Asked Questions

BackOffice Portal

Consult the documentation of the different integrations sections:​

Start integration

undraw_add_to_cart_re_wrdo 1 (1) (1)

CMS Plugins

Complement your integration

SDKs

Payment Methods

Tools