- Device Requirements
- Workstation Configuration
- Building the Sample Application
- Setting Up Your App
- Integration Steps
Device Requirements
- Minimum API level is 22 (platform version 5.1)
- Device cannot be rooted
- Emulator/Simulator is not supported
Workstation Configuration
If your workstation is already configured for android development then you can most likely jump to the next section. Otherwise you can follow this high-level overview for setting up your environment:
- View workstation minimum requirements
- Download Android Studio from Android Studio
- For more detailed information, see the official android developer doc
Building the Sample Application
- Unzip the sample app zip file in your local drive/environment. This example will assume you extracted the files into c:\sample-app.
- Open up build.gradle and look at compileSdkVersion. You will need to install the specified version of the Android SDK if you don't have it already.
- Start your IDE and open c:\sample-app.
- Once the IDE has stopped processing, open the Build Variants tool window (View→Tool Windows→Build Variants).
- In the Build Variants tool window, select the opayoDebug build variant.
- Once the IDE has stopped processing, open up the Gradle tool window (View→Tool Windows→Gradle).
- In the Gradle tool window, click Tasks→Build→double-click Build.
- Once the IDE has stopped processing that task, you will find a new apk in the app/build/outputs/apk folder.
- At this point you should be able run the application from the IDE or you can manually install the apk onto your device. When the app starts up, you will want to tap the menu in the top right corner. Select "Credentials" which will let you enter your Opayo credentials. Select either PROD or DEMO for server type based on your account and environment type.
Setting Up Your App
You can use the sample app's build.gradle file as a starting point for your app. It is already configured to pull in the commerce SDK libraries during build processing.
Permission Setup
As part of your initial application setup, you will need to include the following permissions in your AndroidManifest.xml file:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
Note that some permissions are considered "dangerous" and need to be explicitly requested from the user at runtime. These are:
- READ_PHONE_STATE
- BLUETOOTH_SCAN
- BLUETOOTH_CONNECT
- ACCESS_FINE_LOCATION
You can check the sample app code to see how these permissions are requested.
Integration Steps
The following are the main integration steps for POS system to process a transaction through CSDK. Refer to each section for the detailed instructions for integration:
Commerce SDK Initialization
- Commerce SDK initialization
First we need to initialize the Commerce Android module and check for errors, please refer to com.elavon.commerce.ECLCommerceAndroid for details. The actual error should be of type com.elavon.commerce.ECLCommerceError.
ECCError error = ECLCommerceAndroid.initialize(getApplication()); // if initialized, error will be null. Otherwise stop here and fix the error. // Possible errors are // ECLCommerceError.Codes.ECLSecurityLibraryNotFound, // ECLCommerceError.Codes.ECLDeviceRooted, // ECLCommerceError.Codes.ECLTlvLibraryNotFound, // ECLCommerceError.Codes.ECLStringTablesNotFound if (error instanceof ECLCommerceError) { ... }
- Instantiation of Opayo account listener and Opayo account
- We need to define a class implementing interface com.elavon.commerce.ECLOpayoAccountListener and create an instance of the class and use it in Opayo Account creation. Note that ECLOpayoAccountListener is an extension of com.elavon.commerce.ECLAccountListener, which provides callback methods for the result of the account creation.
// The following code block is copied from CommerceOpayoAccountListener.java in the sample application code, // This class implements interface ECLOpayoAccountListener, which provides the required attributes to set up Opayo Account. class CommerceOpayoAccountListener implements ECLOpayoAccountListener, ECLAccountInformationRetrievalListener { @Override public Context getApplicationContext() { // return Android Context wrapped in deckard.content.android.AndroidContext (see section 2.3 below) return context; } @Override public ECLServerType getServerType() { // return ECLServerType.DEMO if you have a test account return ECLServerType.PROD; } @Override public ECCSensitiveData getMerchantId() { // merchantID (MID) return new ECCSensitiveData("myMerchantId"); } @Override public ECCSensitiveData getClientId() { // clientID (TID) return new ECCSensitiveData("myClientId"); } @Override public ECCSensitiveData getPassword() { // return Initial Password for account at first // after first transaction you will receive the hashed password, so return hashed password from that point on return new ECCSensitiveData("myPassword"); } @Override public ECCSensitiveData getPin() { // return the optional operator PIN if set for the account; otherwise return null return new ECCSensitiveData("myPin"); } ... } // If account is successfully instantiated, method accountDidInitialize defined on ECLAccountListener will be called
- Then we need to create deckard.android.os.AndroidHandler, as shown below.
deckard.os.Handler handler = new AndroidHandler(new android.os.Handler(android.os.Looper.getMainLooper()));
- After that, we create an instance of deckard.content.android.AndroidContext.
deckard.content.Context csdkContext = new deckard.content.android.AndroidContext(getApplicationContext());
- We'll create an instance of CommerceOpayoAccountListener with the context and handler already created previously.
ECLOpayoAccountListener delegate = new CommerceOpayoAccountListener(csdkContext, activity, handler);
- Then we create an instance of com.elavon.commerce.ECLDispatcher.
final ECLDispatcher dispatcher = new ECLDispatcher(handler);
- At last we use ECLCommerce to create account.
ECLCommerce.createAccount(delegate, dispatcher);
- If account is successfully created, method accountDidInitialize defined on com.elavon.commerce.ECLAccountListener will be called. The POS system should cache com.elavon.commerce.ECLAccountInterface for later use. If account fails to instantiate, method accountDidFailToInitialize on com.elavon.commerce.ECLAccountListener will be called with a list of errors. POS system should resolve the error before any further integration.
// The following code block is copied from CommerceOpayoAccountListener.java in the sample application code. class CommerceOpayoAccountListener implements ECLOpayoAccountListener, ECLAccountInformationRetrievalListener { ... @Override public void accountDidInitialize(ECLAccountInterface account) { // the account interface is cached in the sample application. TransactionSavedState.INSTANCE.account = account; } // account usually is null and the error lists the reason for the failure. @Override public void accountDidFailToInitialize(ECLAccountInterface account, ECCError error) { } }
Pair and Connect to Device
After successfully instantiating an account, we can pair the card reader to the Android device if it hasn't been paired already. If POS system does not intend to support in-app pairing, please jump to the next section.
Pair Card Reader
Paring device consists of two steps:
Find Pairable Devices
We should first define a class implementing interface com.elavon.commerce.ECLFindDevicesListener.
// The following code is copied from MainActivity.java in the sample application code. // Here a new instance of com.elavon.commerce.ECLFindDevicesListener is instantiated with the implementation. ECLFindDevicesListener theListener = new ECLFindDevicesListener() { @Override public deckard.content.Context getApplicationContext() { return new deckard.content.android.AndroidContext(thisActivity.getApplicationContext()); } @Override public void uponSearchingDevices(EnumSet<ECLConnectionType> enumSet) { } @Override public void devicesSearchFound(String s, ECLConnectionType eclConnectionType) { // display the detected item on UI displayMessage("devicesSearchFound " + s); } @Override public void devicesSearchDone(List<ECLFindDevicesSearchResult> list) { handler.post(() -> { if (!list.isEmpty()) { // The following is just an example of getting search results. List<String> deviceNames = new ArrayList<>(); for (ECLFindDevicesSearchResult result : list) { deviceNames.add(result.getName()); } } else { showMessage("No card readers to pair"); } }); } } // Then use the following code to search devices // The account is cached from callback method accountDidInitialize defined on com.elavon.commerce.ECLAccountListener TransactionSavedState.INSTANCE.account.getCardReaders().findPairableDevices(theListener);
If there are multiple search results in the previous code block, POS system should prompt merchant to select one to pair. Assuming the selected device name is called deviceName, the following code blocks demonstrates how to pair device. First we'll create an instance of com.elavon.commerce.ECLDevicePairingListener, as shown below.
// The following code is copied from MainActivity.java in the sample application code. ECLDevicePairingListener devicePairingListener = new ECLDevicePairingListener() { @Override public void devicePairingSucceeded(ECLDeviceInterface device) { if (device instanceof ECLCardReaderInterface) { showMessage(((ECLCardReaderInterface) device).getName() + " Paired Succesfully"); } else { showMessage("Paired!"); } } @Override public void devicePairingFailed(ECLDeviceInterface device, final ECCError error) { showMessage("Failed to pair: " + error.getDebugDescription()); } @Override public void devicePairingProgress(ECLDeviceInterface device, final ECLTransactionProgress progress) { handler.post(() -> displayMessageInProgressView("device pairing Progress: " + progress.toString(), false)); } };
Pair a Selected Device
We'll get the com.elavon.commerce.ECLDeviceInterface instance stored in Commerce SDK based on deviceName from the previous step and use the instance to pair the device.
// Gets the device interface stored in Commerce SDK. // deviceName is the name from a searchResult. // the connection type can only be Bluetooth because we previously searched pairable device, ECLDeviceInterface deviceInterface = TransactionSavedState.INSTANCE.account.getCardReaders().selectDevice(deviceName, EnumSet.of(ECLConnectionType.BT)); // then pair the device. // If device is successfully paired, method devicePairingSucceeded(...) on ECLDevicePairingListener will be called. deviceInterface.pair(devicePairingListener);
You can use the above approach to pair more devices.
TMS Update
The first time after installing the CommerceSDK integrated application on the Android device, you must perform a FULL TMS (Terminal Management System) update to retrieve the most up-to-date configurations for your terminal and card reader. Note that card reader connection/initialization will not work unless you have performed a FULL TMS update first.
Check Required TMS Update Type
You can call a method to retrieve the current required TMS update type. It will return FULL when the application is first installed. Note that this method is provided as a convenience mainly to check if a FULL TMS update is needed. However, you can perform a TMS update at any time without calling this method.
The method is getRequiredTmsUpdateType on interface com.elavon.commerce.ECLOpayoAccountInterface. Please see com.elavon.commerce.ECLOpayoTmsUpdateType for all possible values.
ECLOpayoAccountInterface opayoAccount = (ECLOpayoAccountInterface)TransactionSavedState.INSTANCE.account; ECLOpayoTmsUpdateType updateType = opayoAccount.getRequiredTmsUpdateType();
Perform FULL TMS Update
You can use the same ECLOpayoAccountInterface to perform the TMS Update. First you need to create an instance of com.elavon.commerce.ECLTmsUpdateListener.
// The following code block is copied from the sample application code ECLTmsUpdateListener getTmsUpdateListener(MainActivity activity, ECLOpayoTmsUpdateType updateType) { return new ECLTmsUpdateListener() { @Override public void shouldSetCardReaderToUse(List<String> cardReaders) { // if multiple card readers are available, select one and call to update again activity.displayMessageInProgressView("TMS update multiple readers", false); ECLAccountInterface account = TransactionSavedState.INSTANCE.account; account.getCardReaders().selectDevice(cardReaders.get(0), ECLConnectionType.enumSetForAll()); new Thread(() -> ((ECLOpayoAccountInterface)account).performTmsUpdate(updateType, getTmsUpdateListener(activity, updateType))).start(); } @Override public void selectedCardReader(String cardReaderName) { activity.displayMessageInProgressView("TMS update selectedCardReader " + cardReaderName, false); } @Override public void started(ECLTransactionProgress progress) { activity.displayMessageInProgressView("TMS update started", false); } @Override public void progress(ECLTransactionProgress progress) { activity.displayMessageInProgressView("TMS update progress: " + progress, false); } @Override public void completed(boolean success, ECLTransactionProgress progress, ECCError eccError) { if (success) { activity.displayMessageInProgressView("TMS update successfully completed", false); } else { activity.displayMessageInProgressView("TMS update failed: " + eccError.getDebugDescription(), false); } } }; }
Now we can call method performTmsUpdate.
((ECLOpayoAccountInterface)account).performTmsUpdate(ECLOpayoTmsUpdateType.FULL, getTmsUpdateListener(activity, ECLOpayoTmsUpdateType.FULL));
Perform FULL TMS Update
You can also perform a NORMAL TMS update at any time. This can be used to update various account related changes for your app such as gratuity and operator PIN support. It is also recommended to perform this update once a day to ensure the app is up-to-date with the account and terminal configuration on the server.
((ECLOpayoAccountInterface)account).performTmsUpdate(ECLOpayoTmsUpdateType.NORMAL, getTmsUpdateListener(activity, ECLOpayoTmsUpdateType.NORMAL));
Connect Card Reader
We can now establish a connection to the card reader so that we can perform transactions. Note that connecting explicitly via this method is not required. You can choose to start a transaction and CommerceSDK will connect to the device internally if it is not already connected.
Connecting to Card Reader
Define an instance of com.elavon.commerce.ECLFindDevicesListener.
// The following code is copied from MainActivity.java in the sample application code. // Here a new instance of com.elavon.commerce.ECLFindDevicesListener is instantiated with the implementation. com.elavon.commerce.ECLFindDevicesListener findPairedDeviceListener = new ECLFindDevicesListener() { @Override public deckard.content.Context getApplicationContext() { return new deckard.content.android.AndroidContext(thisActivity.getApplicationContext()); } @Override public void uponSearchingDevices(EnumSet<ECLConnectionType> connectionTypes) { //Nothing to do in sample application } @Override public void devicesSearchFound(String deviceName, ECLConnectionType eclConnectionType) { //Simply display device name on UI displayMessage("devicesSearchFound " + deviceName); } @Override public void devicesSearchDone(List<ECLFindDevicesSearchResult> list) { if (!list.isEmpty()) { // The search is complete. There is paired device and the POS system should ask merchant to select. // Please refer to implementation example in the sample application. } else { displayMessage("devicesSearchDone - no devices"); } } };
To find a paired device, you'll use method findDevice defined on com.elavon.commerce.ECLAccountInterface to find all the paired devices.
// The following code is copied from MainActivity.java in the sample application code // The first parameter is the instance of com.elavon.commerce.ECLFindDevicesListener created in the previous code block // The second parameter is set to false, indicating that we'll not disconnect device // The third parameter is set to 120, i.e. searching timeout is 2 minutes. TransactionSavedState.INSTANCE.account.findDevices(findPairedDeviceListener, false, 120);
Assuming that we find a list of paired devices, we'll first implement an instance of com.elavon.commerce.ECLCardReaderListener after merchant makes the selection, as shown below. Please pay attention to when card reader interface instance is cached.
// The following code is copied from CardReaderListenerAdapter.java in the sample application code. // CardReaderListenerAdapter implements interface com.elavon.commerce.ECLCardReaderListener by providing empty implementation. public class CardReaderListenerAdapter implements ECLCardReaderListener { @Override public void cardReaderConnectedAndWillInitialize(ECLCardReaderInterface cardReader) { } @Override public void cardReaderInitialized(ECLCardReaderInterface cardReader, ECLDeviceConnectionChangeReason reason) { } @Override public void cardReaderConnectionOrInitializationError(ECLCardReaderInterface cardReader, ECCError error) { } @Override public void cardReaderWillUpdateConfiguration(ECLCardReaderInterface cardReader) { } @Override public void cardReaderUpdateSucceeded(ECLCardReaderInterface cardReader) { } @Override public void cardReaderUpdateError(ECLCardReaderInterface cardReader, ECCError error) { } @Override public void cardReaderWillReboot(ECLCardReaderInterface cardReader) { } @Override public void cardReaderShouldManuallyReboot(ECLCardReaderInterface cardReader, boolean didUpdate) { } @Override public void cardReaderRebootError(ECLCardReaderInterface cardReader, ECCError error) { } @Override public void cardReaderReconnect(ECLCardReaderInterface eclCardReaderInterface) { } @Override public void cardReaderWillReset(ECLCardReaderInterface cardReader) { } @Override public void cardReaderDidReset(ECLCardReaderInterface cardReader) { } @Override public void cardReaderResetError(ECLCardReaderInterface cardReader, ECCError error) { } @Override public void cardReaderDisconnected(ECLCardReaderInterface cardReader, boolean isStillTransacting, ECLDeviceConnectionChangeReason reason) { } @Override public void cardReaderProgress(ECLCardReaderInterface cardReader, ECLTransactionProgress progress) { } } // The following code is copied from MainActivity.java in the sample application code CardReaderListenerAdapter cardReaderListener = new CardReaderListenerAdapter() { @Override public void cardReaderInitialized(ECLCardReaderInterface cardReader, ECLDeviceConnectionChangeReason reason) { // Here card reader is connected and initialized, cache it. _cardReaderInterface = cardReader; displayMessage("Reader initialized reason: " + reason); } @Override public void cardReaderConnectionOrInitializationError(ECLCardReaderInterface cardReader, ECCError error) { // Just display the error displayMessage("Connection Error: " + error.toString()); } @Override public void cardReaderProgress(ECLCardReaderInterface cardReader, ECLTransactionProgress progress) { // Display the progress displayMessage("Progress when setting card reader: " + progress.toString()); } @Override public void cardReaderWillUpdateConfiguration(ECLCardReaderInterface cardReader) { displayMessage("Updating reader..."); } @Override public void cardReaderUpdateSucceeded(ECLCardReaderInterface cardReader) { displayMessage("Reader update succeeded"); } @Override public void cardReaderUpdateError(ECLCardReaderInterface cardReader, ECCError error) { displayMessage("Reader update failed: " + error.toString()); } };
Then obtain the device interface (com.elavon.commerce.ECLDeviceInterface) from the account cached previously in the sample application.
// The following code is copied from FindDeviceResultsDialog.java in the sample application // deviceName is the name of the devices. We are looking for card reader so device type is set to CARD_READER. ECLCardReaderInterface _cardReaderInterface = TransactionSavedState.INSTANCE.account.getCardReaders().selectDevice(deviceName, ECLDeviceType.CARD_READER); // Then add the card reader listener to the card reader interface _cardReaderInterface.addConnectionListener(cardReaderListener); // Then connect and initialize the card reader through Commerce SDK _cardReaderInterface.connectAndInitialize(true);
If card reader is successfully connected and initialized, method cardReaderInitialized on com.elavon.commerce.ECLCardReaderListener will be called.
Process Transaction
POS system could process transaction by creating a transaction object and send it to Commerce SDK (CSDK) without first connecting to card reader. However, it can sometimes take several minutes for Commerce SDK to successfully connect and initialize a card reader so it is strongly encouraged that the POS system calls Commerce SDK to connect and initialize card reader before running any transactions.
Commerce SDK supports three transaction types:
- SALE transaction (card holder makes a purchase of goods or service).
- Linked Refund transaction (merchant returns a portion or the whole of amount for a SALE transaction back to card holder).
- Stand Alone Refund (SAR) transaction (merchant returns an amount back to carder holder).
SALE and SAR transactions require interaction with card reader while Linked Refund transaction can be executed without a card reader.
SALE Transaction
The following steps lists how to create a SALE transaction and process it.
- In order for CSDK to process a SALE transaction we'll need to create an instance of com.elavon.commerce.datatype.ECLMoney to represent the base transaction amount.
// In this example we create a sale amount of £10.50. ECLMoney saleAmount = new ECLMoney(ECLCurrencyCode.GBP, 1050);
- We then retrieve com.elavon.commerce.ECLTransactionProcessorInterface from the cached account and use it to create an instance of com.elavon.commerce.ECLCurrencyTransactionInterface with the amount just defined above.
// Variable account is the one cached after CSDK is successfully initialized. ECLCurrencyTransactionInterface saleTransaction = account.getTransactionProcessor().createSaleTransactionWithSubtotal(saleAmount);
- We will also create an instance of com.elavon.commerce.ECLCardTenderInterface.
ECLCardTenderInterface cardTender = account.getTransactionProcessor().createCardTender();
- We then create an instance of com.elavon.commerce.ECLOpayoTransactionProcessingListener. Note that it is an extension of com.elavon.commerce.ECLTransactionProcessingListener.
// The following code block is copied from the sample application code. // Some of the method implementations are omitted because they are not applicable to EU market at this point. TransactionSavedState.INSTANCE.transactionListener = new ECLOpayoTransactionProcessingListener() { @Override public void passwordHashUpdated(ECLTransactionInterface transaction, ECLTenderInterface tender, ECCSensitiveDataInterface newPasswordHash) { // you will receive this after running your first transaction with the initial account password. // you must now return the password hash in your ECLOpayoAccountListener.getPassword() implementation } // This method will be called by CSDK after transaction is completed. transaction outcome is returned from CSDK // along with the original transaction request and tender. @Override public void transactionDidComplete(ECLTransactionInterface transaction, ECLTenderInterface tender, final ECLTransactionOutcome outcome) { if (outcome == null) { logger.warn("transaction completed... with null outcome"); return; } if (outcome.getError() != null) { // check if there was an error during transaction completion displayErrorInProgressView("transaction error", outcome.getError()); } if (outcome.getAuthorizationResult() != null) { // check transaction result, i.e. approved, declined, etc. displayMessageInProgressView("Result: ", outcome.getAuthorizationResult()); } if (outcome instanceof ECLCardTransactionOutcome) { // check attributes for card transaction } if (outcome instanceof ECLEmvCardTransactionOutcome) { // check attributes for emv card transaction } } // This method will be called by CSDK if transaction failed to be processed, for example card holder presses cancel button // on card reader when being prompted to insert/tap/swipe card. Errors are returned along with the original transaction request and tender. @Override public void transactionDidFail(ECLTransactionInterface transaction, ECLTenderInterface tender, List<ECCError> errors) { logger.warn("transactionDidFail"); showErrors("transaction", errors); TransactionSavedState.INSTANCE.currentTransaction = null; } // CSDK will ask POS system to provide specific information by calling this method if there is any further information needed to // process a transaction. @Override public void shouldProvideInformation(final ECLTransactionInterface transaction, final ECLTenderInterface tender, ECLTransactionRequirementsInterface transactionRequires, ECLTenderRequirementsInterface tenderRequires) { boolean continueTransaction = false; if (tenderRequires.getRequiresVoiceReferral() != ECLVoiceReferralRequirement.NOT_REQUIRED) { displayMessageInProgressView("Providing voice referral", false); // you should use the phone number provided by ECLTenderRequirementsInterface.getVoiceReferralPhoneNumber() to call and receive voice auth code ((ECLCardTenderInterface) tender).setVoiceReferralHandledAndApproved("123"); continueTransaction = true; } if (tenderRequires.getRequiresSignatureVerification() != ECLSignatureVerificationRequirement.NOT_REQUIRED) { displayMessageInProgressView("Providing signature verification", false); ((ECLCardTenderInterface) tender).setSignatureVerificationHandledAndVerified(); continueTransaction = true; } if (tenderRequires.requiresSpecifyingCardPresence()) { displayMessageInProgressView("Specifying card presence", false); ((ECLCardTenderInterface) tender).setCardPresent(ECLTriState.YES); // can also be ECLTriState.NO if card not present continueTransaction = true; } if (transactionRequires.isGratuityRequired()) { ((ECLCurrencyTransactionInterface) transaction).setGratuity(null); continueTransaction = true; } // After providing required information, POS system should ask CSDK to continue to process transaction by making the following calls if (continueTransaction) { // calls account.getTransactionProcessor().continueProcessingTransaction(transaction, tender, transactionListener) handler.post(() -> new ContinueProcessingTransactionTask(TransactionSavedState.INSTANCE.account, transaction, tender).execute( TransactionSavedState.INSTANCE.transactionListener)); } } // Called when there are multiple card readers available for use during a transaction // Tell CSDK which one to use so the transaction can proceed @Override public void shouldSetCardReaderToUse(final ECLTransactionInterface transaction, final ECLTenderInterface tender, final List<String> cardReadersReadyForUse) { account.getTransactionProcessor().selectDevice(cardReadersReadyForUse.get(0), ECLConnectionType.enumSetForAll()); // calls account.getTransactionProcessor().continueProcessingTransaction(transaction, tender, transactionListener) handler.post(() -> new ContinueProcessingTransactionTask(TransactionSavedState.INSTANCE.account, transaction, tender).execute( TransactionSavedState.INSTANCE.transactionListener)); } // CSDK notifies POS system any progress during transaction process. Typical progress is // ECLTransactionProgress.CARD_ENTRY_PROMPTED when card reader prompts card holder to insert/tap/swipe/manual_enter card @Override public void transactionProgress(final ECLTransactionProgress progress, final ECLTransactionInterface transaction, final ECLTenderInterface tender) { } };
- Afterwards we can call CSDK to process the transaction by making the following call. This is an asynchronous call and CSDK will later notify the POS system about the transaction result through the transaction listener defined above. Please refer to com.elavon.commerce.ECLTransactionOutcome for general transaction details, com.elavon.commerce.ECLCardTransactionOutcome for card based transaction details, and com.elavon.commerce.ECLEmvCardTransactionOutcome for EMV card based transaction details.
// Variable account is the one cached after CSDK is successfully initialized. account.getTransactionProcessor().processTransaction(saleTransaction, cardTender, TransactionSavedState.INSTANCE.transactionListener);
Sale Transaction Attributes
After a SALE transaction is created, a few attributes can be added to the transaction before CSDK processes it. This section discusses about the optional attributes for SALE transaction.
- Gratuity
This attribute can be used to add tip to a SALE transaction.
// Assume we a SALE transaction created here, the amount is £20.00 ECLCurrencyTransactionInterface saleTransaction = account.getTransactionProcessor().createSaleTransactionWithSubtotal(new ECLMoney(ECLCurrencyCode.GBP, 2000)); // The following example shows that a tip of £1.00 is set for the SALE transaction, now the total amount becomes £21.00. // Please the currency code used for Grauity must be same as for the amount used when creating SALE transaction. saleTransaction.setGratuity(new ECLMoney(ECLCurrencyCode.GBP, 100));
- Tax
This attribute can be used to add tax to a SALE transaction.
// Using the same SALE transaction object created in the previous block // The following example shows that a tip of £1.00 is set for the SALE transaction, now the total amount becomes £23.00 // Please the currency code used for Tax must be same as for the amount used when creating SALE transaction. saleTransaction.setTax(new ECLMoney(ECLCurrencyCode.GBP, 200), ECLTaxType.SALE_GENERAL);
- Merchant Reference ID
This attribute can be used to set a reference Id to a SALE transaction, which can be used as cross-reference by merchant's other software system for this transaction.
// Using the same SALE transaction object created in the previous block saleTransaction.setMerchantTransactionReference("Referend Id can be used as cross reference");
Linked Refund Transaction
The same steps for processing SALE transaction should be followed to handle linked refund transaction. The only difference is that an instance of com.elavon.commerce.ECLLinkedRefundTransactionInterface should be created in step 2. You will need the unique identifier of the original SALE transaction that was returned to you as part of the ECLTransactionOutcome.
// The following code is copied from TransactionDialog.java in the sample application code. // originalSaleTransactionUniqueId is the unique id from the original sale transaction outcome. // amount is money value to be refunded. Please note that the value should be equal to or less than the refundable amount from the original SALE transaction. // Variable account is the one cached after CSDK is successfully initialized. ECLLinkedRefundTransactionInterface linkedRefundTransaction = account.getTransactionProcessor().createLinkedRefundTransactionWithTotal(amount, originalSaleTransactionUniqueId); // process the transaction, see SALE transaction page for details on how to create the other parameters account.getTransactionProcessor().processTransaction(linkedRefundTransaction, cardTender, transactionListener);
Stand Alone Refund Transaction
The same steps for processing SALE transaction should be followed to handle standalone refund transaction. The only difference is that an instance of com.elavon.commerce.ECLStandaloneRefundTransactionInterface should be created in step 2.
// Variable account is the one cached after CSDK is successfully initialized. // Variable amount is the total amount to be refunded. ECLStandaloneRefundTransactionInterface standaloneRefundTransaction = account.getTransactionProcessor().createStandaloneRefundTransactionWithTotal(amount); // process the transaction, see Sale transaction page for details on how to create the other parameters account.getTransactionProcessor().processTransaction(standaloneRefundTransaction, cardTender, transactionListener);