fixed ecr connectivity and functionalities
This commit is contained in:
parent
048f802c18
commit
80a8c2b148
@ -102,11 +102,6 @@
|
|||||||
|
|
||||||
|
|
||||||
</service>
|
</service>
|
||||||
|
|
||||||
<service
|
|
||||||
android:name="com.utsmm.kbz.service.SerialPortService"
|
|
||||||
android:foregroundServiceType="connectedDevice"
|
|
||||||
android:exported="false" />
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
@ -40,10 +40,6 @@ import com.nexgo.oaf.apiv3.APIProxy;
|
|||||||
import com.nexgo.oaf.apiv3.DeviceEngine;
|
import com.nexgo.oaf.apiv3.DeviceEngine;
|
||||||
import com.nexgo.oaf.apiv3.device.pinpad.PinPad;
|
import com.nexgo.oaf.apiv3.device.pinpad.PinPad;
|
||||||
import com.nexgo.oaf.apiv3.device.pinpad.WorkKeyTypeEnum;
|
import com.nexgo.oaf.apiv3.device.pinpad.WorkKeyTypeEnum;
|
||||||
import com.nexgo.oaf.apiv3.device.serialport.SerialPortDriver;
|
|
||||||
import com.nexgo.oaf.apiv3.device.usbserial.OnUsbSerialReadListener;
|
|
||||||
import com.nexgo.oaf.apiv3.device.usbserial.UsbSerial;
|
|
||||||
import com.nexgo.oaf.apiv3.device.usbserial.UsbSerialCfgEntity;
|
|
||||||
import com.utsmyanmar.baselib.BaseApplication;
|
import com.utsmyanmar.baselib.BaseApplication;
|
||||||
import com.utsmyanmar.baselib.repo.Repository;
|
import com.utsmyanmar.baselib.repo.Repository;
|
||||||
import com.utsmyanmar.baselib.ui.AnimationDialog;
|
import com.utsmyanmar.baselib.ui.AnimationDialog;
|
||||||
@ -561,8 +557,8 @@ public class MainActivity extends AppCompatActivity implements
|
|||||||
// Clean up RxJava disposables
|
// Clean up RxJava disposables
|
||||||
compositeDisposable.clear();
|
compositeDisposable.clear();
|
||||||
// Reset screen mode
|
// Reset screen mode
|
||||||
// Disconnect ECR
|
// Disconnect serial port
|
||||||
ECRHelper.INSTANCE.disconnect();
|
ECRHelper.INSTANCE.releaseSerialPort();
|
||||||
BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
|
BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,7 @@
|
|||||||
package com.utsmm.kbz;
|
package com.utsmm.kbz;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.Context;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.content.IntentFilter;
|
|
||||||
import android.content.pm.PackageInfo;
|
|
||||||
import android.content.pm.PackageManager;
|
|
||||||
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
|
||||||
import android.os.RemoteException;
|
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -38,16 +29,9 @@ import com.kizzy.cmhl.models.SaleRequest;
|
|||||||
import com.kizzy.cmhl.models.SettlementRequest;
|
import com.kizzy.cmhl.models.SettlementRequest;
|
||||||
import com.kizzy.cmhl.models.VoidQrPaymentRequest;
|
import com.kizzy.cmhl.models.VoidQrPaymentRequest;
|
||||||
import com.kizzy.cmhl.models.VoidRequest;
|
import com.kizzy.cmhl.models.VoidRequest;
|
||||||
import com.nexgo.oaf.apiv3.APIProxy;
|
|
||||||
import com.nexgo.oaf.apiv3.DeviceEngine;
|
|
||||||
import com.nexgo.oaf.apiv3.SdkResult;
|
|
||||||
import com.nexgo.oaf.apiv3.device.serialport.SerialCfgEntity;
|
|
||||||
import com.nexgo.oaf.apiv3.device.serialport.SerialPortDriver;
|
|
||||||
import com.nexgo.oaf.apiv3.emv.AidEntity;
|
import com.nexgo.oaf.apiv3.emv.AidEntity;
|
||||||
import com.nexgo.oaf.apiv3.emv.CapkEntity;
|
import com.nexgo.oaf.apiv3.emv.CapkEntity;
|
||||||
//import com.pos.connection.bridge.binder.ECRConstant;
|
|
||||||
|
|
||||||
import com.utsmm.kbz.service.SerialPortService;
|
|
||||||
import com.utsmm.kbz.util.MockData;
|
import com.utsmm.kbz.util.MockData;
|
||||||
//import com.utsmm.kbz.util.ecr.ModernECRFactory;
|
//import com.utsmm.kbz.util.ecr.ModernECRFactory;
|
||||||
//import com.utsmm.kbz.util.ecr.ModernECRManager;
|
//import com.utsmm.kbz.util.ecr.ModernECRManager;
|
||||||
@ -59,6 +43,7 @@ import com.utsmyanmar.baselib.util.DataBindingConfig;
|
|||||||
import com.utsmyanmar.baselib.util.DialogCallback;
|
import com.utsmyanmar.baselib.util.DialogCallback;
|
||||||
import com.utsmyanmar.baselib.util.TerminalUtil;
|
import com.utsmyanmar.baselib.util.TerminalUtil;
|
||||||
import com.utsmyanmar.checkxread.sdk.NexGoSDK;
|
import com.utsmyanmar.checkxread.sdk.NexGoSDK;
|
||||||
|
import com.utsmyanmar.ecr.ECRHelper;
|
||||||
import com.utsmyanmar.ecr.ECRProcess;
|
import com.utsmyanmar.ecr.ECRProcess;
|
||||||
import com.utsmyanmar.ecr.data.ResultOf;
|
import com.utsmyanmar.ecr.data.ResultOf;
|
||||||
import com.utsmyanmar.ecr.data.model.Transactions;
|
import com.utsmyanmar.ecr.data.model.Transactions;
|
||||||
@ -68,7 +53,6 @@ import com.utsmyanmar.paylibs.model.TradeData;
|
|||||||
import com.utsmyanmar.paylibs.print.PrintHelper;
|
import com.utsmyanmar.paylibs.print.PrintHelper;
|
||||||
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
|
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
|
||||||
import com.utsmyanmar.paylibs.utils.POSUtil;
|
import com.utsmyanmar.paylibs.utils.POSUtil;
|
||||||
import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil;
|
|
||||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
|
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
|
||||||
import com.utsmyanmar.paylibs.utils.enums.CurrencyType;
|
import com.utsmyanmar.paylibs.utils.enums.CurrencyType;
|
||||||
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
|
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
|
||||||
@ -110,7 +94,6 @@ import com.utsmyanmar.paylibs.utils.params.Params;
|
|||||||
//import com.utsmm.kbz.util.ecr.ModernECRFactory;
|
//import com.utsmm.kbz.util.ecr.ModernECRFactory;
|
||||||
//import com.utsmm.kbz.util.ecr.ModernECRManager;
|
//import com.utsmm.kbz.util.ecr.ModernECRManager;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
public class MainFragment extends DataBindingFragment {
|
public class MainFragment extends DataBindingFragment {
|
||||||
@ -150,38 +133,43 @@ public class MainFragment extends DataBindingFragment {
|
|||||||
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
|
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
|
||||||
tmsProcessViewModel = getFragmentScopeViewModel(TMSProcessViewModel.class);
|
tmsProcessViewModel = getFragmentScopeViewModel(TMSProcessViewModel.class);
|
||||||
|
|
||||||
// Initialize ModernECRManager
|
|
||||||
// ModernECRFactory factory = new ModernECRFactory(requireContext(), sharedViewModel);
|
|
||||||
// modernECRManager = new ViewModelProvider(this, factory).get(ModernECRManager.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStart() {
|
public void onStart() {
|
||||||
super.onStart();
|
super.onStart();
|
||||||
// Register to listen for serial data
|
|
||||||
|
|
||||||
// Setup ECR Service
|
if (SystemParamsOperation.getInstance().getECRStatus()) {
|
||||||
if(SystemParamsOperation.getInstance().getECRStatus()){
|
ECRHelper.INSTANCE.setOnECRReceive(bytes -> {
|
||||||
LocalBroadcastManager.getInstance(requireContext())
|
if (getActivity() == null) {
|
||||||
.registerReceiver(serialReceiver,
|
return null;
|
||||||
new IntentFilter(SerialPortService.ACTION_DATA_RECEIVED));
|
|
||||||
|
|
||||||
// Start the service
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
requireContext().startForegroundService(
|
|
||||||
new Intent(requireContext(), SerialPortService.class));
|
|
||||||
}
|
}
|
||||||
|
requireActivity().runOnUiThread(() -> handleSerialData(bytes));
|
||||||
LogUtil.d(TAG,"ECR service initialized!");
|
return null;
|
||||||
|
});
|
||||||
|
ECRHelper.INSTANCE.initSerialPort(requireContext().getApplicationContext());
|
||||||
|
LogUtil.d(TAG, "ECR SerialPortDriver listening");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStop() {
|
public void onStop() {
|
||||||
super.onStop();
|
super.onStop();
|
||||||
LocalBroadcastManager.getInstance(requireContext())
|
ECRHelper.INSTANCE.setOnECRReceive(bytes -> null);
|
||||||
.unregisterReceiver(serialReceiver);
|
}
|
||||||
|
|
||||||
|
private void handleSerialData(byte[] data) {
|
||||||
|
if (data == null || data.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LogUtil.d(TAG, "Serial received len=" + data.length);
|
||||||
|
|
||||||
|
if (SystemParamsOperation.getInstance().isCMHLEnabled()) {
|
||||||
|
ECRActionCHML(data);
|
||||||
|
} else {
|
||||||
|
ECRAction(new String(data, StandardCharsets.UTF_8));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -244,33 +232,6 @@ public class MainFragment extends DataBindingFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private BroadcastReceiver serialReceiver = new BroadcastReceiver() {
|
|
||||||
@Override
|
|
||||||
public void onReceive(Context context, Intent intent) {
|
|
||||||
String data = intent.getStringExtra(SerialPortService.EXTRA_DATA);
|
|
||||||
LogUtil.d("USB", "UI received: " + data);
|
|
||||||
// update your UI here
|
|
||||||
|
|
||||||
// LogUtil.d(TAG, "Received : " + msg);
|
|
||||||
|
|
||||||
|
|
||||||
if (sharedViewModel.isEcrFinished.getValue() != null && sharedViewModel.isEcrFinished.getValue()) {
|
|
||||||
if(SystemParamsOperation.getInstance().isCMHLEnabled()) {
|
|
||||||
ECRActionCHML(ByteUtil.hexStr2Bytes(data));
|
|
||||||
} else {
|
|
||||||
ECRAction(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if(SystemParamsOperation.getInstance().isCMHLEnabled()) {
|
|
||||||
ECRActionCHML(ByteUtil.hexStr2Bytes(data));
|
|
||||||
} else {
|
|
||||||
ECRAction(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
@ -314,9 +275,6 @@ public class MainFragment extends DataBindingFragment {
|
|||||||
// enableHomeButton();
|
// enableHomeButton();
|
||||||
}
|
}
|
||||||
|
|
||||||
private SerialPortDriver port;
|
|
||||||
private boolean isRunning = false;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||||
super.onViewCreated(view, savedInstanceState);
|
super.onViewCreated(view, savedInstanceState);
|
||||||
@ -412,19 +370,6 @@ public class MainFragment extends DataBindingFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private boolean checkECRServiceAppExistOrNot() {
|
|
||||||
PackageInfo packageInfo;
|
|
||||||
try {
|
|
||||||
packageInfo = requireActivity().getPackageManager().getPackageInfo("com.kizzy.ecrservice", 0);
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return packageInfo != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DataBindingConfig getDataBindingConfig() {
|
protected DataBindingConfig getDataBindingConfig() {
|
||||||
|
|
||||||
|
|||||||
@ -1,112 +0,0 @@
|
|||||||
package com.utsmm.kbz.service;
|
|
||||||
|
|
||||||
import android.app.Notification;
|
|
||||||
import android.app.NotificationChannel;
|
|
||||||
import android.app.NotificationManager;
|
|
||||||
import android.app.Service;
|
|
||||||
import android.content.Intent;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.os.IBinder;
|
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
|
||||||
|
|
||||||
import com.nexgo.oaf.apiv3.APIProxy;
|
|
||||||
import com.nexgo.oaf.apiv3.DeviceEngine;
|
|
||||||
import com.nexgo.oaf.apiv3.SdkResult;
|
|
||||||
import com.nexgo.oaf.apiv3.device.serialport.SerialCfgEntity;
|
|
||||||
import com.nexgo.oaf.apiv3.device.serialport.SerialPortDriver;
|
|
||||||
import com.utsmm.kbz.R;
|
|
||||||
import com.utsmyanmar.paylibs.utils.LogUtil;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public class SerialPortService extends Service {
|
|
||||||
|
|
||||||
private static final String TAG = "USB";
|
|
||||||
private SerialPortDriver port;
|
|
||||||
private volatile boolean isRunning = false;
|
|
||||||
private Thread receiveThread;
|
|
||||||
|
|
||||||
// Broadcast action so any Activity/Fragment can observe
|
|
||||||
public static final String ACTION_DATA_RECEIVED = "com.yourapp.SERIAL_DATA";
|
|
||||||
public static final String EXTRA_DATA = "data";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
|
||||||
startForegroundNotification(); // required for foreground service
|
|
||||||
connectAndListen();
|
|
||||||
return START_STICKY; // restarts if killed
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectAndListen() {
|
|
||||||
DeviceEngine deviceEngine = APIProxy.getDeviceEngine(this);
|
|
||||||
port = deviceEngine.getSerialPortDriver(0);
|
|
||||||
|
|
||||||
SerialCfgEntity entity = new SerialCfgEntity();
|
|
||||||
entity.setBaudRate(115200);
|
|
||||||
entity.setDataBits(8);
|
|
||||||
entity.setParity('n');
|
|
||||||
entity.setStopBits(1);
|
|
||||||
|
|
||||||
int result = port.connect(entity);
|
|
||||||
|
|
||||||
if (result == SdkResult.Success) {
|
|
||||||
LogUtil.d(TAG, "Connected");
|
|
||||||
isRunning = true;
|
|
||||||
startReceiveThread();
|
|
||||||
} else {
|
|
||||||
LogUtil.e(TAG, "Connection failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startReceiveThread() {
|
|
||||||
receiveThread = new Thread(() -> {
|
|
||||||
byte[] buffer = new byte[2048];
|
|
||||||
while (isRunning) {
|
|
||||||
int len = port.recv(buffer, buffer.length, 3000);
|
|
||||||
if (len > 0) {
|
|
||||||
String msg = new String(buffer, 0, len, StandardCharsets.UTF_8);
|
|
||||||
LogUtil.d(TAG, "Received: " + msg);
|
|
||||||
broadcastData(msg); // notify UI
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
receiveThread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void broadcastData(String msg) {
|
|
||||||
Intent intent = new Intent(ACTION_DATA_RECEIVED);
|
|
||||||
intent.putExtra(EXTRA_DATA, msg);
|
|
||||||
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onDestroy() {
|
|
||||||
isRunning = false;
|
|
||||||
if (port != null) port.disconnect();
|
|
||||||
super.onDestroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startForegroundNotification() {
|
|
||||||
NotificationChannel channel = null;
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
channel = new NotificationChannel(
|
|
||||||
"serial_channel", "Serial Port", NotificationManager.IMPORTANCE_LOW);
|
|
||||||
|
|
||||||
getSystemService(NotificationManager.class).createNotificationChannel(channel);
|
|
||||||
|
|
||||||
Notification notification = new Notification.Builder(this, "serial_channel")
|
|
||||||
.setContentTitle("Serial Port Active")
|
|
||||||
.setSmallIcon(R.drawable.ic_launcher_foreground)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
startForeground(1, notification);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
@Override
|
|
||||||
public IBinder onBind(Intent intent) { return null; }
|
|
||||||
}
|
|
||||||
@ -606,9 +606,9 @@ public class TMSSetupsImpl implements TMSSetups{
|
|||||||
} else if (TextUtils.equals(name, "upi_tc_enabled")) {
|
} else if (TextUtils.equals(name, "upi_tc_enabled")) {
|
||||||
SystemParamsOperation.getInstance().setUpiTCEnabled(parseBoolean(data));
|
SystemParamsOperation.getInstance().setUpiTCEnabled(parseBoolean(data));
|
||||||
} else if (TextUtils.equals(name,"master_terminal_capability")) {
|
} else if (TextUtils.equals(name,"master_terminal_capability")) {
|
||||||
if(!data.isEmpty()) {
|
// if(!data.isEmpty()) {
|
||||||
emvParamOperation.updatePayPassTerminalCapability(data);
|
// emvParamOperation.updatePayPassTerminalCapability(data);
|
||||||
}
|
// }
|
||||||
} else if (TextUtils.equals(name,"speedup_contactless_enable")) {
|
} else if (TextUtils.equals(name,"speedup_contactless_enable")) {
|
||||||
SystemParamsOperation.getInstance().setSpeedUpContactless(parseBoolean(data));
|
SystemParamsOperation.getInstance().setSpeedUpContactless(parseBoolean(data));
|
||||||
} else if (TextUtils.equals(name,"manual_entry_pin_enable")) {
|
} else if (TextUtils.equals(name,"manual_entry_pin_enable")) {
|
||||||
|
|||||||
1
cmhl/.gitignore
vendored
Normal file
1
cmhl/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
||||||
35
cmhl/build.gradle
Normal file
35
cmhl/build.gradle
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
plugins {
|
||||||
|
id 'com.android.library'
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace 'com.kizzy.cmhl'
|
||||||
|
compileSdk 34
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk 23 // Lowered to 23 for broader device compatibility
|
||||||
|
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
consumerProguardFiles "consumer-rules.pro"
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_11
|
||||||
|
targetCompatibility JavaVersion.VERSION_11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
|
||||||
|
implementation 'androidx.appcompat:appcompat:1.7.1'
|
||||||
|
implementation 'com.google.android.material:material:1.13.0'
|
||||||
|
testImplementation 'junit:junit:4.13.2'
|
||||||
|
androidTestImplementation 'androidx.test.ext:junit:1.3.0'
|
||||||
|
androidTestImplementation 'androidx.test.espresso:espresso-core:3.7.0'
|
||||||
|
}
|
||||||
0
cmhl/consumer-rules.pro
Normal file
0
cmhl/consumer-rules.pro
Normal file
21
cmhl/proguard-rules.pro
vendored
Normal file
21
cmhl/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
package com.kizzy.cmhl;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ExampleInstrumentedTest {
|
||||||
|
@Test
|
||||||
|
public void useAppContext() {
|
||||||
|
// Context of the app under test.
|
||||||
|
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
assertEquals("com.kizzy.cmhl.test", appContext.getPackageName());
|
||||||
|
}
|
||||||
|
}
|
||||||
4
cmhl/src/main/AndroidManifest.xml
Normal file
4
cmhl/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</manifest>
|
||||||
148
cmhl/src/main/java/com/kizzy/cmhl/EcrManager.java
Normal file
148
cmhl/src/main/java/com/kizzy/cmhl/EcrManager.java
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
package com.kizzy.cmhl;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.models.EcrCommand;
|
||||||
|
import com.kizzy.cmhl.models.EcrPacket;
|
||||||
|
import com.kizzy.cmhl.utils.ByteUtils;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class EcrManager {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds the full packet bytes from an EcrCommand (Request or Response).
|
||||||
|
* Structure: STX LLL(2) VERSION COMMAND DATA... ETX LRC
|
||||||
|
* LLL is BCD encoded length of (VERSION + COMMAND + DATA).
|
||||||
|
* LRC = XOR of (LLL + VERSION + DATA + ETX).
|
||||||
|
*/
|
||||||
|
public static byte[] buildPacket(EcrCommand command) {
|
||||||
|
byte[] tlvData = command.toTlvBytes();
|
||||||
|
|
||||||
|
int bodyLength = 1 + 1 + tlvData.length;
|
||||||
|
|
||||||
|
byte[] lll = ByteUtils.intToBcd(bodyLength);
|
||||||
|
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(1 + 2 + bodyLength + 1 + 1);
|
||||||
|
|
||||||
|
buffer.put(EcrProtocol.STX);
|
||||||
|
buffer.put(lll);
|
||||||
|
buffer.put(EcrProtocol.VERSION);
|
||||||
|
buffer.put(command.getCommandCode());
|
||||||
|
buffer.put(tlvData);
|
||||||
|
buffer.put(EcrProtocol.ETX);
|
||||||
|
|
||||||
|
byte[] packet = buffer.array();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
byte lrc = 0;
|
||||||
|
int etxIndex = packet.length - 2;
|
||||||
|
|
||||||
|
for (int i = 1; i < etxIndex; i++) { // added <= instead of <
|
||||||
|
lrc ^= packet[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
packet[packet.length - 1] = lrc;
|
||||||
|
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static byte[] buildPacket(EcrCommand command) {
|
||||||
|
// byte[] tlvData = command.toTlvBytes();
|
||||||
|
// int bodyLength = 1 + 1 + tlvData.length; // Version(1) + Command(1) + Data
|
||||||
|
//
|
||||||
|
// // Convert bodyLength to BCD
|
||||||
|
// byte[] lll = ByteUtils.intToBcd(bodyLength);
|
||||||
|
//
|
||||||
|
// ByteBuffer buffer = ByteBuffer.allocate(1 + 2 + bodyLength + 1 + 1);
|
||||||
|
//
|
||||||
|
// buffer.put(EcrProtocol.STX);
|
||||||
|
// buffer.put(lll);
|
||||||
|
// buffer.put(EcrProtocol.VERSION);
|
||||||
|
// buffer.put(command.getCommandCode());
|
||||||
|
// buffer.put(tlvData);
|
||||||
|
// buffer.put(EcrProtocol.ETX);
|
||||||
|
//
|
||||||
|
// byte[] packet = buffer.array();
|
||||||
|
//
|
||||||
|
// // Calculate LRC
|
||||||
|
// // From LLL (index 1) to ETX (index packet.length - 2), inclusive
|
||||||
|
// byte lrc = 0;
|
||||||
|
// for (int i = 1; i < packet.length - 1; i++) {
|
||||||
|
// lrc ^= packet[i];
|
||||||
|
// }
|
||||||
|
// packet[packet.length - 1] = lrc;
|
||||||
|
//
|
||||||
|
// return packet;
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses raw bytes into an EcrPacket.
|
||||||
|
* Validates STX and LRC.
|
||||||
|
*/
|
||||||
|
public static EcrPacket parsePacket(byte[] packet) throws Exception {
|
||||||
|
if (packet == null || packet.length < 5) {
|
||||||
|
throw new Exception("Invalid packet length");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet[0] != EcrProtocol.STX) {
|
||||||
|
throw new Exception("Invalid STX");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte receivedLrc = packet[packet.length - 1];
|
||||||
|
byte calculatedLrc = 0;
|
||||||
|
for (int i = 1; i < packet.length - 1; i++) {
|
||||||
|
if (i == 4) continue;
|
||||||
|
calculatedLrc ^= packet[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receivedLrc != calculatedLrc) {
|
||||||
|
System.out.println("LRC Mismatch: Recv=" + receivedLrc + " Calc=" + calculatedLrc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int lll = bcdToInt(packet[1], packet[2]);
|
||||||
|
|
||||||
|
byte commandCode = packet[4];
|
||||||
|
|
||||||
|
int dataEnd = packet.length - 2;
|
||||||
|
byte[] data = new byte[dataEnd - 5];
|
||||||
|
System.arraycopy(packet, 5, data, 0, data.length);
|
||||||
|
|
||||||
|
Map<Byte, byte[]> tlvMap = parseTlv(data);
|
||||||
|
|
||||||
|
return new EcrPacket(commandCode, tlvMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int bcdToInt(byte b1, byte b2) {
|
||||||
|
int thousands = (b1 >> 4) & 0x0F;
|
||||||
|
int hundreds = b1 & 0x0F;
|
||||||
|
int tens = (b2 >> 4) & 0x0F;
|
||||||
|
int ones = b2 & 0x0F;
|
||||||
|
return thousands * 1000 + hundreds * 100 + tens * 10 + ones;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<Byte, byte[]> parseTlv(byte[] data) {
|
||||||
|
Map<Byte, byte[]> map = new HashMap<>();
|
||||||
|
int i = 0;
|
||||||
|
while (i < data.length) {
|
||||||
|
if (i + 1 >= data.length) break;
|
||||||
|
byte tag = data[i++];
|
||||||
|
int len = data[i++] & 0xFF;
|
||||||
|
|
||||||
|
if (i + len > data.length) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] value = new byte[len];
|
||||||
|
System.arraycopy(data, i, value, 0, len);
|
||||||
|
map.put(tag, value);
|
||||||
|
|
||||||
|
i += len;
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
cmhl/src/main/java/com/kizzy/cmhl/EcrProtocol.java
Normal file
40
cmhl/src/main/java/com/kizzy/cmhl/EcrProtocol.java
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
package com.kizzy.cmhl;
|
||||||
|
|
||||||
|
public class EcrProtocol {
|
||||||
|
public static final byte STX = 0x02;
|
||||||
|
public static final byte ETX = 0x03;
|
||||||
|
public static final byte VERSION = 0x01;
|
||||||
|
public static final byte ACK = 0x06;
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
public static final byte CMD_PING = 0x01;
|
||||||
|
public static final byte CMD_SALE = 0x03;
|
||||||
|
public static final byte CMD_VOID = 0x04;
|
||||||
|
public static final byte CMD_SETTLEMENT = 0x05;
|
||||||
|
public static final byte CMD_PRE_AUTH = 0x06;
|
||||||
|
public static final byte CMD_PRE_AUTH_COMPLETION = 0x07;
|
||||||
|
public static final byte CMD_PRE_AUTH_CANCELLATION = 0x08;
|
||||||
|
public static final byte CMD_QR_PAYMENT = 0x0B;
|
||||||
|
public static final byte CMD_VOID_QR_PAYMENT = 0x0C;
|
||||||
|
|
||||||
|
// Tags
|
||||||
|
public static final byte TAG_PAN = 0x02;
|
||||||
|
public static final byte TAG_AMOUNT = 0x04;
|
||||||
|
public static final byte TAG_STAN = 0x11;
|
||||||
|
public static final byte TAG_TIME = 0x12;
|
||||||
|
public static final byte TAG_DATE = 0x13;
|
||||||
|
public static final byte TAG_EXP_DATE = 0x14;
|
||||||
|
public static final byte TAG_CARD_TYPE = 0x15;
|
||||||
|
public static final byte TAG_PAYMENT_TYPE = 0x16;
|
||||||
|
public static final byte TAG_POS_ENTRY = 0x22;
|
||||||
|
public static final byte TAG_RRN = 0x37;
|
||||||
|
public static final byte TAG_APPROVAL_CODE = 0x38;
|
||||||
|
public static final byte TAG_RESPONSE_CODE = 0x39;
|
||||||
|
public static final byte TAG_TID = 0x41;
|
||||||
|
public static final byte TAG_MID = 0x42;
|
||||||
|
public static final byte TAG_CURRENCY_CODE = 0x49;
|
||||||
|
public static final byte TAG_INVOICE_NUMBER = 0x62;
|
||||||
|
|
||||||
|
public static final String CARD_TYPE_ALL = "00"; //
|
||||||
|
|
||||||
|
}
|
||||||
49
cmhl/src/main/java/com/kizzy/cmhl/EcrRequestDispatcher.java
Normal file
49
cmhl/src/main/java/com/kizzy/cmhl/EcrRequestDispatcher.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
package com.kizzy.cmhl;
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.models.EcrPacket;
|
||||||
|
import com.kizzy.cmhl.models.*;
|
||||||
|
|
||||||
|
public class EcrRequestDispatcher {
|
||||||
|
|
||||||
|
public static void dispatch(EcrPacket packet, EcrRequestListener listener) {
|
||||||
|
if (packet == null || listener == null) return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch (packet.getCommandCode()) {
|
||||||
|
case EcrProtocol.CMD_PING:
|
||||||
|
listener.onPingRequest(new PingRequest(packet));
|
||||||
|
break;
|
||||||
|
case EcrProtocol.CMD_SALE:
|
||||||
|
listener.onSaleRequest(new SaleRequest(packet));
|
||||||
|
break;
|
||||||
|
case EcrProtocol.CMD_VOID:
|
||||||
|
listener.onVoidRequest(new VoidRequest(packet));
|
||||||
|
break;
|
||||||
|
case EcrProtocol.CMD_SETTLEMENT:
|
||||||
|
listener.onSettlementRequest(new SettlementRequest(packet));
|
||||||
|
break;
|
||||||
|
case EcrProtocol.CMD_PRE_AUTH:
|
||||||
|
listener.onPreAuthRequest(new PreAuthRequest(packet));
|
||||||
|
break;
|
||||||
|
case EcrProtocol.CMD_PRE_AUTH_COMPLETION:
|
||||||
|
listener.onPreAuthCompletionRequest(new PreAuthCompletionRequest(packet));
|
||||||
|
break;
|
||||||
|
case EcrProtocol.CMD_PRE_AUTH_CANCELLATION:
|
||||||
|
listener.onPreAuthCancellationRequest(new PreAuthCancellationRequest(packet));
|
||||||
|
break;
|
||||||
|
case EcrProtocol.CMD_QR_PAYMENT:
|
||||||
|
listener.onQrPaymentRequest(new QrPaymentRequest(packet));
|
||||||
|
break;
|
||||||
|
case EcrProtocol.CMD_VOID_QR_PAYMENT:
|
||||||
|
listener.onVoidQrPaymentRequest(new VoidQrPaymentRequest(packet));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
listener.onUnknownRequest(packet);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
listener.onUnknownRequest(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
17
cmhl/src/main/java/com/kizzy/cmhl/EcrRequestListener.java
Normal file
17
cmhl/src/main/java/com/kizzy/cmhl/EcrRequestListener.java
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.kizzy.cmhl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.models.*;
|
||||||
|
|
||||||
|
public interface EcrRequestListener {
|
||||||
|
void onPingRequest(PingRequest request);
|
||||||
|
void onSaleRequest(SaleRequest request);
|
||||||
|
void onVoidRequest(VoidRequest request);
|
||||||
|
void onSettlementRequest(SettlementRequest request);
|
||||||
|
void onPreAuthRequest(PreAuthRequest request);
|
||||||
|
void onPreAuthCompletionRequest(PreAuthCompletionRequest request);
|
||||||
|
void onPreAuthCancellationRequest(PreAuthCancellationRequest request);
|
||||||
|
void onQrPaymentRequest(QrPaymentRequest request);
|
||||||
|
void onVoidQrPaymentRequest(VoidQrPaymentRequest request);
|
||||||
|
void onUnknownRequest(EcrPacket packet);
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
import com.kizzy.cmhl.utils.ByteUtils;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public abstract class BaseEcrResponse implements EcrCommand {
|
||||||
|
protected String responseCode;
|
||||||
|
protected String tid;
|
||||||
|
protected String mid;
|
||||||
|
protected String time;
|
||||||
|
protected String date;
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public String getResponseCode() { return responseCode; }
|
||||||
|
public String getTid() { return tid; }
|
||||||
|
public String getMid() { return mid; }
|
||||||
|
public String getTime() { return time; }
|
||||||
|
public String getDate() { return date; }
|
||||||
|
|
||||||
|
public boolean isApproved() {
|
||||||
|
return "00".equals(responseCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeCommonTags(ByteArrayOutputStream baos) throws IOException {
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RESPONSE_CODE, responseCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_TIME, time);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_DATE, date);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_TID, tid);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_MID, mid);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void parseCommonTags(EcrPacket packet) {
|
||||||
|
this.responseCode = packet.getValueAsString(EcrProtocol.TAG_RESPONSE_CODE);
|
||||||
|
this.time = packet.getValueAsString(EcrProtocol.TAG_TIME);
|
||||||
|
this.date = packet.getValueAsString(EcrProtocol.TAG_DATE);
|
||||||
|
this.tid = packet.getValueAsString(EcrProtocol.TAG_TID);
|
||||||
|
this.mid = packet.getValueAsString(EcrProtocol.TAG_MID);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeTag(ByteArrayOutputStream baos, byte tag, String value) throws IOException {
|
||||||
|
if (value != null) {
|
||||||
|
|
||||||
|
byte[] bytes = value.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(tag);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void writeTagBinary(ByteArrayOutputStream baos, byte tag, String hexString) throws IOException {
|
||||||
|
if (hexString != null) {
|
||||||
|
byte[] bytes = ByteUtils.hexStringToByteArray(hexString);
|
||||||
|
baos.write(tag);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
6
cmhl/src/main/java/com/kizzy/cmhl/models/EcrCommand.java
Normal file
6
cmhl/src/main/java/com/kizzy/cmhl/models/EcrCommand.java
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
public interface EcrCommand {
|
||||||
|
byte getCommandCode();
|
||||||
|
byte[] toTlvBytes();
|
||||||
|
}
|
||||||
35
cmhl/src/main/java/com/kizzy/cmhl/models/EcrPacket.java
Normal file
35
cmhl/src/main/java/com/kizzy/cmhl/models/EcrPacket.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a generic parsed ECR packet (Command + TLV Data).
|
||||||
|
* Can be a Request or a Response depending on context.
|
||||||
|
*/
|
||||||
|
public class EcrPacket {
|
||||||
|
private byte commandCode;
|
||||||
|
private Map<Byte, byte[]> tlvData;
|
||||||
|
|
||||||
|
public EcrPacket(byte commandCode, Map<Byte, byte[]> tlvData) {
|
||||||
|
this.commandCode = commandCode;
|
||||||
|
this.tlvData = tlvData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return commandCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Byte, byte[]> getTlvData() {
|
||||||
|
return tlvData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getValue(byte tag) {
|
||||||
|
return tlvData.get(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValueAsString(byte tag) {
|
||||||
|
byte[] val = tlvData.get(tag);
|
||||||
|
if (val == null) return null;
|
||||||
|
return new String(val);
|
||||||
|
}
|
||||||
|
}
|
||||||
26
cmhl/src/main/java/com/kizzy/cmhl/models/PingRequest.java
Normal file
26
cmhl/src/main/java/com/kizzy/cmhl/models/PingRequest.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
|
||||||
|
public class PingRequest implements EcrCommand {
|
||||||
|
|
||||||
|
public PingRequest() {}
|
||||||
|
public PingRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_PING) {
|
||||||
|
throw new IllegalArgumentException("Invalid command for PingRequest");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_PING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
return new byte[0]; // Empty body
|
||||||
|
}
|
||||||
|
}
|
||||||
42
cmhl/src/main/java/com/kizzy/cmhl/models/PingResponse.java
Normal file
42
cmhl/src/main/java/com/kizzy/cmhl/models/PingResponse.java
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PingResponse extends BaseEcrResponse {
|
||||||
|
|
||||||
|
public PingResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_PING) {
|
||||||
|
}
|
||||||
|
parseCommonTags(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PingResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_PING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RESPONSE_CODE, responseCode);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public PingResponse build() { return new PingResponse(this); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,69 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class PreAuthCancellationRequest implements EcrCommand {
|
||||||
|
private String referenceNumber;
|
||||||
|
private String cardType;
|
||||||
|
private String approvalCode;
|
||||||
|
|
||||||
|
public PreAuthCancellationRequest(String referenceNumber, String cardType, String approvalCode) {
|
||||||
|
this.referenceNumber = referenceNumber;
|
||||||
|
this.cardType = cardType;
|
||||||
|
this.approvalCode = approvalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PreAuthCancellationRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_PRE_AUTH_CANCELLATION) {
|
||||||
|
throw new IllegalArgumentException("Invalid command");
|
||||||
|
}
|
||||||
|
this.referenceNumber = packet.getValueAsString(EcrProtocol.TAG_RRN);
|
||||||
|
this.cardType = packet.getValueAsString(EcrProtocol.TAG_CARD_TYPE);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCardType() { return cardType; }
|
||||||
|
public String getReferenceNumber() { return referenceNumber; }
|
||||||
|
|
||||||
|
public String getApprovalCode() { return approvalCode; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_PRE_AUTH_CANCELLATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (referenceNumber != null) {
|
||||||
|
byte[] bytes = referenceNumber.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_RRN);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
if (approvalCode != null) {
|
||||||
|
byte[] bytes = approvalCode.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardType != null) {
|
||||||
|
byte[] bytes = cardType.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_CARD_TYPE);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PreAuthCancellationResponse extends BaseEcrResponse {
|
||||||
|
private String invoiceNumber;
|
||||||
|
private String approvalCode;
|
||||||
|
|
||||||
|
public PreAuthCancellationResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_PRE_AUTH_CANCELLATION) {}
|
||||||
|
parseCommonTags(packet);
|
||||||
|
this.invoiceNumber = packet.getValueAsString(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PreAuthCancellationResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
this.time = builder.time;
|
||||||
|
this.date = builder.date;
|
||||||
|
this.tid = builder.tid;
|
||||||
|
this.mid = builder.mid;
|
||||||
|
this.invoiceNumber = builder.invoiceNumber;
|
||||||
|
this.approvalCode = builder.approvalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInvoiceNumber() { return invoiceNumber; }
|
||||||
|
public String getApprovalCode() { return approvalCode; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_PRE_AUTH_CANCELLATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writeCommonTags(baos);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_INVOICE_NUMBER, invoiceNumber);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_APPROVAL_CODE, approvalCode);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String invoiceNumber;
|
||||||
|
private String approvalCode;
|
||||||
|
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public Builder setTime(String time) { this.time = time; return this; }
|
||||||
|
public Builder setDate(String date) { this.date = date; return this; }
|
||||||
|
public Builder setTid(String tid) { this.tid = tid; return this; }
|
||||||
|
public Builder setMid(String mid) { this.mid = mid; return this; }
|
||||||
|
public Builder setInvoiceNumber(String invoiceNumber) { this.invoiceNumber = invoiceNumber; return this; }
|
||||||
|
public Builder setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; return this; }
|
||||||
|
|
||||||
|
public PreAuthCancellationResponse build() { return new PreAuthCancellationResponse(this); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class PreAuthCompletionRequest implements EcrCommand {
|
||||||
|
private String referenceNumber;
|
||||||
|
private String cardType;
|
||||||
|
private String approvalCode;
|
||||||
|
|
||||||
|
public PreAuthCompletionRequest(String referenceNumber, String cardType, String approvalCode) {
|
||||||
|
this.referenceNumber = referenceNumber;
|
||||||
|
this.cardType = cardType;
|
||||||
|
this.approvalCode = approvalCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PreAuthCompletionRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_PRE_AUTH_COMPLETION) {
|
||||||
|
throw new IllegalArgumentException("Invalid command");
|
||||||
|
}
|
||||||
|
this.referenceNumber = packet.getValueAsString(EcrProtocol.TAG_RRN);
|
||||||
|
this.cardType = packet.getValueAsString(EcrProtocol.TAG_CARD_TYPE);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCardType() { return cardType; }
|
||||||
|
public String getReferenceNumber() { return referenceNumber; }
|
||||||
|
|
||||||
|
public String getApprovalCode() { return approvalCode; }
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_PRE_AUTH_COMPLETION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (referenceNumber != null) {
|
||||||
|
byte[] bytes = referenceNumber.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_RRN);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
if (approvalCode != null) {
|
||||||
|
byte[] bytes = approvalCode.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cardType != null) {
|
||||||
|
byte[] bytes = cardType.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_CARD_TYPE);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,117 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PreAuthCompletionResponse extends BaseEcrResponse {
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String approvalCode;
|
||||||
|
private String rrn;
|
||||||
|
private String invoiceNumber;
|
||||||
|
|
||||||
|
private String entry;
|
||||||
|
|
||||||
|
public PreAuthCompletionResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_PRE_AUTH_COMPLETION) {}
|
||||||
|
parseCommonTags(packet);
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
this.pan = packet.getValueAsString(EcrProtocol.TAG_PAN);
|
||||||
|
this.expDate = packet.getValueAsString(EcrProtocol.TAG_EXP_DATE);
|
||||||
|
this.stan = packet.getValueAsString(EcrProtocol.TAG_STAN);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
this.rrn = packet.getValueAsString(EcrProtocol.TAG_RRN);
|
||||||
|
this.invoiceNumber = packet.getValueAsString(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private PreAuthCompletionResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
this.time = builder.time;
|
||||||
|
this.date = builder.date;
|
||||||
|
this.tid = builder.tid;
|
||||||
|
this.mid = builder.mid;
|
||||||
|
this.amount = builder.amount;
|
||||||
|
this.pan = builder.pan;
|
||||||
|
this.expDate = builder.expDate;
|
||||||
|
this.stan = builder.stan;
|
||||||
|
this.approvalCode = builder.approvalCode;
|
||||||
|
this.rrn = builder.rrn;
|
||||||
|
this.invoiceNumber = builder.invoiceNumber;
|
||||||
|
this.entry = builder.entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
public String getPan() { return pan; }
|
||||||
|
public String getExpDate() { return expDate; }
|
||||||
|
public String getStan() { return stan; }
|
||||||
|
public String getApprovalCode() { return approvalCode; }
|
||||||
|
public String getRrn() { return rrn; }
|
||||||
|
public String getInvoiceNumber() { return invoiceNumber; }
|
||||||
|
|
||||||
|
public String getEntry() { return entry; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_PRE_AUTH_COMPLETION;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writeCommonTags(baos);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_AMOUNT, amount);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_PAN, pan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_EXP_DATE, expDate);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_STAN, stan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_APPROVAL_CODE, approvalCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RRN, rrn);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_INVOICE_NUMBER, invoiceNumber);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_POS_ENTRY, entry);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String approvalCode;
|
||||||
|
private String rrn;
|
||||||
|
private String invoiceNumber;
|
||||||
|
|
||||||
|
private String entry;
|
||||||
|
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public Builder setTime(String time) { this.time = time; return this; }
|
||||||
|
public Builder setDate(String date) { this.date = date; return this; }
|
||||||
|
public Builder setTid(String tid) { this.tid = tid; return this; }
|
||||||
|
public Builder setMid(String mid) { this.mid = mid; return this; }
|
||||||
|
public Builder setAmount(String amount) { this.amount = amount; return this; }
|
||||||
|
public Builder setPan(String pan) { this.pan = pan; return this; }
|
||||||
|
public Builder setExpDate(String expDate) { this.expDate = expDate; return this; }
|
||||||
|
public Builder setStan(String stan) { this.stan = stan; return this; }
|
||||||
|
public Builder setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; return this; }
|
||||||
|
public Builder setRrn(String rrn) { this.rrn = rrn; return this; }
|
||||||
|
public Builder setInvoiceNumber(String invoiceNumber) { this.invoiceNumber = invoiceNumber; return this; }
|
||||||
|
public Builder setEntry(String entry) { this.entry = entry; return this; }
|
||||||
|
|
||||||
|
public PreAuthCompletionResponse build() { return new PreAuthCompletionResponse(this); }
|
||||||
|
}
|
||||||
|
}
|
||||||
57
cmhl/src/main/java/com/kizzy/cmhl/models/PreAuthRequest.java
Normal file
57
cmhl/src/main/java/com/kizzy/cmhl/models/PreAuthRequest.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class PreAuthRequest implements EcrCommand {
|
||||||
|
private String amount;
|
||||||
|
|
||||||
|
public PreAuthRequest(String amount) {
|
||||||
|
this.amount = formatAmount(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PreAuthRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_PRE_AUTH) {
|
||||||
|
throw new IllegalArgumentException("Invalid command");
|
||||||
|
}
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
|
||||||
|
private String formatAmount(String amount) {
|
||||||
|
if (amount == null) return "000000000000";
|
||||||
|
if (amount.length() > 12) return amount.substring(0, 12);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < 12 - amount.length(); i++) {
|
||||||
|
sb.append('0');
|
||||||
|
}
|
||||||
|
sb.append(amount);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_PRE_AUTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
if (amount != null) {
|
||||||
|
byte[] bytes = amount.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_AMOUNT);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
124
cmhl/src/main/java/com/kizzy/cmhl/models/PreAuthResponse.java
Normal file
124
cmhl/src/main/java/com/kizzy/cmhl/models/PreAuthResponse.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class PreAuthResponse extends BaseEcrResponse {
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String approvalCode;
|
||||||
|
private String rrn;
|
||||||
|
private String invoiceNumber;
|
||||||
|
|
||||||
|
private String cardType;
|
||||||
|
private String entry;
|
||||||
|
|
||||||
|
public PreAuthResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_PRE_AUTH) {}
|
||||||
|
parseCommonTags(packet);
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
this.pan = packet.getValueAsString(EcrProtocol.TAG_PAN);
|
||||||
|
this.expDate = packet.getValueAsString(EcrProtocol.TAG_EXP_DATE);
|
||||||
|
this.stan = packet.getValueAsString(EcrProtocol.TAG_STAN);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
this.rrn = packet.getValueAsString(EcrProtocol.TAG_RRN);
|
||||||
|
this.invoiceNumber = packet.getValueAsString(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PreAuthResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
this.time = builder.time;
|
||||||
|
this.date = builder.date;
|
||||||
|
this.tid = builder.tid;
|
||||||
|
this.mid = builder.mid;
|
||||||
|
this.amount = builder.amount;
|
||||||
|
this.pan = builder.pan;
|
||||||
|
this.expDate = builder.expDate;
|
||||||
|
this.stan = builder.stan;
|
||||||
|
this.approvalCode = builder.approvalCode;
|
||||||
|
this.rrn = builder.rrn;
|
||||||
|
this.invoiceNumber = builder.invoiceNumber;
|
||||||
|
this.entry = builder.entry;
|
||||||
|
this.cardType = builder.cardType;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
public String getPan() { return pan; }
|
||||||
|
public String getExpDate() { return expDate; }
|
||||||
|
public String getStan() { return stan; }
|
||||||
|
public String getApprovalCode() { return approvalCode; }
|
||||||
|
public String getRrn() { return rrn; }
|
||||||
|
public String getInvoiceNumber() { return invoiceNumber; }
|
||||||
|
|
||||||
|
public String getEntry() {return entry;}
|
||||||
|
|
||||||
|
public String getCardType() {return cardType;}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_PRE_AUTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writeCommonTags(baos);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_AMOUNT, amount);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_PAN, pan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_EXP_DATE, expDate);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_STAN, stan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_APPROVAL_CODE, approvalCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RRN, rrn);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_INVOICE_NUMBER, invoiceNumber);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_POS_ENTRY, entry);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_CARD_TYPE, cardType);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String approvalCode;
|
||||||
|
private String rrn;
|
||||||
|
private String invoiceNumber;
|
||||||
|
|
||||||
|
private String cardType;
|
||||||
|
private String entry;
|
||||||
|
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public Builder setTime(String time) { this.time = time; return this; }
|
||||||
|
public Builder setDate(String date) { this.date = date; return this; }
|
||||||
|
public Builder setTid(String tid) { this.tid = tid; return this; }
|
||||||
|
public Builder setMid(String mid) { this.mid = mid; return this; }
|
||||||
|
public Builder setAmount(String amount) { this.amount = amount; return this; }
|
||||||
|
public Builder setPan(String pan) { this.pan = pan; return this; }
|
||||||
|
public Builder setExpDate(String expDate) { this.expDate = expDate; return this; }
|
||||||
|
public Builder setStan(String stan) { this.stan = stan; return this; }
|
||||||
|
public Builder setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; return this; }
|
||||||
|
public Builder setRrn(String rrn) { this.rrn = rrn; return this; }
|
||||||
|
public Builder setInvoiceNumber(String invoiceNumber) { this.invoiceNumber = invoiceNumber; return this; }
|
||||||
|
|
||||||
|
public Builder setCardType(String cardType) { this.cardType = cardType; return this; }
|
||||||
|
public Builder setEntry(String entry) { this.entry = entry; return this;}
|
||||||
|
|
||||||
|
public PreAuthResponse build() { return new PreAuthResponse(this); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,74 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class QrPaymentRequest implements EcrCommand {
|
||||||
|
private String amount; // 12 digits
|
||||||
|
private String currencyCode; // 3 digits
|
||||||
|
|
||||||
|
public QrPaymentRequest(String amount, String currencyCode) {
|
||||||
|
this.amount = formatAmount(amount);
|
||||||
|
this.currencyCode = currencyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public QrPaymentRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_QR_PAYMENT) {
|
||||||
|
throw new IllegalArgumentException("Invalid command code for QrPaymentRequest");
|
||||||
|
}
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
this.currencyCode = packet.getValueAsString(EcrProtocol.TAG_CURRENCY_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCurrencyCode() {
|
||||||
|
return currencyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatAmount(String amount) {
|
||||||
|
if (amount == null) return "000000000000";
|
||||||
|
if (amount.length() > 12) return amount.substring(0, 12);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < 12 - amount.length(); i++) {
|
||||||
|
sb.append('0');
|
||||||
|
}
|
||||||
|
sb.append(amount);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_QR_PAYMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
if (amount != null) {
|
||||||
|
byte[] amountBytes = amount.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_AMOUNT);
|
||||||
|
baos.write((byte) amountBytes.length);
|
||||||
|
baos.write(amountBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currencyCode != null) {
|
||||||
|
byte[] currencyBytes = currencyCode.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_CURRENCY_CODE);
|
||||||
|
baos.write((byte) currencyBytes.length);
|
||||||
|
baos.write(currencyBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
155
cmhl/src/main/java/com/kizzy/cmhl/models/QrPaymentResponse.java
Normal file
155
cmhl/src/main/java/com/kizzy/cmhl/models/QrPaymentResponse.java
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class QrPaymentResponse implements EcrCommand {
|
||||||
|
private String responseCode;
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String approvalCode;
|
||||||
|
private String rrn;
|
||||||
|
private String posEntryMode;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String invoiceNumber;
|
||||||
|
private String paymentType;
|
||||||
|
private String currencyCode;
|
||||||
|
|
||||||
|
public QrPaymentResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_QR_PAYMENT) {
|
||||||
|
}
|
||||||
|
this.responseCode = packet.getValueAsString(EcrProtocol.TAG_RESPONSE_CODE);
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
this.pan = packet.getValueAsString(EcrProtocol.TAG_PAN);
|
||||||
|
this.expDate = packet.getValueAsString(EcrProtocol.TAG_EXP_DATE);
|
||||||
|
this.stan = packet.getValueAsString(EcrProtocol.TAG_STAN);
|
||||||
|
this.time = packet.getValueAsString(EcrProtocol.TAG_TIME);
|
||||||
|
this.date = packet.getValueAsString(EcrProtocol.TAG_DATE);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
this.rrn = packet.getValueAsString(EcrProtocol.TAG_RRN);
|
||||||
|
this.posEntryMode = packet.getValueAsString(EcrProtocol.TAG_POS_ENTRY);
|
||||||
|
this.tid = packet.getValueAsString(EcrProtocol.TAG_TID);
|
||||||
|
this.mid = packet.getValueAsString(EcrProtocol.TAG_MID);
|
||||||
|
this.invoiceNumber = packet.getValueAsString(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
this.paymentType = packet.getValueAsString(EcrProtocol.TAG_PAYMENT_TYPE);
|
||||||
|
this.currencyCode = packet.getValueAsString(EcrProtocol.TAG_CURRENCY_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private QrPaymentResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
this.amount = builder.amount;
|
||||||
|
this.pan = builder.pan;
|
||||||
|
this.expDate = builder.expDate;
|
||||||
|
this.stan = builder.stan;
|
||||||
|
this.time = builder.time;
|
||||||
|
this.date = builder.date;
|
||||||
|
this.approvalCode = builder.approvalCode;
|
||||||
|
this.rrn = builder.rrn;
|
||||||
|
this.posEntryMode = builder.posEntryMode;
|
||||||
|
this.tid = builder.tid;
|
||||||
|
this.mid = builder.mid;
|
||||||
|
this.invoiceNumber = builder.invoiceNumber;
|
||||||
|
this.paymentType = builder.paymentType;
|
||||||
|
this.currencyCode = builder.currencyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isApproved() {
|
||||||
|
return "00".equals(responseCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public String getResponseCode() { return responseCode; }
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
public String getPan() { return pan; }
|
||||||
|
public String getInvoiceNumber() { return invoiceNumber; }
|
||||||
|
public String getApprovalCode() { return approvalCode; }
|
||||||
|
public String getRrn() { return rrn; }
|
||||||
|
public String getTid() { return tid; }
|
||||||
|
public String getMid() { return mid; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_QR_PAYMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writeTag(baos, EcrProtocol.TAG_AMOUNT, amount);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RESPONSE_CODE, responseCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_PAN, pan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_EXP_DATE, expDate);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_STAN, stan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_TIME, time);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_DATE, date);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_APPROVAL_CODE, approvalCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RRN, rrn);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_POS_ENTRY, posEntryMode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_TID, tid);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_MID, mid);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_INVOICE_NUMBER, invoiceNumber);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_PAYMENT_TYPE, paymentType);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_CURRENCY_CODE, currencyCode);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeTag(ByteArrayOutputStream baos, byte tag, String value) throws IOException {
|
||||||
|
if (value != null) {
|
||||||
|
byte[] bytes = value.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(tag);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String approvalCode;
|
||||||
|
private String rrn;
|
||||||
|
private String posEntryMode;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String invoiceNumber;
|
||||||
|
private String paymentType;
|
||||||
|
private String currencyCode;
|
||||||
|
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public Builder setAmount(String amount) { this.amount = amount; return this; }
|
||||||
|
public Builder setPan(String pan) { this.pan = pan; return this; }
|
||||||
|
public Builder setExpDate(String expDate) { this.expDate = expDate; return this; }
|
||||||
|
public Builder setStan(String stan) { this.stan = stan; return this; }
|
||||||
|
public Builder setTime(String time) { this.time = time; return this; }
|
||||||
|
public Builder setDate(String date) { this.date = date; return this; }
|
||||||
|
public Builder setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; return this; }
|
||||||
|
public Builder setRrn(String rrn) { this.rrn = rrn; return this; }
|
||||||
|
public Builder setPosEntryMode(String posEntryMode) { this.posEntryMode = posEntryMode; return this; }
|
||||||
|
public Builder setTid(String tid) { this.tid = tid; return this; }
|
||||||
|
public Builder setMid(String mid) { this.mid = mid; return this; }
|
||||||
|
public Builder setInvoiceNumber(String invoiceNumber) { this.invoiceNumber = invoiceNumber; return this; }
|
||||||
|
public Builder setPaymentType(String paymentType) { this.paymentType = paymentType; return this; }
|
||||||
|
public Builder setCurrencyCode(String currencyCode) { this.currencyCode = currencyCode; return this; }
|
||||||
|
|
||||||
|
public QrPaymentResponse build() {
|
||||||
|
return new QrPaymentResponse(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
cmhl/src/main/java/com/kizzy/cmhl/models/SaleRequest.java
Normal file
57
cmhl/src/main/java/com/kizzy/cmhl/models/SaleRequest.java
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class SaleRequest implements EcrCommand {
|
||||||
|
private String amount;
|
||||||
|
|
||||||
|
public SaleRequest(String amount) {
|
||||||
|
this.amount = formatAmount(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SaleRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_SALE) {
|
||||||
|
throw new IllegalArgumentException("Invalid command");
|
||||||
|
}
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
|
||||||
|
private String formatAmount(String amount) {
|
||||||
|
if (amount == null) return "000000000000";
|
||||||
|
if (amount.length() > 12) return amount.substring(0, 12);
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < 12 - amount.length(); i++) {
|
||||||
|
sb.append('0');
|
||||||
|
}
|
||||||
|
sb.append(amount);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_SALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
if (amount != null) {
|
||||||
|
byte[] bytes = amount.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_AMOUNT);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
140
cmhl/src/main/java/com/kizzy/cmhl/models/SaleResponse.java
Normal file
140
cmhl/src/main/java/com/kizzy/cmhl/models/SaleResponse.java
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SaleResponse extends BaseEcrResponse {
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String approvalCode;
|
||||||
|
private String referenceNum;
|
||||||
|
private String invoiceNumber;
|
||||||
|
|
||||||
|
private String entry;
|
||||||
|
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
private String cardType;
|
||||||
|
|
||||||
|
public SaleResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_SALE) {}
|
||||||
|
parseCommonTags(packet);
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
this.pan = packet.getValueAsString(EcrProtocol.TAG_PAN);
|
||||||
|
this.expDate = packet.getValueAsString(EcrProtocol.TAG_EXP_DATE);
|
||||||
|
this.stan = packet.getValueAsString(EcrProtocol.TAG_STAN);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
this.referenceNum = packet.getValueAsString(EcrProtocol.TAG_RRN);
|
||||||
|
this.invoiceNumber = packet.getValueAsString(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SaleResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
this.time = builder.time;
|
||||||
|
this.date = builder.date;
|
||||||
|
this.tid = builder.tid;
|
||||||
|
this.mid = builder.mid;
|
||||||
|
this.amount = builder.amount;
|
||||||
|
this.pan = builder.pan;
|
||||||
|
this.expDate = builder.expDate;
|
||||||
|
this.stan = builder.stan;
|
||||||
|
this.approvalCode = builder.approvalCode;
|
||||||
|
this.referenceNum = builder.referenceNum;
|
||||||
|
this.invoiceNumber = builder.invoiceNumber;
|
||||||
|
this.entry = builder.entry;
|
||||||
|
this.cardType = builder.cardType;
|
||||||
|
this.currency = builder.currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Getters
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
public String getPan() { return pan; }
|
||||||
|
public String getExpDate() { return expDate; }
|
||||||
|
public String getStan() { return stan; }
|
||||||
|
public String getApprovalCode() { return approvalCode; }
|
||||||
|
public String getReferenceNum() { return referenceNum; }
|
||||||
|
public String getInvoiceNumber() { return invoiceNumber; }
|
||||||
|
|
||||||
|
public String getEntry() { return entry; }
|
||||||
|
|
||||||
|
public String getCardType() { return cardType; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_SALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
// writeCommonTags(baos);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_AMOUNT, amount);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RESPONSE_CODE, responseCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_PAN, pan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_EXP_DATE, expDate);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_STAN, stan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_TIME, time);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_DATE, date);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_APPROVAL_CODE, approvalCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RRN, referenceNum);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_POS_ENTRY, entry);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_TID, tid);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_MID, mid);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_INVOICE_NUMBER, invoiceNumber);
|
||||||
|
writeTagBinary(baos, EcrProtocol.TAG_CARD_TYPE, cardType);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_CURRENCY_CODE, currency);
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
|
||||||
|
private String entry;
|
||||||
|
|
||||||
|
private String cardType;
|
||||||
|
private String approvalCode;
|
||||||
|
private String referenceNum;
|
||||||
|
private String invoiceNumber;
|
||||||
|
|
||||||
|
private String currency;
|
||||||
|
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public Builder setTime(String time) { this.time = time; return this; }
|
||||||
|
public Builder setDate(String date) { this.date = date; return this; }
|
||||||
|
public Builder setTid(String tid) { this.tid = tid; return this; }
|
||||||
|
public Builder setMid(String mid) { this.mid = mid; return this; }
|
||||||
|
public Builder setAmount(String amount) { this.amount = amount; return this; }
|
||||||
|
public Builder setPan(String pan) { this.pan = pan; return this; }
|
||||||
|
public Builder setExpDate(String expDate) { this.expDate = expDate; return this; }
|
||||||
|
public Builder setStan(String stan) { this.stan = stan; return this; }
|
||||||
|
public Builder setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; return this; }
|
||||||
|
public Builder setReferenceNum(String rrn) { this.referenceNum = rrn; return this; }
|
||||||
|
|
||||||
|
public Builder setEntry(String entry) { this.entry = entry; return this;}
|
||||||
|
|
||||||
|
public Builder setCardType(String cardType) { this.cardType = cardType; return this;}
|
||||||
|
public Builder setInvoiceNumber(String invoiceNumber) { this.invoiceNumber = invoiceNumber; return this; }
|
||||||
|
|
||||||
|
public Builder setCurrency(String currency) { this.currency = currency; return this; }
|
||||||
|
|
||||||
|
public SaleResponse build() { return new SaleResponse(this); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class SettlementRequest implements EcrCommand {
|
||||||
|
private String cardType;
|
||||||
|
|
||||||
|
public SettlementRequest(String cardType) {
|
||||||
|
this.cardType = cardType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SettlementRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_SETTLEMENT) {
|
||||||
|
throw new IllegalArgumentException("Invalid command");
|
||||||
|
}
|
||||||
|
this.cardType = packet.getValueAsString(EcrProtocol.TAG_CARD_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCardType() { return cardType; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_SETTLEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
if (cardType != null) {
|
||||||
|
byte[] bytes = cardType.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_CARD_TYPE);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SettlementResponse extends BaseEcrResponse {
|
||||||
|
|
||||||
|
public SettlementResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_SETTLEMENT) {}
|
||||||
|
parseCommonTags(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
private SettlementResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
this.time = builder.time;
|
||||||
|
this.date = builder.date;
|
||||||
|
this.tid = builder.tid;
|
||||||
|
this.mid = builder.mid;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_SETTLEMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writeCommonTags(baos);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public Builder setTime(String time) { this.time = time; return this; }
|
||||||
|
public Builder setDate(String date) { this.date = date; return this; }
|
||||||
|
public Builder setTid(String tid) { this.tid = tid; return this; }
|
||||||
|
public Builder setMid(String mid) { this.mid = mid; return this; }
|
||||||
|
|
||||||
|
public SettlementResponse build() { return new SettlementResponse(this); }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class VoidQrPaymentRequest implements EcrCommand {
|
||||||
|
private String invoiceNumber;
|
||||||
|
private String paymentType;
|
||||||
|
|
||||||
|
public VoidQrPaymentRequest(String invoiceNumber, String paymentType) {
|
||||||
|
this.invoiceNumber = invoiceNumber;
|
||||||
|
this.paymentType = paymentType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VoidQrPaymentRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_VOID_QR_PAYMENT) {
|
||||||
|
throw new IllegalArgumentException("Invalid command code for VoidQrPaymentRequest");
|
||||||
|
}
|
||||||
|
this.invoiceNumber = packet.getValueAsString(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
this.paymentType = packet.getValueAsString(EcrProtocol.TAG_PAYMENT_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInvoiceNumber() { return invoiceNumber; }
|
||||||
|
public String getPaymentType() { return paymentType; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_VOID_QR_PAYMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
// Invoice Number
|
||||||
|
if (invoiceNumber != null) {
|
||||||
|
byte[] invoiceBytes = invoiceNumber.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
baos.write((byte) invoiceBytes.length);
|
||||||
|
baos.write(invoiceBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payment Type
|
||||||
|
if (paymentType != null) {
|
||||||
|
byte[] typeBytes = paymentType.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_PAYMENT_TYPE);
|
||||||
|
baos.write((byte) typeBytes.length);
|
||||||
|
baos.write(typeBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class VoidQrPaymentResponse implements EcrCommand {
|
||||||
|
private String responseCode;
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String approvalCode;
|
||||||
|
private String rrn;
|
||||||
|
private String posEntryMode;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String currencyCode;
|
||||||
|
|
||||||
|
|
||||||
|
// Parsing Constructor (ECR Role)
|
||||||
|
public VoidQrPaymentResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_VOID_QR_PAYMENT) {
|
||||||
|
}
|
||||||
|
this.responseCode = packet.getValueAsString(EcrProtocol.TAG_RESPONSE_CODE);
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
this.pan = packet.getValueAsString(EcrProtocol.TAG_PAN);
|
||||||
|
this.expDate = packet.getValueAsString(EcrProtocol.TAG_EXP_DATE);
|
||||||
|
this.stan = packet.getValueAsString(EcrProtocol.TAG_STAN);
|
||||||
|
this.time = packet.getValueAsString(EcrProtocol.TAG_TIME);
|
||||||
|
this.date = packet.getValueAsString(EcrProtocol.TAG_DATE);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
this.rrn = packet.getValueAsString(EcrProtocol.TAG_RRN);
|
||||||
|
this.posEntryMode = packet.getValueAsString(EcrProtocol.TAG_POS_ENTRY);
|
||||||
|
this.tid = packet.getValueAsString(EcrProtocol.TAG_TID);
|
||||||
|
this.mid = packet.getValueAsString(EcrProtocol.TAG_MID);
|
||||||
|
this.currencyCode = packet.getValueAsString(EcrProtocol.TAG_CURRENCY_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Building Constructor (EDC Role)
|
||||||
|
private VoidQrPaymentResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
this.amount = builder.amount;
|
||||||
|
this.pan = builder.pan;
|
||||||
|
this.expDate = builder.expDate;
|
||||||
|
this.stan = builder.stan;
|
||||||
|
this.time = builder.time;
|
||||||
|
this.date = builder.date;
|
||||||
|
this.approvalCode = builder.approvalCode;
|
||||||
|
this.rrn = builder.rrn;
|
||||||
|
this.posEntryMode = builder.posEntryMode;
|
||||||
|
this.tid = builder.tid;
|
||||||
|
this.mid = builder.mid;
|
||||||
|
this.currencyCode = builder.currencyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isApproved() {
|
||||||
|
return "00".equals(responseCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getResponseCode() { return responseCode; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_VOID_QR_PAYMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RESPONSE_CODE, responseCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_AMOUNT, amount);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_PAN, pan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_EXP_DATE, expDate);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_STAN, stan);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_TIME, time);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_DATE, date);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_APPROVAL_CODE, approvalCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RRN, rrn);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_POS_ENTRY, posEntryMode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_TID, tid);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_MID, mid);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_CURRENCY_CODE, currencyCode);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeTag(ByteArrayOutputStream baos, byte tag, String value) throws IOException {
|
||||||
|
if (value != null) {
|
||||||
|
byte[] bytes = value.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(tag);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
private String amount;
|
||||||
|
private String pan;
|
||||||
|
private String expDate;
|
||||||
|
private String stan;
|
||||||
|
private String time;
|
||||||
|
private String date;
|
||||||
|
private String approvalCode;
|
||||||
|
private String rrn;
|
||||||
|
private String posEntryMode;
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String currencyCode;
|
||||||
|
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public Builder setAmount(String amount) { this.amount = amount; return this; }
|
||||||
|
public Builder setPan(String pan) { this.pan = pan; return this; }
|
||||||
|
public Builder setExpDate(String expDate) { this.expDate = expDate; return this; }
|
||||||
|
public Builder setStan(String stan) { this.stan = stan; return this; }
|
||||||
|
public Builder setTime(String time) { this.time = time; return this; }
|
||||||
|
public Builder setDate(String date) { this.date = date; return this; }
|
||||||
|
public Builder setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; return this; }
|
||||||
|
public Builder setRrn(String rrn) { this.rrn = rrn; return this; }
|
||||||
|
public Builder setPosEntryMode(String posEntryMode) { this.posEntryMode = posEntryMode; return this; }
|
||||||
|
public Builder setTid(String tid) { this.tid = tid; return this; }
|
||||||
|
public Builder setMid(String mid) { this.mid = mid; return this; }
|
||||||
|
public Builder setCurrencyCode(String currencyCode) { this.currencyCode = currencyCode; return this; }
|
||||||
|
|
||||||
|
public VoidQrPaymentResponse build() {
|
||||||
|
return new VoidQrPaymentResponse(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
cmhl/src/main/java/com/kizzy/cmhl/models/VoidRequest.java
Normal file
46
cmhl/src/main/java/com/kizzy/cmhl/models/VoidRequest.java
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
|
public class VoidRequest implements EcrCommand {
|
||||||
|
private String invoiceNumber;
|
||||||
|
|
||||||
|
public VoidRequest(String invoiceNumber) {
|
||||||
|
this.invoiceNumber = invoiceNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
public VoidRequest(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_VOID) {
|
||||||
|
throw new IllegalArgumentException("Invalid command");
|
||||||
|
}
|
||||||
|
this.invoiceNumber = packet.getValueAsString(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getInvoiceNumber() { return invoiceNumber; }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
if (invoiceNumber != null) {
|
||||||
|
byte[] bytes = invoiceNumber.getBytes(StandardCharsets.US_ASCII);
|
||||||
|
baos.write(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
baos.write((byte) bytes.length);
|
||||||
|
baos.write(bytes);
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
93
cmhl/src/main/java/com/kizzy/cmhl/models/VoidResponse.java
Normal file
93
cmhl/src/main/java/com/kizzy/cmhl/models/VoidResponse.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
package com.kizzy.cmhl.models;
|
||||||
|
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.EcrProtocol;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class VoidResponse extends BaseEcrResponse {
|
||||||
|
private String amount;
|
||||||
|
private String voucherNumber;
|
||||||
|
private String approvalCode;
|
||||||
|
private String referenceNum;
|
||||||
|
|
||||||
|
private String entry;
|
||||||
|
|
||||||
|
public VoidResponse(EcrPacket packet) {
|
||||||
|
if (packet.getCommandCode() != EcrProtocol.CMD_VOID) {}
|
||||||
|
parseCommonTags(packet);
|
||||||
|
this.amount = packet.getValueAsString(EcrProtocol.TAG_AMOUNT);
|
||||||
|
this.voucherNumber = packet.getValueAsString(EcrProtocol.TAG_INVOICE_NUMBER);
|
||||||
|
this.approvalCode = packet.getValueAsString(EcrProtocol.TAG_APPROVAL_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private VoidResponse(Builder builder) {
|
||||||
|
this.responseCode = builder.responseCode;
|
||||||
|
this.time = builder.time;
|
||||||
|
this.date = builder.date;
|
||||||
|
this.tid = builder.tid;
|
||||||
|
this.mid = builder.mid;
|
||||||
|
this.amount = builder.amount;
|
||||||
|
this.voucherNumber = builder.voucherNum;
|
||||||
|
this.approvalCode = builder.approvalCode;
|
||||||
|
this.referenceNum = builder.referenceNum;
|
||||||
|
this.entry = builder.entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAmount() { return amount; }
|
||||||
|
public String getVoucherNumber() { return voucherNumber; }
|
||||||
|
public String getApprovalCode() { return approvalCode; }
|
||||||
|
|
||||||
|
public String getReferenceNum() { return referenceNum;}
|
||||||
|
|
||||||
|
public String getEntry() {return entry;}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte getCommandCode() {
|
||||||
|
return EcrProtocol.CMD_VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] toTlvBytes() {
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
try {
|
||||||
|
writeCommonTags(baos);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_AMOUNT, amount);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_STAN, voucherNumber);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_APPROVAL_CODE, approvalCode);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_RRN,referenceNum);
|
||||||
|
writeTag(baos, EcrProtocol.TAG_POS_ENTRY,entry);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return baos.toByteArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private String responseCode;
|
||||||
|
private String time; // len 6
|
||||||
|
private String date; // len 4
|
||||||
|
private String tid;
|
||||||
|
private String mid;
|
||||||
|
private String amount;
|
||||||
|
private String voucherNum;
|
||||||
|
private String approvalCode;
|
||||||
|
private String referenceNum;
|
||||||
|
|
||||||
|
private String entry;
|
||||||
|
|
||||||
|
public Builder setResponseCode(String responseCode) { this.responseCode = responseCode; return this; }
|
||||||
|
public Builder setTime(String time) { this.time = time; return this; }
|
||||||
|
public Builder setDate(String date) { this.date = date; return this; }
|
||||||
|
public Builder setTid(String tid) { this.tid = tid; return this; }
|
||||||
|
public Builder setMid(String mid) { this.mid = mid; return this; }
|
||||||
|
public Builder setAmount(String amount) { this.amount = amount; return this; }
|
||||||
|
public Builder setVoucherNumber(String voucherNum) { this.voucherNum = voucherNum; return this; }
|
||||||
|
public Builder setApprovalCode(String approvalCode) { this.approvalCode = approvalCode; return this; }
|
||||||
|
public Builder setReferenceNum(String referenceNum) { this.referenceNum = referenceNum; return this; }
|
||||||
|
public Builder setEntry(String entry) { this.entry = entry; return this; }
|
||||||
|
|
||||||
|
public VoidResponse build() { return new VoidResponse(this); }
|
||||||
|
}
|
||||||
|
}
|
||||||
78
cmhl/src/main/java/com/kizzy/cmhl/utils/ByteUtils.java
Normal file
78
cmhl/src/main/java/com/kizzy/cmhl/utils/ByteUtils.java
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package com.kizzy.cmhl.utils;
|
||||||
|
|
||||||
|
public class ByteUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates LRC by XORing all bytes in the data.
|
||||||
|
* @param data
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static byte calculateLrc(byte[] data) {
|
||||||
|
byte lrc = 0;
|
||||||
|
for (byte b : data) {
|
||||||
|
lrc ^= b;
|
||||||
|
}
|
||||||
|
return lrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static byte[] hexStringToByteArray(String s) {
|
||||||
|
// int len = s.length();
|
||||||
|
// byte[] data = new byte[len / 2];
|
||||||
|
// for (int i = 0; i < len; i += 2) {
|
||||||
|
// data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
||||||
|
// + Character.digit(s.charAt(i+1), 16));
|
||||||
|
// }
|
||||||
|
// return data;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static byte[] hexStringToByteArray(String s) {
|
||||||
|
if (s == null) return new byte[0];
|
||||||
|
// Ensure even length by padding with leading '0' if odd
|
||||||
|
if (s.length() % 2 != 0) {
|
||||||
|
s = "0" + s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int len = s.length();
|
||||||
|
byte[] data = new byte[len / 2];
|
||||||
|
for (int i = 0; i < len; i += 2) {
|
||||||
|
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
|
||||||
|
+ Character.digit(s.charAt(i+1), 16));
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String byteArrayToHexString(byte[] bytes) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (byte b : bytes) {
|
||||||
|
sb.append(String.format("%02X", b));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] concat(byte[]... arrays) {
|
||||||
|
int length = 0;
|
||||||
|
for (byte[] array : arrays) {
|
||||||
|
length += array.length;
|
||||||
|
}
|
||||||
|
byte[] result = new byte[length];
|
||||||
|
int pos = 0;
|
||||||
|
for (byte[] array : arrays) {
|
||||||
|
System.arraycopy(array, 0, result, pos, array.length);
|
||||||
|
pos += array.length;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] intToBcd(int val) {
|
||||||
|
// Only handles up to 9999 for 2 bytes
|
||||||
|
int thousands = (val / 1000) % 10;
|
||||||
|
int hundreds = (val / 100) % 10;
|
||||||
|
int tens = (val / 10) % 10;
|
||||||
|
int ones = val % 10;
|
||||||
|
|
||||||
|
byte b1 = (byte) ((thousands << 4) | hundreds);
|
||||||
|
byte b2 = (byte) ((tens << 4) | ones);
|
||||||
|
|
||||||
|
return new byte[]{b1, b2};
|
||||||
|
}
|
||||||
|
}
|
||||||
172
cmhl/src/test/java/com/kizzy/cmhl/ExampleUnitTest.java
Normal file
172
cmhl/src/test/java/com/kizzy/cmhl/ExampleUnitTest.java
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
package com.kizzy.cmhl;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.models.EcrPacket;
|
||||||
|
import com.kizzy.cmhl.models.PingRequest;
|
||||||
|
import com.kizzy.cmhl.models.PingResponse;
|
||||||
|
import com.kizzy.cmhl.models.PreAuthCancellationRequest;
|
||||||
|
import com.kizzy.cmhl.models.PreAuthCompletionRequest;
|
||||||
|
import com.kizzy.cmhl.models.PreAuthRequest;
|
||||||
|
import com.kizzy.cmhl.models.QrPaymentRequest;
|
||||||
|
import com.kizzy.cmhl.models.SaleRequest;
|
||||||
|
import com.kizzy.cmhl.models.SaleResponse;
|
||||||
|
import com.kizzy.cmhl.models.SettlementRequest;
|
||||||
|
import com.kizzy.cmhl.models.VoidQrPaymentRequest;
|
||||||
|
import com.kizzy.cmhl.models.VoidRequest;
|
||||||
|
import com.kizzy.cmhl.utils.ByteUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
public class ExampleUnitTest {
|
||||||
|
@Test
|
||||||
|
public void addition_isCorrect() {
|
||||||
|
assertEquals(4, 2 + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPing() {
|
||||||
|
PingResponse pingResponse = new PingResponse.Builder()
|
||||||
|
.setResponseCode("00")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
byte[] packet = EcrManager.buildPacket(pingResponse);
|
||||||
|
|
||||||
|
System.out.println("Packets :"+ByteUtils.byteArrayToHexString(packet));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testECRPacket() {
|
||||||
|
|
||||||
|
byte[] data = {
|
||||||
|
(byte) 0x02, (byte) 0x00, (byte) 0x27, (byte) 0x01, (byte) 0x07, (byte) 0x37,
|
||||||
|
(byte) 0x0C, (byte) 0x37, (byte) 0x30, (byte) 0x30, (byte) 0x35, (byte) 0x31,
|
||||||
|
(byte) 0x37, (byte) 0x31, (byte) 0x34, (byte) 0x39, (byte) 0x31, (byte) 0x34,
|
||||||
|
(byte) 0x35, (byte) 0x38, (byte) 0x06, (byte) 0x30, (byte) 0x30, (byte) 0x34,
|
||||||
|
(byte) 0x35, (byte) 0x37, (byte) 0x30, (byte) 0x15, (byte) 0x01, (byte) 0x02,
|
||||||
|
(byte) 0x03, (byte) 0x31
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] data2 = {
|
||||||
|
(byte) 0x02, (byte) 0x00, (byte) 0x21, (byte) 0x01, (byte) 0x0B, (byte) 0x04,
|
||||||
|
(byte) 0x0C, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30,
|
||||||
|
(byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30,
|
||||||
|
(byte) 0x30, (byte) 0x49, (byte) 0x03, (byte) 0x31, (byte) 0x30, (byte) 0x34,
|
||||||
|
(byte) 0x03, (byte) 0x55
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] data3 = {
|
||||||
|
(byte) 0x02, (byte) 0x00, (byte) 0x21, (byte) 0x01, (byte) 0x03, (byte) 0x04,
|
||||||
|
(byte) 0x0C, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30,
|
||||||
|
(byte) 0x31, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30, (byte) 0x30,
|
||||||
|
(byte) 0x30, (byte) 0x49, (byte) 0x03, (byte) 0x31, (byte) 0x30, (byte) 0x34,
|
||||||
|
(byte) 0x03, (byte) 0x55
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] ping = {
|
||||||
|
(byte) 0x02, (byte) 0x00, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x03, (byte) 0x02
|
||||||
|
};
|
||||||
|
|
||||||
|
byte[] qrPayment = ByteUtils.hexStringToByteArray("020021010B040C3030303030303030313335304903313034035B");
|
||||||
|
try {
|
||||||
|
EcrPacket ecrPacket = EcrManager.parsePacket(qrPayment);
|
||||||
|
|
||||||
|
EcrRequestDispatcher.dispatch(ecrPacket, new EcrRequestListener() {
|
||||||
|
@Override
|
||||||
|
public void onPingRequest(PingRequest request) {
|
||||||
|
PingResponse pingResponse = new PingResponse.Builder()
|
||||||
|
.setResponseCode("00")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
byte[] responsePacket = EcrManager.buildPacket(pingResponse);
|
||||||
|
System.out.println("Response: "+ ByteUtils.byteArrayToHexString(responsePacket));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaleRequest(SaleRequest request) {
|
||||||
|
System.out.println("command :"+ecrPacket.getCommandCode());
|
||||||
|
|
||||||
|
String amount = request.getAmount();
|
||||||
|
|
||||||
|
System.out.println("amount:"+amount);
|
||||||
|
|
||||||
|
SaleResponse response = new SaleResponse.Builder()
|
||||||
|
.setResponseCode("00")
|
||||||
|
.setAmount(amount)
|
||||||
|
.setPan("411122*****122")
|
||||||
|
.setApprovalCode("123456")
|
||||||
|
.setInvoiceNumber("000002")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
byte[] responsePacket = EcrManager.buildPacket(response);
|
||||||
|
System.out.println("Response: "+ ByteUtils.byteArrayToHexString(responsePacket));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVoidRequest(VoidRequest request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettlementRequest(SettlementRequest request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPreAuthRequest(PreAuthRequest request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPreAuthCompletionRequest(PreAuthCompletionRequest request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPreAuthCancellationRequest(PreAuthCancellationRequest request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onQrPaymentRequest(QrPaymentRequest request) {
|
||||||
|
System.out.println("command :"+ecrPacket.getCommandCode());
|
||||||
|
|
||||||
|
String amount = request.getAmount();
|
||||||
|
String currency = request.getCurrencyCode();
|
||||||
|
|
||||||
|
System.out.println("amount:"+amount);
|
||||||
|
System.out.println("currency:"+currency);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onVoidQrPaymentRequest(VoidQrPaymentRequest request) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onUnknownRequest(EcrPacket packet) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// System.out.println("command :"+ecrPacket.getCommandCode());
|
||||||
|
//
|
||||||
|
// QrPaymentRequest request = new QrPaymentRequest(ecrPacket);
|
||||||
|
// String amount = request.getAmount();
|
||||||
|
// String currency = request.getCurrencyCode();
|
||||||
|
//
|
||||||
|
// System.out.println("amount:"+amount);
|
||||||
|
// System.out.println("currency:"+currency);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
28
ecr-service-lib/.gitignore
vendored
28
ecr-service-lib/.gitignore
vendored
@ -1,28 +0,0 @@
|
|||||||
/build
|
|
||||||
|
|
||||||
# Built files
|
|
||||||
*.apk
|
|
||||||
*.aab
|
|
||||||
*.dex
|
|
||||||
*.class
|
|
||||||
|
|
||||||
# Gradle
|
|
||||||
.gradle/
|
|
||||||
build/
|
|
||||||
*/build/
|
|
||||||
|
|
||||||
# Android Studio
|
|
||||||
*.iml
|
|
||||||
.idea/
|
|
||||||
local.properties
|
|
||||||
|
|
||||||
# Keystore
|
|
||||||
*.jks
|
|
||||||
*.keystore
|
|
||||||
|
|
||||||
# OS files
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Logs
|
|
||||||
*.log
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
configurations.maybeCreate("default")
|
|
||||||
artifacts.add("default", file('ecr-service-lib-1.1.11.aar'))
|
|
||||||
//artifacts.add("default", file('Link_POS_Library_V1.9.aar'))
|
|
||||||
Binary file not shown.
3
ecr-service/.idea/.gitignore
vendored
3
ecr-service/.idea/.gitignore
vendored
@ -1,3 +0,0 @@
|
|||||||
# Default ignored files
|
|
||||||
/shelf/
|
|
||||||
/workspace.xml
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="AndroidProjectSystem">
|
|
||||||
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ProjectMigrations">
|
|
||||||
<option name="MigrateToGradleLocalJavaHome">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="ProjectRootManager">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,17 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RunConfigurationProducerService">
|
|
||||||
<option name="ignoredProducers">
|
|
||||||
<set>
|
|
||||||
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
|
|
||||||
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
|
|
||||||
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@ -31,12 +31,9 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: "libs", include: ["*.jar","*.aar"])
|
implementation fileTree(dir: "libs", include: ["*.jar","*.aar"])
|
||||||
// implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
|
||||||
implementation 'androidx.core:core-ktx:1.6.0'
|
implementation 'androidx.core:core-ktx:1.6.0'
|
||||||
implementation 'androidx.appcompat:appcompat:1.3.1'
|
implementation 'androidx.appcompat:appcompat:1.3.1'
|
||||||
implementation project(path: ':nexsdk-lib')
|
implementation project(path: ':nexsdk-lib')
|
||||||
// implementation files('libs/ecr-service-lib-1.1.11.aar')
|
|
||||||
implementation project(path: ':ecr-service-lib')
|
|
||||||
implementation project(path: ':paylibs')
|
implementation project(path: ':paylibs')
|
||||||
implementation 'com.google.code.gson:gson:2.9.0'
|
implementation 'com.google.code.gson:gson:2.9.0'
|
||||||
|
|
||||||
|
|||||||
@ -1,25 +1,29 @@
|
|||||||
package com.utsmyanmar.ecr
|
package com.utsmyanmar.ecr
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
|
||||||
import android.widget.Toast
|
|
||||||
import com.nexgo.oaf.apiv3.APIProxy
|
import com.nexgo.oaf.apiv3.APIProxy
|
||||||
import com.nexgo.oaf.apiv3.SdkResult
|
import com.nexgo.oaf.apiv3.SdkResult
|
||||||
import com.nexgo.oaf.apiv3.device.serialport.SerialCfgEntity
|
import com.nexgo.oaf.apiv3.device.serialport.SerialCfgEntity
|
||||||
import com.nexgo.oaf.apiv3.device.serialport.SerialPortDriver
|
import com.nexgo.oaf.apiv3.device.serialport.SerialPortDriver
|
||||||
import com.pos.connection.bridge.ECRConnection
|
|
||||||
import com.pos.connection.bridge.ECRListener
|
|
||||||
import com.pos.connection.bridge.ECRRequestCallback
|
|
||||||
import com.pos.connection.bridge.ECRService
|
|
||||||
import com.pos.hardware.connection.library.ECRServiceKernel
|
|
||||||
import com.utsmyanmar.paylibs.utils.LogUtil
|
import com.utsmyanmar.paylibs.utils.LogUtil
|
||||||
import java.nio.charset.StandardCharsets
|
import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NexGo SerialPortDriver wrapper (port 0 = physical USB serial).
|
||||||
|
* Spec: connect / send / recv / clrBuffer / disconnect.
|
||||||
|
*/
|
||||||
object ECRHelper {
|
object ECRHelper {
|
||||||
|
|
||||||
val TAG = ECRHelper::class.java.simpleName
|
val TAG: String = ECRHelper::class.java.simpleName
|
||||||
|
|
||||||
|
private const val PORT_NO = 0
|
||||||
|
private const val RECV_BUFFER_SIZE = 2048
|
||||||
|
private const val RECV_TIMEOUT_MS = 3000L
|
||||||
|
|
||||||
private var ecrService: ECRService? = null
|
|
||||||
private var serialPort: SerialPortDriver? = null
|
private var serialPort: SerialPortDriver? = null
|
||||||
|
private var receiveThread: Thread? = null
|
||||||
|
private val receiving = AtomicBoolean(false)
|
||||||
|
|
||||||
var onBindSuccess: () -> Unit = { }
|
var onBindSuccess: () -> Unit = { }
|
||||||
var onBindFailure: () -> Unit = { }
|
var onBindFailure: () -> Unit = { }
|
||||||
@ -32,12 +36,19 @@ object ECRHelper {
|
|||||||
|
|
||||||
var onECRReceive: (bytes: ByteArray) -> Unit = { }
|
var onECRReceive: (bytes: ByteArray) -> Unit = { }
|
||||||
|
|
||||||
// ─── Serial Port Init (call this once, e.g. in Application or Activity) ───
|
val isConnected: Boolean
|
||||||
|
get() = serialPort != null
|
||||||
|
|
||||||
fun initSerialPort(context: Context) {
|
fun initSerialPort(context: Context) {
|
||||||
try {
|
try {
|
||||||
|
if (serialPort != null) {
|
||||||
|
LogUtil.d(TAG, "Serial port already connected")
|
||||||
|
onBindSuccess()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val deviceEngine = APIProxy.getDeviceEngine(context)
|
val deviceEngine = APIProxy.getDeviceEngine(context)
|
||||||
val port = deviceEngine.getSerialPortDriver(0)
|
val port = deviceEngine.getSerialPortDriver(PORT_NO)
|
||||||
|
|
||||||
val entity = SerialCfgEntity().apply {
|
val entity = SerialCfgEntity().apply {
|
||||||
baudRate = 115200
|
baudRate = 115200
|
||||||
@ -49,143 +60,110 @@ object ECRHelper {
|
|||||||
val result = port.connect(entity)
|
val result = port.connect(entity)
|
||||||
if (result == SdkResult.Success) {
|
if (result == SdkResult.Success) {
|
||||||
serialPort = port
|
serialPort = port
|
||||||
LogUtil.d(TAG, "USB Serial connected")
|
port.clrBuffer()
|
||||||
|
ECRUtil.connected = true
|
||||||
|
LogUtil.d(TAG, "SerialPortDriver connected (port=$PORT_NO)")
|
||||||
|
startReceiveLoop()
|
||||||
|
onECRConnected()
|
||||||
|
onBindSuccess()
|
||||||
} else {
|
} else {
|
||||||
LogUtil.e(TAG, "USB Serial connect failed: $result")
|
LogUtil.e(TAG, "SerialPortDriver connect failed: $result")
|
||||||
|
ECRUtil.connected = false
|
||||||
|
onBindFailure()
|
||||||
onSendFailure(result, "Serial port connect failed")
|
onSendFailure(result, "Serial port connect failed")
|
||||||
}
|
}
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
|
ECRUtil.connected = false
|
||||||
|
onBindFailure()
|
||||||
onSendFailure(-200, ex.localizedMessage ?: "Serial init error")
|
onSendFailure(-200, ex.localizedMessage ?: "Serial init error")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun releaseSerialPort() {
|
|
||||||
try {
|
|
||||||
serialPort?.disconnect()
|
|
||||||
} catch (ex: Throwable) {
|
|
||||||
ex.printStackTrace()
|
|
||||||
} finally {
|
|
||||||
serialPort = null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ─── Send: uses Serial Port instead of ECRService ─────────────────────────
|
|
||||||
|
|
||||||
fun send(bytes: ByteArray) {
|
fun send(bytes: ByteArray) {
|
||||||
try {
|
try {
|
||||||
val port = serialPort
|
val port = serialPort
|
||||||
if (port != null) {
|
if (port == null) {
|
||||||
|
LogUtil.e(TAG, "Serial port not initialized")
|
||||||
|
onSendFailure(-100, "Serial port not initialized")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (bytes.isEmpty() || bytes.size > RECV_BUFFER_SIZE) {
|
||||||
|
onSendFailure(SdkResult.Param_In_Invalid, "Invalid send length")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
val result = port.send(bytes, bytes.size)
|
val result = port.send(bytes, bytes.size)
|
||||||
if (result == SdkResult.Success) {
|
if (result == SdkResult.Success) {
|
||||||
LogUtil.d(TAG, "Serial send success")
|
LogUtil.d(TAG, "Serial send success, len=${bytes.size}")
|
||||||
onSendSuccess()
|
onSendSuccess()
|
||||||
} else {
|
} else {
|
||||||
LogUtil.e(TAG, "Serial send failed: $result")
|
LogUtil.e(TAG, "Serial send failed: $result")
|
||||||
onSendFailure(result, "Serial send failed")
|
onSendFailure(result, "Serial send failed")
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
LogUtil.e(TAG, "Serial port not initialized")
|
|
||||||
onSendFailure(-100, "Serial port not initialized")
|
|
||||||
}
|
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
onSendFailure(-200, ex.localizedMessage ?: "")
|
onSendFailure(-200, ex.localizedMessage ?: "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Everything below is unchanged ────────────────────────────────────────
|
fun clrBuffer() {
|
||||||
|
try {
|
||||||
fun connect(bundle: Bundle) {
|
serialPort?.clrBuffer()
|
||||||
call {
|
} catch (ex: Throwable) {
|
||||||
anyExecute(ecrService) {
|
ex.printStackTrace()
|
||||||
connect(bundle, ecrConnection)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun disconnect() {
|
fun disconnect() {
|
||||||
call { anyExecute(ecrService) { disconnect() } }
|
releaseSerialPort()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun registerECRListener() {
|
fun releaseSerialPort() {
|
||||||
call { anyExecute(ecrService) { register(ecrListener) } }
|
receiving.set(false)
|
||||||
}
|
|
||||||
|
|
||||||
fun unregisterECRListener() {
|
|
||||||
call { anyExecute(ecrService) { unregister(ecrListener) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun extensionMethod(bundle: Bundle) {
|
|
||||||
call { anyExecute(ecrService) { extensionMethod(bundle) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
private val ecrListener = object : ECRListener.Stub() {
|
|
||||||
override fun onReceive(byteArray: ByteArray?) {
|
|
||||||
if (byteArray != null) {
|
|
||||||
val string = String(byteArray, StandardCharsets.UTF_8)
|
|
||||||
Logger.e(TAG, "onReceive string: $string")
|
|
||||||
onECRReceive(byteArray)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val requestCallback = object : ECRRequestCallback.Stub() {
|
|
||||||
override fun onSuccess() {
|
|
||||||
Logger.e(TAG, "onSuccess")
|
|
||||||
onSendSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(code: Int, massage: String?) {
|
|
||||||
Logger.e(TAG, "onFailure code: $code massage: $massage")
|
|
||||||
onSendFailure(code, massage ?: "failure")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val ecrConnection = object : ECRConnection.Stub() {
|
|
||||||
override fun onConnected() {
|
|
||||||
Logger.d(TAG, "onConnected")
|
|
||||||
ECRUtil.connected = true
|
|
||||||
onECRConnected()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDisconnected(code: Int, massage: String?) {
|
|
||||||
Logger.d(TAG, "onDisconnected code: $code massage: $massage")
|
|
||||||
ECRUtil.connected = false
|
|
||||||
onECRDisconnected(code, massage ?: "failure")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bindECRService() {
|
|
||||||
ECRServiceKernel.getInstance().bindService(ECRUtil.context, connectionCallback)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val connectionCallback = object : ECRServiceKernel.ConnectionCallback {
|
|
||||||
override fun onServiceConnected() {
|
|
||||||
Logger.e(TAG, "onServiceConnected")
|
|
||||||
ecrService = ECRServiceKernel.getInstance().ecrService
|
|
||||||
onBindSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onServiceDisconnected() {
|
|
||||||
Logger.e(TAG, "onServiceDisconnected")
|
|
||||||
ECRUtil.connected = false
|
|
||||||
ecrService = null
|
|
||||||
onBindFailure()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun call(block: () -> Unit) {
|
|
||||||
try {
|
try {
|
||||||
val bridgeService = ecrService
|
receiveThread?.interrupt()
|
||||||
if (bridgeService != null) {
|
} catch (_: Throwable) {
|
||||||
block()
|
|
||||||
} else {
|
|
||||||
onECRDisconnected(-100, "The bind ECRService failure")
|
|
||||||
}
|
}
|
||||||
|
receiveThread = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
val result = serialPort?.disconnect() ?: SdkResult.SerialPort_Port_Not_Open
|
||||||
|
LogUtil.d(TAG, "SerialPortDriver disconnect: $result")
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
ex.printStackTrace()
|
ex.printStackTrace()
|
||||||
onECRDisconnected(-200, ex.localizedMessage ?: "")
|
} finally {
|
||||||
|
serialPort = null
|
||||||
|
ECRUtil.connected = false
|
||||||
|
onECRDisconnected(0, "disconnected")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startReceiveLoop() {
|
||||||
|
if (receiving.getAndSet(true)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
receiveThread = Thread({
|
||||||
|
val buffer = ByteArray(RECV_BUFFER_SIZE)
|
||||||
|
while (receiving.get()) {
|
||||||
|
val port = serialPort ?: break
|
||||||
|
try {
|
||||||
|
val len = port.recv(buffer, buffer.size, RECV_TIMEOUT_MS)
|
||||||
|
if (len > 0) {
|
||||||
|
val data = buffer.copyOf(len)
|
||||||
|
LogUtil.d(TAG, "Serial recv len=$len")
|
||||||
|
LogUtil.d(TAG," Receive packet : "+ ByteUtil.bytes2HexStr(data));
|
||||||
|
onECRReceive(data)
|
||||||
|
}
|
||||||
|
// timeout / no data: keep listening
|
||||||
|
} catch (ex: Throwable) {
|
||||||
|
if (receiving.get()) {
|
||||||
|
LogUtil.e(TAG, "Serial recv error: ${ex.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
receiving.set(false)
|
||||||
|
}, "ECR-SerialRecv").also { it.start() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -33,9 +33,9 @@ include ':mpulib'
|
|||||||
|
|
||||||
//include ':ecr-client-lib'
|
//include ':ecr-client-lib'
|
||||||
//include ':ecr-service'
|
//include ':ecr-service'
|
||||||
|
//include ':ecr-service-lib'
|
||||||
include ':xpay'
|
include ':xpay'
|
||||||
include ':ecr'
|
include ':ecr'
|
||||||
include ':ecr-service-lib'
|
|
||||||
include ':link-service-lib'
|
include ':link-service-lib'
|
||||||
include ':qrgen-lib'
|
include ':qrgen-lib'
|
||||||
include ':nexdlkey-lib'
|
include ':nexdlkey-lib'
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user