API Examples
Java API Examples Collection
To jump straight to the pure code of all the following API examples, see Java API Examples.
Generating a Transaction ID
As we mentioned in GETTING_STARTED, it is a matter of personal choice how you generate the unique transaction ID. We recommend the following format:
String currentDateTime = new SimpleDateFormat("yyyyMMddHHmmss")
.format(Calendar.getInstance().getTime());
StringBuilder postfix = new StringBuilder();
for(int i = 0; i < 3; i++) {
Random rand = new Random();
int randomNum = rand.nextInt(10);
postfix.append(Integer.toString(randomNum));
}
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
...
Sale Transaction
- Card present: YES
Transaction transaction = new Transaction();
transaction.amount = "100";
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.SALE;
transaction.currency = Transaction.Currency.EUR;
transaction.receiptNum = "1";
transaction.txOrigin = "1";
transaction.sourceID = "1";
transaction.langCode = "EN";
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
// Alternatively, use the short variant: paymentService.sale(12300000, currentDateTime + postfix, currentDateTime, 100, "EUR");
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
System.out.println("Transaction Approved");
System.out.println("response: " + response.getResponse());
transaction.toString(); // Transaction object in JSON format. After the transaction has successfully completed, you can use this object to store the transaction in your application, thus enhancing the merchant's experience.
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Ideally, you can use paymentService.sale(int, String, String, int, String)
without having to initialize the Transaction
object.
Pre-Auth Transaction
- Card present: YES
Transaction transaction = new Transaction();
transaction.amount = "100";
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.PRE_AUTHORIZATION;
transaction.currency = Transaction.Currency.EUR;
transaction.receiptNum = "1";
transaction.txOrigin = "5";
transaction.sourceID = "1";
transaction.langCode = "EN";
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
System.out.println("Transaction Approved");
System.out.println("response: " + response.getResponse());
transaction.toString(); // Transaction object in JSON format. After the transaction has successfully completed, you can use this object to store the transaction in your application, thus enhancing the merchant's experience.
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
For more on this type of transaction, see References.
Refund Transaction
- Card present: YES
As we pointed out in Getting Started, a refund transaction is a whole other transaction that returns money to the customer's bank account in the event of a complaint or return. It is the same as a sale transaction, just with a different message type.
Transaction transaction = new Transaction();
transaction.amount = "100";
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.CREDIT_NOTE;
transaction.currency = Transaction.Currency.EUR;
transaction.receiptNum = "1";
transaction.txOrigin = "1";
transaction.sourceID = "1";
transaction.langCode = "EN";
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
// Alternatively, you can use the short variant: paymentService.refund(12300000, currentDateTime + postfix, currentDateTime, 100, "EUR");
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
System.out.println("Transaction Approved");
System.out.println("response: " + response.getResponse());
transaction.toString(); // Transaction object in JSON format. After the transaction has successfully completed, you can use this object to store the transaction in your application, thus enhancing the merchant's experience.
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Sale Plus Tip Transaction
- Card present: YES
Transaction transaction = new Transaction();
transaction.amount = "100";
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.TIP_SALE;
transaction.currency = Transaction.Currency.EUR;
transaction.receiptNum = "1";
transaction.ecrdata = "TIP=10;"; // Tip in cents e.g. 10 = 0.10
transaction.txOrigin = "1";
transaction.sourceID = "1";
transaction.langCode = "EN";
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
// Alternatively, you can use the short variant: paymentService.sale(12300000, currentDateTime + postfix, currentDateTime, 100, 10, "EUR");
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
System.out.println("Transaction Approved");
System.out.println("response: " + response.getResponse());
transaction.toString(); // Transaction object in JSON format. After the transaction has successfully completed, you can use this object to store the transaction in your application, thus enhancing the merchant's experience.
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Capture Transaction
- Card present: NO
NOTE: most card-not-present transactions require the original transaction ID to be specified.
public String padWithZeros(String str) {
StringBuilder s = new StringBuilder();
for(int i = 0; i < 20 - str.length(); i++) {
s.append('0');
}
return s + str;
}
The exact original transaction ID is the identifier of the transaction being sent to the acquirer for authorization.
Transaction transaction = new Transaction();
transaction.amount = "100";
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = "0017";
transaction.currency = Transaction.Currency.EUR;
transaction.receiptNum = "1";
transaction.txOrigin = "4";
transaction.sourceID = "1";
transaction.langCode = "EN";
transaction.cardNum = "TXID" + padWithZeros("20240515230015056"); // The original transaction ID is padded with zeros in order to give it a length of 20.
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
System.out.println("Transaction Approved");
System.out.println("response: " + response.getResponse());
transaction.toString(); // Transaction object in JSON format. After the transaction has successfully completed, you can use this object to store the transaction in your application, thus enhancing the merchant's experience.
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Cancel Transaction
- Card present: NO
NOTE: most card-not-present transactions require the original transaction ID to be specified.
To cancel a transaction, the original transaction ID needs to be specified. This ID is the exact identifier of the transaction being cancelled. The other fields, such as amount and currency, likewise have to be exact in order for the cancellation to be completed.
Transaction transaction = new Transaction();
transaction.amount = "100";
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.CANCEL;
transaction.currency = Transaction.Currency.EUR;
transaction.receiptNum = "1";
transaction.txOrigin = "2";
transaction.sourceID = "1";
transaction.originInd = "2"; // Transaction.TransactionOriginIndicator.MAIL_ORDER
transaction.langCode = "EN";
transaction.cardNum = "TXID" + padWithZeros("20240515230015056"); // The original transaction ID is padded with zeros in order to give it a length of 20.
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
System.out.println("Transaction Cancelled");
System.out.println("response: " + response.getResponse());
transaction.toString(); // Transaction object in JSON format. After the transaction has successfully completed, you can use this object to store the transaction in your application, thus enhancing the merchant's experience.
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Get Status
There are other types of requests beside transaction requests, such as terminal status, connection status and reconciliation request. These requests are treated as transaction requests as they have to be sent over TCP.
Terminal Status
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.msgType = Transaction.MessageType.GET_TERMINAL_STATUS;
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
System.out.println("response: " + response.getResponse());
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Connection Status
This is basically the same code as shown below except with a different message type constant: Transaction.MessageType.CONNECTION_STATUS
.
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.msgType = Transaction.MessageType.CONNECTION_STATUS;
try {
// Alternatively
// paymentService.connectionStatus(String transactionID, String dateTime)
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
System.out.println("response: " + response.getResponse());
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Reconciliation Request
- Card present: NO
The reconciliation request feature makes it possible for the ECR to receive reconciliation data covering the time period from the last reconciliation to the current reconciliation. This functionality ensures that all transaction data within this period is accurately captured and processed, thus providing a clear and comprehensive overview of the financial activities and transactions that took place in the period in question.
Reconciliation data includes all sales, refunds and adjustments made during the specified period. By leveraging this feature, businesses can maintain accurate financial records, streamline their accounting processes and ensure compliance with financial reporting standards. This is especially beneficial for end-of-day or end-of-period financial reporting as it enables businesses to verify that all transactions have been correctly recorded and accounted for.
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.RECONCILIATION_REQUEST;
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
// Handle response.getReconciliationResponse()
System.out.println(response.getReconciliationResponse());
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
The reconciliation response returned by getReconciliationResponse
consists of the following JSON
fields:
Key | Description |
---|---|
"cardAID" | Card brand AID (e.g. A0000000032020, A0000000043060, A000000025) |
"cardProviderName" | Card brand name (e.g. American Express, Visa, Mastercard, Bankaxept) |
"numberOfDebit" | Number of sale transactions |
"debitAmount" | Transaction amount (basic amount without refunds or tips) |
"tip" | Tip |
"debitTotal" | Total sum of basic amounts plus tips |
"numberOfCredit" | Number of refund transactions |
"creditTotal" | Total credit amount including refunds and tips |
Here is an example of a reconciliation response:
{
"cardtypeData":[
{
"cardAID":"A000000003",
"cardProviderName":"VISA",
"numberOfDebit":12345,
"debitAmount":123.45,
"tip":0.06,
"debitTotal":1234.56,
"numberOfCredit":9,
"creditTotal":1234
},
{
"cardAID":"A000000004",
"cardProviderName":"MASTERCARD",
"numberOfDebit":59,
"debitAmount":0.12,
"tip":0.03,
"debitTotal":1.23,
"numberOfCredit":5,
"creditTotal":12
},
{
"cardAID":"A000000025",
"cardProviderName":"AMEX",
"numberOfDebit":58,
"debitAmount":0.11,
"tip":0.03,
"debitTotal":1.23,
"numberOfCredit":5,
"creditTotal":12
},
{
"cardAID":"D5780000021010",
"cardProviderName":"BANKAXEPT",
"numberOfDebit":57,
"debitAmount":0.1,
"tip":0.03,
"debitTotal":1.23,
"numberOfCredit":5,
"creditTotal":12
}
],
"numberOfDebitSum":99,
"debitAmountSum":123.45,
"tipSum":0.06,
"debitSum":1234.56,
"numberOfCreditSum":9,
"creditAmountSum":1234
}
Abort Transaction
- Card present: NO
By using SmartPOS on another ECR, this request allows a transaction that is in progress to be interrupted. The transaction in question is taking place on a terminal that is in card reader screen mode (as this is where, by default, NaTALI sits). 'AbortTransaction' is commonly used in Semi-Integrated Mode. For the detailed workflow of this use case, see Use Cases.
It is important to specify the terminal identifier for this request. This simulates the cancel button on the screen of that terminal.
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.ABORT;
transaction.currency = Transaction.Currency.EUR;
transaction.receiptNum = "1";
transaction.txOrigin = "1";
transaction.sourceID = "1";
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
System.out.println("Transaction Aborted");
System.out.println("response: " + response.getResponse());
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Card Balance Request
- Card present: YES
If this request is successful, the balance amount is included in the response.
NOTE: this feature is only intended for specific voucher cards. It is not supported by standard payment cards.
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.BALANCE;
transaction.originInd = "0"; // Transaction.TransactionOriginIndicator.PIN_PAD
transaction.txOrigin = "7";
transaction.sourceID = "1";
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
String cardBalance = response.balanceAmount; // Received card balance.
System.out.println("Card Balance: " + cardBalance);
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
QR and Barcode Scanner
- Card present: NO
- Supported devices:
SCANNER
- N700
- N910
SCANNER_CAMER
- Any device with a camera
For this feature, NaTALI needs permission to access the camera. This can be set in Settings -> Apps -> NaTALI -> Permissions. The SCAN_ENABLED
parameter in your terminal configuration also needs to be activated (by Bluefin TECS).
As well as some of the most common transactions, SmartPOS also supports QR and barcode scanning. This is intended for any kind of content that an ISV can make use of to provide their ECR applications and their customers with more features.
To get the scanned data, SmartPOS implements getScanData as a utility function of response class.
The following two scanner modes are used to triggered the scanner:
- Silent scanner mode - the device scans QR codes and barcodes without displaying the camera view. Use message type - SCANNER to initiate this mode.
- Camera view scanner mode - camera view is displayed when the scanner activates. Use message type - SCANNER_CAMERA to initiate this mode.
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = Transaction.MessageType.SCANNER;
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
String scanData = response.getScanData();
// Use scanData
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
Offline Mode Transactions
-
Supported card reading methods:
- Chip insert
-
Supported transactions:
- Sale
Force Offline Mode
This transaction request allows an ECR to set the terminal to offline mode. In this mode, transactions such as sale, pre-auth and refund are added to the offline buffer and the offline transactions sit in the background. These can be retrieved using Offline Transation Pending Request. Once the device is rebooted or set back to online mode FTO=0
, the pending offline transactions are sent to the payment gateway.
This feature can be turned on and off using the FTO
parameter, as shown below.
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = "0019";
transaction.ecrdata = "FTO=X;"; // where X: 1 - enable offline transactions, 0 - disable
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
System.out.println("Offline transactions turned on/off");
System.out.println("response: " + response.getResponse());
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
FTO=1
- Force offline transactions; offline transactions enabled
FTO=0
- Offline transactions disabled - back to online mode
Offline Transaction Pending Request
This transaction request receives the number of offline transactions waiting to be sent to the payment gateway.
Transaction transaction = new Transaction();
transaction.ID = currentDateTime + postfix.toString();
transaction.dateTime = currentDateTime;
transaction.terminalNum = "TERMINALID";
transaction.msgType = "0020";
try {
paymentService.sendTransaction(transaction);
} catch (TransactionFieldException e) {
throw new RuntimeException(e);
}
paymentService.listen(new ResponseListener() {
@Override
public void onResponseReceived(Response response) {
if(response.responseCode.equals("0000")) {
String receiptFooter = response.receiptFooter; // OFFLINE_TX:X, where X: the number of pending offline transactions
// Use receiptFooter
}
}
@Override
public void onReadFailed() {
// ...
}
@Override
public void onDisconnected() {
// ...
}
});
SmartPOS Controller
Version 2.16.0
Java docs: https://doc.tecs.at/pubdoc/smartpos_sdk_javadoc/at/tecs/smartpos/SmartPOSController.html
The SmartPOS controller is supported from NaTALI version 1.48.0
on.
Supported by the SmartPOS SDK, the SmartPOS controller facilitates communication with the terminal's card module, thus enabling interaction with supported cards.
Importing SmartPOS Java Classes
import java.util.Arrays;
import java.util.ArrayList;
import at.tecs.smartpos.utils.Pair;
import at.tecs.ControlParser.Command;
import at.tecs.smartpos.CardControl;
import at.tecs.smartpos.SmartPOSController;
import at.tecs.smartpos.data.RFReturnCode;
import at.tecs.smartpos.data.PrinterPrintType;
import at.tecs.smartpos.data.PrinterReturnCode;
RF Communication
- Supported devices:
- All (with the exception of Sunmi devices, which are only able to read the UUID of an RF card).
To initiate communication with the card that is present, an RF interface is opened that waits for the card to be present. For Mifare cards, the user taps the card on or near the contactless card reader. The SmartPOSController
class implements this using the asynchronous openCardReader function. This function sits in the background for the specified number of milliseconds without launching the card reader screen. The events in the lifecycle of this function are recorded using the OpenCardReaderListener
interface methods.
Supported card types:
- Mifare cards (Mifare Ultralight C and Mifare Classic) - commonly used for room cards and membership cards.
Command.CARD_TYPE.*
- Card types
A
andB
are high frequency (HF) RFID cards with a security layer or protocol, or payment cards. - Card types
M0
andM1
are high frequency (HF) RFID cards without a security layer or protocol.
- Card types
OpenListener Events Description
-
onDetected
: this event is triggered when the RF interface is successfully opened and a card is detected. It enables communication with the detected card using theCardControl
class instance, which is passed as an argument to theonDetected
function. -
onError
: this event captures unexpected return codes.
SmartPOS RF Communication - Read Block Example
SmartPOSController smartPOSController = new SmartPOSController();
// The RF interface opens for 10,000 milliseconds, accepting M0 card types.
// This operation is asynchronous. It is managed and its stages are handled using the OpenListener interface.
smartPOSController.openCardReader(10000, Command.CARD_TYPE.M0, new SmartPOSController.OpenCardReaderListener() {
@Override
public void onDetected(CardControl cardControl, int cardType, byte[] UUID) {
// The CardControl instance enables communication with the card through the RF interface.
RFReturnCode authenticationResult = cardControl.authenticateM0(new byte[] {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08});
if(authenticationResult == RFReturnCode.SUCCESS) {
// Writing test data to block with ID 0x01
RFReturnCode writeResult = cardControl.writeBlock(0x01, new byte[] {0x01, 0x02, 0x03, 0x04, 0x05});
if(writeResult == RFReturnCode.SUCCESS) {
// Reading from block with ID 0x01
Pair<RFReturnCode, byte[]> readResult = cardControl.readBlock(0x01);
if(readResult.first == RFReturnCode.SUCCESS && readResult.second != null) {
// Printing read data
System.out.println("Read data : " + Arrays.toString(readResult.second));
}
}
}
// When the operations with RF communication are done, the interface is closed.
cardControl.close();
}
@Override
public void onError(RFReturnCode returnCode) {
// Handle return code
}
});
SmartPOS RF Communication - Reading UUID
The UUID (unique identifier) of a Mifare card can be used in several ways, depending on the application and the system it is integrated with. Some common practical uses are access control, public transportation, attendance tracking, loyalty programs, library systems, asset tracking and event management.
UUID reading is supported by all devices. Only Sunmi devices can do the reading; all other communication methods are excluded.
SmartPOSController smartPOSController = new SmartPOSController();
smartPOSController.openCardReader(10000, Command.CARD_TYPE.M1, new SmartPOSController.OpenCardReaderListener() {
@Override
public void onDetected(CardControl cardControl, int cardType, byte[] UUID) {
StringBuilder hex_uuid = new StringBuilder();
for (byte b : UUID) {
hex_uuid.append(String.format("%02X ", b));
}
// Use UUID
System.out.println(Arrays.toString(UUID));
System.out.println(hex_uuid.toString());
cardControl.close();
}
@Override
public void onError(RFReturnCode returnCode) {
// Handle return code
System.out.println("Controller Error");
}
});
SmartPOS RF Communication - RF Transmit Example
The transmit function handles raw transmission functionality, thus enabling bulk commands to be sent and their responses to be received. Authentication, using a key for a specific card, must happen before read/write commands.
Authentication and the CRC calculation are implemented in the SmartPOS Demo application.
SmartPOSController smartPOSController = new SmartPOSController();
// The RF interface opens for 10,000 milliseconds, accepting M0 card types.
// This operation is asynchronous and can be managed with the OpenListener interface for handling its stages.
smartPOSController.openCardReader(10000, Command.CARD_TYPE.M0, new SmartPOSController.OpenCardReaderListener() {
@Override
public void onDetected(CardControl cardControl, int cardType, byte[] UUID) {
// The CardControl instance makes it possible to communicate with the card through the RF interface.
ArrayList<byte[]> request = new ArrayList<>();
// Read data from block 5 on Ultralight C card
request.add(Utils.calcCrc(new byte[]{0x30,(byte) 0x05}));
// Write data to block 5 on Ultralight C card
request.add(Utils.calcCrc(new byte[]{(byte) 0xA2, 0x05, 0x01, 0x02, 0x03, 0x04}));
// Perform communication with card
Pair<RFReturnCode, ArrayList<byte[]>> responseTmp = cardControl.transmit(request);
// The interface is closed when the operations with RF communication are done.
cardControl.close();
}
@Override
public void onError(RFReturnCode returnCode) {
// Handle return code
}
});
SmartPOS RF Communication - Close Example
You can close an open RF interface outside of the openCardReader
scope using the closeCardReader
function from the SmartPOSController
class. This action also triggers the onError
event in the OpenCardReaderListener
, resulting in RFReturnCode.DISCONNECTED
.
OpenCardReaderListener myListener = new SmartPOSController.OpenCardReaderListener() {
// See above
});
// The RF interface opens for 10,000 milliseconds, accepting M0 card types
smartPOSController.openCardReader(10000, Command.CARD_TYPE.M0, myListener));
// Closing an RF interface that is outside the scope of RFOpen
if(smartPOSController.closeCardReader() == RFReturnCode.SUCCESS) {
System.out.println("RF interface successfully closed!");
}
Printer
- Supported devices
- Newland N910
- Newland N910 PRO
- Newland N950
For a device to support this feature, DEVICE_CONTROL
has to be enabled (by Bluefin TECS).
To initiate communication with the terminal printer, use the openPrinter
function of the SmartPOSController
class. Similarly to how the card reader is managed, printer operations are accessed through the PrinterControl
instance. This instance is provided in the onOpened
callback of OpenPrinterListener
.
Here are some samples of what can be printed:
String imageBuffer = "Qk3+EgAAAAAAAD4AAAAoAAAAgAEAAGQAAAABAAEAAAAAAMAS...";
String receiptTicket = " KUNDENBELEG\n\n\nTID: 88091137 MID: 102003557\nDate: 07/05/2021 Time: 15:30\n\n\nSALE \nVISA CREDIT \nPAN: ************0119 \nPAN SEQ NO: 01 \nVISA ACQUIRER TEST/CARD 01 \n\n\nSTAN: 154714 \nTXID: 20210507153032 \nORIG. TXID: 20210507153032 \nAPPROVAL CODE: 213031 \nINVOICE:1 \nAC: F46E3CEA8232A966 \nAID: A0000000031010 \n\n\nEUR 1.00\n\n\n Authorized\n";
SmartPOSController smartPOSController = new SmartPOSController();
smartPOSController.openPrinter(new SmartPOSController.OpenPrinterListener() {
@Override
public void onOpened(PrinterControl printerControl) {
PrinterReturnCode ret = printerControl.getStatus();
if (ret != PrinterReturnCode.SUCCESS) {
printerControl.close();
return;
}
ret = printerControl.print(imageBuffer, PrinterPrintType.IMAGE);
if (ret != PrinterReturnCode.SUCCESS) {
printerControl.close();
return;
}
printerControl.feedLine(2);
ret = printerControl.print(receiptTicket, PrinterPrintType.TEXT);
if (ret != PrinterReturnCode.SUCCESS) {
printerControl.close();
return;
}
printerControl.feedLine(2);
ret = printerControl.print("https://www.tecs.at/", PrinterPrintType.QR_SMALL);
if (ret != PrinterReturnCode.SUCCESS) {
printerControl.close();
return;
}
printerControl.feedLine(10);
printerControl.close();
}
@Override
public void onError(PrinterReturnCode printerReturnCode) {
System.out.println("PRINTER ERROR");
System.out.println(printerReturnCode);
smartPOSController.closePrinter();
}
});
Updated about 1 month ago