TTS App Integration
App Definition
For your app to be recognized properly by the device, you should add the following meta-data to your AndroidManifest.xml file.
"1234" will be your payment operator id. We will send it to you.
<meta-data android:name="app_name" android:value="TTS_1234_APPNAME" />
<meta-data
android:name="app_model_type"
android:value="1000TR" />
<meta-data
android:name="app_version"
android:value="1" />Sale

Following code snippet is used by PaymentGateway in order to open payment application:
Bundle bundle = new Bundle();
bundle.putInt("Amount",amount);
bundle.putString("Plate",plate)
bundle.putString("TaxID",taxId);
bundle.putString("UUID",uuid);
bundle.putString("FuelType",fuelType);
bundle.putInt("FuelQuantity",fuelQuantity);
bundle.putInt("FuelPrice",fuelPrice); // Price per literAmount : Integer: Ex: 1.25 TL is written 125
UUID: Transactions are kept with this value on Payment Gate Way and your application in case of a power cut. Payment Gate Way sends this value and waits for the return of the transaction result.
Plate: String: Ex: "34AA111"
0
Kurşunsuz 95
1
Kurşunsuz 95-2
2
Kurşunsuz 98
3
Motorin
4
Motorin 2
5
Otogaz LPG
6
Gaz Yağı
7
Yakıt Nafta
8
LNG
9
Elektrik
10
CNG
11
ADBLUE
Manifest Modifications
To be able to get data from payment gateway, there should be intent filter like below in related class.
<activity android:name=".SaleActivity">
<intent-filter>
<action android:name="TTS_Sale_Action" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>After the payment process, the payment application should return the result.
void onSaleResponseRetrieved(Integer price, ResponseCode code, Boolean hasSlip, SlipType slipType, String cardNo, String ownerName) {
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putInt("ResponseCode", code.ordinal());
bundle.putInt("Amount",price);
bundle.putInt("BatchNo",0);
bundle.putInt("TxnNo",0);
bundle.putBoolean("IsSlip", hasSlip);
bundle.putString("RefundInfo", refound_info);
if (hasCustomerSlip) {
bundle.putString("customerSlipData", PrintHelper.getFormattedText(getSampleReceipt(cardNo, ownerName), SlipType.CARDHOLDER_SLIP));
}
if (hasMerchantSlip) {
bundle.putString("merchantSlipData", PrintHelper.getFormattedText(getSampleReceipt(cardNo, ownerName), SlipType.MERCHANT_SLIP));
}
resultIntent.putExtras(bundle);
setResult(Activity.RESULT_OK,resultIntent);
finish();
}responseCode : Result of the payment process
enum RESPONSE_CODE{
SUCCESS,
ERROR,
CANCELLED,
OFFLINE_DECLINE,
UNABLE_DECLINE,
ONLINE_DECLINE
}amount : Integer. Amount that is charged by the payment application. If amount is less than the Broadcasted Amount by Payment Gateway, it means Partial Limit is applied.
batchNo : The current Batch No which includes current sale.
txnNo : The current Txn No of the sale in current Batch.
IsSlip: Indicates that if a payment slip will be printed or not. (true to print slip)
customerSlipData: Formatted String for card holder slip.
merchantSlipData: Formatted String for merchant slip.
Sample Code to Generate Formatted Slip String
public static String getFormattedText(SampleReceipt receipt, SlipType slipType) {
StyledString styledText = new StyledString();
styledText.setLineSpacing(0.5f);
styledText.setFontSize(12);
styledText.setFontFace(PrinterDefinitions.Font_E.SourceSansPro);
styledText.addTextToLine(receipt.getMerchantName(), Alignment.Center);
styledText.newLine();
styledText.setFontFace(PrinterDefinitions.Font_E.Sans_Semi_Bold);
styledText.addTextToLine("İŞYERİ NO:", Alignment.Left);
styledText.setFontFace(PrinterDefinitions.Font_E.SourceSansPro);
styledText.addTextToLine(receipt.getMerchantID(), Alignment.Right);
styledText.newLine();
styledText.setFontFace(PrinterDefinitions.Font_E.Sans_Semi_Bold);
styledText.addTextToLine("TERMİNAL NO:", Alignment.Left);
styledText.setFontFace(PrinterDefinitions.Font_E.SourceSansPro);
styledText.addTextToLine(receipt.getPosID(), Alignment.Right);
styledText.newLine();
if (slipType == SlipType.CARDHOLDER_SLIP) {
styledText.addTextToLine("MÜŞTERİ NÜSHASI", Alignment.Center);
styledText.newLine();
}
else if (slipType == SlipType.MERCHANT_SLIP) {
styledText.addTextToLine("İŞYERİ NÜSHASI", Alignment.Center);
styledText.newLine();
}
styledText.addTextToLine("SATIŞ", Alignment.Center);
SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yy HH:mm:ss", Locale.getDefault());
String time = sdf.format(Calendar.getInstance().getTime());
styledText.newLine();
styledText.addTextToLine(time + " " + "C ONLINE", Alignment.Center);
styledText.newLine();
styledText.addTextToLine(receipt.getCardNo(), Alignment.Center);
styledText.newLine();
styledText.addTextToLine(receipt.getFullName(), Alignment.Center);
styledText.setLineSpacing(1f);
styledText.setFontSize(14);
styledText.setFontFace(PrinterDefinitions.Font_E.Sans_Semi_Bold);
styledText.newLine();
styledText.addTextToLine("TUTAR:");
styledText.addTextToLine(receipt.getAmount(), Alignment.Right);
styledText.setLineSpacing(0.5f);
styledText.setFontSize(10);
styledText.newLine();
if (slipType == SlipType.CARDHOLDER_SLIP) {
styledText.addTextToLine("KARŞILIĞI MAL/HİZM ALDIM", Alignment.Center);
}
else {
styledText.addTextToLine("İşlem Şifre Girilerek Yapılmıştır", Alignment.Center);
styledText.newLine();
styledText.addTextToLine("İMZAYA GEREK YOKTUR", Alignment.Center);
}
styledText.setFontFace(PrinterDefinitions.Font_E.Sans_Bold);
styledText.setFontSize(12);
styledText.newLine();
styledText.addTextToLine("SN: " + "0001");
styledText.addTextToLine("ONAY KODU: " + "235188", Alignment.Right);
styledText.setFontSize(8);
styledText.setFontFace(PrinterDefinitions.Font_E.Sans_Semi_Bold);
styledText.newLine();
styledText.addTextToLine("GRUP NO:" + receipt.getGroupNo());
styledText.newLine();
styledText.addTextToLine("AID: " + receipt.getAid());
styledText.newLine();
styledText.addTextToLine("BU İŞLEM YURT İÇİ KARTLA YAPILMIŞTIR", Alignment.Center);
styledText.newLine();
styledText.addTextToLine("BU BELGEYİ SAKLAYINIZ", Alignment.Center);
styledText.newLine();
styledText.printBitmap("ykb", 20);
styledText.addSpace(100);
return styledText.toString();
}You can receive the Z No and the Receipt No as;
getIntent().getExtras().getString("zNO");
getIntent().getExtras().getString("receiptNo");Pos Settings

Following code snippet is used by PaymentGateway in order to open payment application:
Intent sendIntentSettingsTxn = new Intent();
sendIntentSettingsTxn.setPackage(tag);
sendIntentSettingsTxn.setAction(getResources().getString(R.string.Settings_Action)); //Settings_Action="Settings_Action"
sendIntentSettingsTxn.setType("text/plain");
startActivityForResult(sendIntentSettingsTxn, getResources().getInteger(R.integer.Settings_Request_Code)); //Settings_Request_Code=24Manifest Modifications
To be able to get data from payment gateway, there should be intent filter like below in related class.
<activity android:name=".SettingsActivity">
<intent-filter>
<action android:name="Settings_Action" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>After the pos settings process, the payment application should send the result.
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putInt("ResponseCode",responseCode);
resultIntent.putExtras(bundle);
setResult(Activity.RESULT_OK,resultIntent); //Settings_Request_Code=24
finish();responseCode : Return of the pos settings request.
Batch Close

Following code snippet is used by PaymentGateway in order to open payment application:
Intent sendIntentPosTxn = new Intent();
sendIntentPosTxn.setPackage(packages.get(i));
sendIntentPosTxn.setAction(getResources().getString(R.string.BatchClose_Action)); //BatchClose_Action="BatchClose_Action"
sendIntentPosTxn.setType("text/plain");
startActivityForResult(sendIntentPosTxn, getResources().getInteger(R.integer.BatchClose_Request_Code)); //BatchClose_Request_Code=25Manifest Modifications
To be able to get data from payment gateway, there should be intent filter like below in related class.
<activity android:name=".BatchCloseActivity">
<intent-filter>
<action android:name="BatchClose_Action" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>After the batch close process, the payment application should send the result.
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putInt("ResponseCode",responseCode);
resultIntent.putExtras(bundle);
setResult(Activity.RESULT_OK,resultIntent); //BatchClose_Request_Code=25
finish();responseCode : Return of the pos settings request.
Parameter
Following code snippet is used by PaymentGateway in order to open payment application:
Intent sendIntentSettingsTxn = new Intent();
sendIntentSettingsTxn.setPackage(data.getPackage());
sendIntentSettingsTxn.setAction(getResources().getString(R.string.Parameter_Action)); //Parameter_Action="Parameter_Action"
sendIntentSettingsTxn.setType("text/plain");
startActivityForResult(sendIntentSettingsTxn, getResources().getInteger(R.integer.Parameter_Request_Code)); //Parameter_Request_Code=16Manifest Modifications
To be able to get data from payment gateway, there should be intent filter like below in related class.
<activity android:name=".ParameterActivity">
<intent-filter>
<action android:name="Parameter_Action" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>After the parameter update process, the payment application should send the result.
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putInt("ResponseCode",responseCode);
resultIntent.putExtras(bundle);
setResult(Activity.RESULT_OK,resultIntent); //Parameter_Request_Code=16
finish();responseCode : Return of the pos settings request.
Power Cut Inquiry
If there has been a power cut during a sale transaction, transaction is inquired after device reboot. In order to receive inquiry and return transaction information, a broadcast receiver must be registered in the Android manifest file with action "check_sale" like below:
<receiver android:name=".receivers.CheckSaleReceiver">
<intent-filter>
<action android:name="check_sale" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>When inquiry broadcast is received, in the broadcast receiver's onReceive() method, if transaction is successful, transaction info must be returned in a bundle like below.
@Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra("UUID")) {
String uuid = intent.getExtras().getString("UUID");
...
//check if a successful transaction with uuid exists
...
Intent resultIntent = new Intent();
if (transaction != null) {
Bundle bundle = new Bundle();
bundle.putInt("ResponseCode", ResponseCode.SUCCESS.ordinal());
bundle.putInt("Amount", ...);
bundle.putString("customerSlipData", ...);
bundle.putString("merchantSlipData", ...);
bundle.putInt("BatchNo", ...);
bundle.putInt("TxnNo", ...);
bundle.putBoolean("IsSlip", true);
resultIntent.putExtras(bundle);
}
resultIntent.setAction("check_sale_result");
resultIntent.setPackage("com.tokeninc.sardis.paymentgateway");
context.sendBroadcast(resultIntent);
}
}If you are using SQLite database to store transactions, you should configure your database to insert record instantly when a transaction completed in case of a power cut scenario. https://www.sqlite.org/pragma.html#pragma_synchronous
To do this, in your SQLiteOpenHelper class, override onConfigure() method and add the following code:
@Override
public void onConfigure(SQLiteDatabase db) {
db.execSQL("PRAGMA synchronous = 2");
}Following code snippet is used by PaymentGateway in order to check the payment, if there is a power cut PaymentGateway checks for the last sale result then returns UUID to ask for the result of the last sale status.
registerReceiver(receiver, new IntentFilter("check_sale_result"));
Intent intent = new Intent("check_sale");
intent.setPackage(packageName);
intent.putExtra("UUID", uuid);
sendBroadcast(intent);Void / Refund Flow
Void/Refund transaction is started outside of your application. In order for this to work, your app must return Refund Info at the end of a successful sale transaction along with other sale data.
bundle.putInt("BatchNo", ...);
bundle.putInt("TxnNo", ...);
bundle.putInt("Amount2", amount);
...
bundle.putString("RefundInfo", ...);
...RefundInfo is a string which could be in any format that your application could use later in case of a refund. Remember, this info will be used only by regarding application itself.
For your refund activity to be triggered by platform, register your activity with action named "Refund_Action".
<activity android:name=".activity.refund.RefundActivity">
<intent-filter>
<action android:name="Refund_Action" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>In case your refund activity is triggered, the same RefundInfo string you returned with sale data will be delivered to you. In your activity, you could retrieve it this way:
//In this case, RefundInfo is a JSON value, but you could use any format you want.
String refundInfo = getIntent().getStringExtra("RefundInfo");
try {
JSONObject json = new JSONObject(refundInfo);
batchNo = json.getInt("BatchNo");
txnNo = json.getInt("TxnNo");
}
//Customer shouldn't need to enter any input about transaction except card information.
//All the other transaction data should be retrieved in RefundInfo string.
//Do the void/refund transaction and return the result:
Intent resultIntent = new Intent();
Bundle bundle = new Bundle();
bundle.putInt("ResponseCode", responseCode.ordinal());
resultIntent.putExtras(bundle);
setResult(Activity.RESULT_OK, resultIntent);
finish();
// Always return activity result "RESULT_OK" with "ResponseCode".
// On Back Press, return activity result "RESULT_CANCELED", platform will consider as "5002", "CANCELED".
@Override
public void onBackPressed() {
setResult(Activity.RESULT_CANCELED);
super.onBackPressed();
}Remote Activation
To be able to list your application in device, you need to support remote activation system as example given below. Let's say you have an activity to run activation process. For that activity or other ui element, you have to support given intent filter below to run activation process.
<activity android:name=".SettingsActivity" android:launchMode="singleTop">
<intent-filter>
<action android:name="Activate_TTS" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>Inside intent bundle, you'll see parameters for use that are merchantID and terminalID as string. It's up to you to use this parameters as it totally depends your design. This will start your activation process remotely. When activation on your app is complete
setResult(Activity.RESULT_OK, yourIntent);
finish()and yourIntent should contain merchantID and terminalID as string if you're not using parameters coming from device.
If some error occured,
setResult(Activity.RESULT_CANCELED, yourIntent);
finish()and your intent should contain field "message" to understand and log it.
Update Parameters on Active App
If your application on same fiscal id has changeable merchantID and terminalID, you have to support given intent filter below to run activation process. Let's say you have an activity to run activation process. For that activity or other ui element,
<activity android:name=".SettingsActivity" android:launchMode="singleTop">
<intent-filter>
<action android:name="Update_Parameter" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>Inside intent bundle, you'll see parameters for use that are merchantID and terminalID as string. It's up to you to use this parameters as it totally depends your design. This will start your terminalID and merchantID update process remotely. When update on your app is complete
setResult(Activity.RESULT_OK, yourIntent);
finish()and yourIntent should contain merchantID and terminalID as string if you're not using parameters coming from device.
If some error occured,
setResult(Activity.RESULT_CANCELED, yourIntent);
finish()and your intent should contain field "message" to understand and log it.
Manual App Activation
Let's say some operator needs to install your application manually and doesn't have a chance to send remote activation process. For that kind of situations, please use function setBankParams at
Important Note: If you don't implement this function, your application can't be activated and it can't seen in ATMS. Therefore you couldn't see your applications on POS transactions and sale menu! You can read Pos Settings on the Template Banking app for more information.
DeviceInfo deviceInfo = new DeviceInfo(context);
deviceInfo.setAppParams(
object : DeviceInfoAppParamsSetterHandler {
override fun onReturn(result: Boolean) {
Log.i("RESULT", result.toString())
}
},
"TERMINAL_ID", "MERCHANT_ID",
)Our UIComponents library provides components such as ListMenuFragment, InfoDialog, InputListFragment and NumPadDialog which are explained here.
Last updated