Integrate the SDK
                                The PayButton is our own easy-to-use reference implementation
                                        for a user interface on top of the SDK.
Before starting a Custom Integration, please evaluate whether
                                        the PayButton already fulfills your needs.
To get started with your own implementation, add the SDK to your app. Then, choose a view
                                    controller of your app. This should be the view controller that
                                    starts the payment.
We recommend integrating the UI for the payment either into a
                                    modal or a screen separate from your checkout (e.g., the modal
                                    should be shown over the shopping cart). You have to make sure
                                    that during a transaction the user cannot change the amount, or
                                    add/delete products from the cart. 
 Also, it is important that this modal or separate screen can be
                                    closed only oncethe SDK calls the
completed
callback. Make sure to hide all 'close'
                                    or 'back' buttons untilthe transaction is completed. Otherwise,
                                    if such a button is tapped,the SDK will continue with the
                                    transaction, but the merchant cannot see the result. Paste the following code into the view controller implementation.
                                    Replace
                                        
MERCHANT_IDENTIFIER
andMERCHANT_SECRET_KEY
with
                                    your testing credentials. Uncomment the correct value for your
                                    reader.- (IBAction)transaction:(id)sender { MPTransactionProvider* transactionProvider = [MPMpos transactionProviderForMode:MPProviderModeTEST merchantIdentifier:@"MERCHANT_IDENTIFIER" merchantSecretKey:@"MERCHANT_SECRET_KEY"]; MPTransactionParameters *transactionParameters = [MPTransactionParameters chargeWithAmount:[NSDecimalNumber decimalNumberWithString:@"5.00"] currency:MPCurrencyEUR optionals:^(id<MPTransactionParametersOptionals> _Nonnull optionals) { optionals.subject = @"Bouquet of Flowers"; optionals.customIdentifier = @"yourReferenceForTheTransaction"; }]; // When using the Bluetooth Miura, use the following parameters: // MPAccessoryParameters *ap = [MPAccessoryParameters externalAccessoryParametersWithFamily:MPAccessoryFamilyMiuraMPI // protocol:@"com.miura.shuttle" // optionals:nil]; // When using Verifone readers via WiFi or Ethernet, use the following parameters: // MPAccessoryParameters *ap = [MPAccessoryParameters tcpAccessoryParametersWithFamily:MPAccessoryFamilyVerifoneVIPA // remote:@"192.168.254.123" // port:16107 // optionals:nil]; MPTransactionProcess *process = [transactionProvider startTransactionWithParameters:transactionParameters accessoryParameters:ap registered:^(MPTransactionProcess *process, MPTransaction *transaction) { NSLog(@"registered MPTransactionProcess, transaction id: %@", transaction.identifier); } statusChanged:^(MPTransactionProcess *process, MPTransaction *transaction, MPTransactionProcessDetails *details) { NSLog(@"%@\n%@", details.information[0], details.information[1]); } actionRequired:^(MPTransactionProcess *process, MPTransaction *transaction, MPTransactionAction action, MPTransactionActionSupport *support) { switch (action) { case MPTransactionActionCustomerSignature: { NSLog(@"show a UI that let's the customer provide his/her signature!"); // In a live app, this image comes from your signature screen UIGraphicsBeginImageContext(CGSizeMake(1, 1)); UIImage *capturedSignature = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); [process continueWithCustomerSignature:capturedSignature verified:YES]; // Add this instead, if you would like to collect the customer signature on the printed merchant receipt [process continueWithCustomerSignatureOnReceipt]; break; } case MPTransactionActionCustomerIdentification: { // always return NO here [process continueWithCustomerIdentityVerified:NO]; break; } case MPTransactionActionApplicationSelection: { // This happens only for readers that don't support application selection on their screen break; } default: { break; } } } completed:^(MPTransactionProcess *process, MPTransaction *transaction, MPTransactionProcessDetails *details) { NSLog(@"Transaction ended, transaction status is %lu", (unsigned long) transaction.status); if (details.state == MPTransactionProcessDetailsStateApproved) { // Ask the merchant, whether the shopper wants to have a receipt // and close the checkout UI } else { // Allow your merchant to try another transaction } // only close your modal here }]; }
 Create a button and connect it with
                                        the
transaction
action. In your payment UI,
                                    add two UILabels
 that display
                                    the contents ofdetails.information[0]
 anddetails.information[1]
 each timestatusChange
is called.This way,
                                    the merchant always receives detailed status information about
                                    the transaction.  Start the app and tap your button. Follow the instructions on
                                    the reader and in the app. Do not worry about charging your
                                    card, it is just a test transaction. Nice! You just processed
                                    the first transaction from your app. 
Let the Merchant abort the
                                        transaction
You have to add a button in the app to enable themerchant to
                                        abort the transaction.
For this, add a button in your payment UI. Aborting a transaction
                                    is not always possible, e.g. it is not possible to abort in the
                                    last stage of a transaction. Therefore, show/hide your button
                                    using the
canBeAborted
flag
                                        instatusChanged
:statusChanged:^(MPTransactionProcess *process, MPTransaction *transaction, MPTransactionProcessDetails *details) { _abortButton.hidden = ![transaction canBeAborted]; }
Then, create an action for the abort button that aborts the
                                    transaction:
- (IBAction)abortTapped:(id)sender { [_process requestAbort]; }
Don't hide the checkoutUI directly after requesting the abort, and don't show text such as 'Aborting...' by yourself. The SDK will call thecompletedcallback once the transaction is aborted. Also, we recommend to let the transaction continue while the app is in the background.
Store Merchant Data on
                                        your Backend
Right now, you have hardcoded the 
merchantIdentifier
 and merchantSecretKey
. This means that all payments
                                    would berouted to the same merchant.For a live solution, you might want to support multiple
                                    merchants, e.g. two different restaurants, to route the payment
                                    correctly.To support multiple merchants, store the following
                                    data on your backend:
- merchantIdentifierandmerchantSecretKey. They identify to which merchant the payment is routed. You can create new merchants and get their credentials in the Gateway Manager.
- Whether the merchant is aTESTorLIVEmerchant.
You can then fetch this data before a transaction and configure
                                    the SDK correctly:
MPTransactionProvider* transactionProvider = [MPMpos transactionProviderForMode:<TEST or LIVE, loaded from your backend> merchantIdentifier:<MerchantIdentifier loaded from your backend> merchantSecretKey:<MerchantSecretKey loaded from your backend> ];
Specifythe accessory
You have to specify which accessory you want to use with your app
                                    and how to connect to it by defining an 
MPAccessoryParameters
 object, which you can create
                                    with the provided class helper methods.The 
MPAccessoryFamily
-is type
                                    of accessory that you want to connect to. The optionals block
                                    provides access to all parameters that can optionally be
                                    specified for this type of connection. For an External
                                    Accessory, this is for example a name prefix to filter for.Different types of accessories can be connected with different methods, wrong configuration will fail when starting the transaction. Also make sure you have included the correct libraries for the accessory and connection type.
Specifythe transaction
You have to specify the parameters of the transaction you want to
                                    execute with a 
MPTransactionParameters
 object, which you can
                                    create with the provided class methods.For charge transactions call 
chargeWithAmount:
 with the amount and currency
                                    which you want to use.Currencies, which you can use for your transactions are limited by the configuration of your Processing Path, wrong currency will fail when executing the transaction.
In the optionals block you can specify additional parameters that
                                    are attached to the transaction:
| .subject | Subject of the transaction. | Gateway Manager | all | 
| .customIdentifier | Your identifier or the transaction. | Gateway Manager | all | 
| .statementDescriptor | The descriptor of the transaction. | Stripe Dashboard, customer's card
                                                  bill | Stripe | 
| .applicationFee | The fee which will be further applied to the
                                                  transaction. | Stripe Dashboard | Stripe | 
| .metadata | Extra information to further specify the
                                                  transction. | Stripe Dashboard | Stripe | 
Integrate the SDK 
The PayButton is our own easy-to-use
reference implementation for a user interface on top of the
SDK.
Before starting a Custom Integration, please evaluate whether
the PayButton already fulfils your needs.
To get started with your own implementation, add the SDK to your app first. Then, choose an
activity of your App. This should be the activity that starts the
payment.
We recommend to integrate the UI
for the paymenteitherinto a modal or a screen separate
from your checkout (e.g., the modal should be shown over the
shopping cart). You have to make sure that during a transaction the
user cannot change the amount, or add/delete products from the
cart.
  
Also, it is important that this
modal or separate screen can be closed only oncethe SDK calls
the
onCompleted
callback. Make
sure to hide all 'close' or 'back' buttons untilthe
transaction is completed. Otherwise, if such a button is
tapped,the SDK will continue with the transaction, but the
merchant cannot see the result.
  Paste the following code into your activity.
Replace
MERCHANT_IDENTIFIER
andMERCHANT_SECRET_KEY
with
your testing credentials, or use TransactionProvider in mocked
mode.Use the correct value of AccessoryParameters for your
reader.void transaction() { final TransactionProvider transactionProvider = Mpos.createTransactionProvider(this, ProviderMode.TEST, "MERCHANT_IDENTIFIER", "MERCHANT_SECRET_KEY"); /* For starting transaction in mocked mode use fallowing provider: final TransactionProvider transactionProvider = Mpos.createTransactionProvider(this, ProviderMode.MOCK, "merchantIdentifier", "merchantSecretKey"); */ /* When using the Bluetooth Miura, use the following parameters: */ AccessoryParameters accessoryParameters = new AccessoryParameters.Builder(AccessoryFamily.MIURA_MPI) .bluetooth() .build(); /* When using Verifone readers via WiFi or Ethernet, use the following parameters: AccessoryParameters accessoryParameters = new AccessoryParameters.Builder(AccessoryFamily.VERIFONE_VIPA) .tcp("192.168.254.123", 16107) .build(); */ TransactionParameters transactionParameters = new TransactionParameters.Builder() .charge(new BigDecimal("5.00"), io.mpos.transactions.Currency.EUR) .subject("Bouquet of Flowers") .customIdentifier("yourReferenceForTheTransaction") .build(); TransactionProcess paymentProcess = transactionProvider.startTransaction(transactionParameters, accessoryParameters, new TransactionProcessWithRegistrationListener() { @Override public void onRegistered(TransactionProcess process, Transaction transaction) { Log.d("mpos", "transaction identifier is: " + transaction.getIdentifier() + ". Store it in your backend so that you can always query its status."); } @Override public void onStatusChanged(TransactionProcess process , Transaction transaction, TransactionProcessDetails processDetails) { Log.d("mpos", "status changed: " + Arrays.toString(processDetails.getInformation())); } @Override public void onCustomerSignatureRequired(TransactionProcess process, Transaction transaction) { // in a live app, this image comes from your signature screen Bitmap.Config conf = Bitmap.Config.ARGB_8888; Bitmap bm = Bitmap.createBitmap(1, 1, conf); byte[] signature = AndroidImageHelper.byteArrayFromBitmap(bm); process.continueWithCustomerSignature(signature, true); } @Override public void onCustomerVerificationRequired(TransactionProcess process, Transaction transaction) { // always return false here process.continueWithCustomerIdentityVerified(false); } @Override public void onApplicationSelectionRequired(TransactionProcess process, Transaction transaction, List<ApplicationInformation> applicationInformation) { // This happens only for readers that don't support application selection on their screen process.continueWithSelectedApplication(applicationInformation.get(0)); } @Override public void onDccSelectionRequired(TransactionProcess transactionProcess, Transaction transaction, DccInformation dccInformation) { // This comes up if the DCC selection cannot be done on the terminal itself transactionProcess.continueDccSelectionWithOriginalAmount(); } @Override public void onCompleted(TransactionProcess process, Transaction transaction, TransactionProcessDetails processDetails) { Log.d("mpos", "completed"); if (processDetails.getState() == TransactionProcessDetailsState.APPROVED) { // print the merchant receipt Receipt merchantReceipt = transaction.getMerchantReceipt(); // print a signature line if required if(merchantReceipt.isSignatureLineRequired()) { System.out.println(""); System.out.println(""); System.out.println(""); System.out.println("------ PLEASE SIGN HERE ------"); } // ask the merchant, whether the shopper wants to have a receipt Receipt customerReceipt = transaction.getCustomerReceipt(); // and close the checkout UI } else { // Allow your merchant to try another transaction } } }); } @Override public void onBackPressed() { Toast.makeText(this, "The back button is disabled during a transaction. Please use the 'abort' button to cancel the transaction.", Toast.LENGTH_LONG).show(); }
Create a button tocall the
transaction
method. In your payment UI, add
twoTextViews
that
displaythe contents of processDetails.getInformation()[0]
and
processDetails.getInformation()[1]
each
timeonStatusChanged
is
called.This way, the merchant always receives detailed status
information about the transaction.Then, for the Bluetooth Miura reader, pair the reader with your device.
Start the app and tap your button. Follow the instructions on
the reader and in the app. Do not worry about charging your card,
it is just a test transaction.
Nice! You just processed the first transaction from your
app.
Let the Merchant abort the transaction
You have to add a button in the app to enable the merchant to
abort the transaction.
For this, add a button in your payment UI. Aborting a
transaction is not always possible, e.g. it is not possible to
abort it in the last stage of a transaction. Therefore, show/hide
your button using the
canBeAborted
flag inonStatusChanged
:public void onStatusChanged(TransactionProcess process , Transaction transaction, TransactionProcessDetails processDetails) { //.. abortButton.setVisibility(transaction != null && transaction.canBeAborted() ? View.VISIBLE : View.INVISIBLE); }
Then, create a click listener for the abort button that aborts
the transaction:
public void abort() { process.requestAbort(); }
Don't hide the checkout UI directly after the merchant hasrequested the abort, and don't show text such as 'Aborting...' by yourself. The SDK will call theonCompletedcallback once the transaction is aborted. Also, we recommend to let the transaction continue while the app is in the background.
Store Merchant Data on
           your Backend
Right now, you have hardcoded the
merchantIdentifier
andmerchantSecretKey
. This means that all payments would
berouted to the same merchant.For a live solution, you might want to support multiple
merchants, e.g. two different restaurants, to route the payment
correctly.To support multiple merchants, store the following
data on your backend:
- merchantIdentifierandmerchantSecretKey. They identify to which merchant the payment is routed.You can create new merchants and get their credentials in the Gateway Manager.
- Whether the merchant is aTESTorLIVEmerchant.
You can then fetch this data before a transaction and configure
the SDK correctly:
final TransactionProvider transactionProvider = Mpos.createTransactionProvider(this, <TEST or LIVE, loaded from your backend>, <MerchantIdentifier loaded from your backend>, <MerchantSecretKey loaded from your backend>);
Specifythe accessory
You have to specify which accessory you want to use with your
app and how to connect to it by defining an 
AccessoryParameters
 object, which you can create with
the provided builder.The argument which you pass into the builder's constructor
specifies the 
AccessoryFamily
-the type of accessory that
you want to connect to.The method, which you call right after the constructor specifies
the connection type that you want to use. Currently possible
methods are 
mock()
, bluetooth()
 and tcp()
.Different types of accessories can be connected with different methods, wrong configuration will fail when starting the transaction. Also make sure you have included the correct libraries for the accessory and connection type.
After the second method, depending on which connection type you
selected, you can set different options specifying the connection.
For example, for bluetooth you can select an address prefix which
will be applied when searching for the accessory.
Specifythe transaction
You have to specify the parameters of the transaction you want
to execute with a 
TransactionParameters
object, which you can create with the provided builder.For charge transactions call 
charge()
method with the amount and currency which you want to use.Currencies, which you can use for your transactions are limited by the configuration of your Processing Path, wrong currency will fail when executing the transaction.
After the 
charge()
 method you can
specify additional, optional parameters:| Method | Description | Visible in | Applicable for | 
| subject() | Subject of the transaction. | Gateway Manager | all | 
| customIdentifier() | Your identifier or the transaction. | Gateway Manager | all | 
| statementDescriptor() | The descriptor of the transaction. | Stripe Dashboard, customer's card bill | Stripe | 
| applicationFee() | The fee which will be further applied to the transaction. | Stripe Dashboard | Stripe | 
| metadata() | Extra information to further specify the transction. | Stripe Dashboard | Stripe | 
