From 048f802c18c80156ea47e5e85c79edaa17be359c Mon Sep 17 00:00:00 2001 From: kizzy Date: Tue, 24 Mar 2026 15:33:16 +0700 Subject: [PATCH] ECR need polish --- app/build.gradle | 1 + app/src/main/AndroidManifest.xml | 8 + .../main/java/com/utsmm/kbz/MainFragment.java | 360 +++++++++++---- .../java/com/utsmm/kbz/MyApplication.java | 3 +- .../utsmm/kbz/service/SerialPortService.java | 112 +++++ .../kbz/ui/core_ui/CardWaitingFragment.java | 30 +- .../ui/core_ui/EmvTransactionFragment.java | 26 +- .../kbz/ui/core_ui/ProcessingFragment.java | 15 +- .../ui/core_ui/TransactionResultFragment.java | 20 +- .../kbz/ui/kpay/QRConnectingFragment.java | 39 +- .../kbz/ui/kpay/QRTransactionFragment.java | 24 +- .../utsmm/kbz/ui/pinpad/PinPadFragment.java | 19 +- .../com/utsmm/kbz/util/TransactionUtil.java | 3 +- .../com/utsmm/kbz/util/ecr/CoreUtils.java | 416 +++++++++++++++++- .../utsmm/kbz/util/ecr/ECRResultStatus.java | 12 + .../com/utsmm/kbz/util/ecr/ECRSetupsCMHL.java | 35 ++ .../com/utsmm/kbz/util/tms/TMSSetupsImpl.java | 2 + .../baselib/viewModel/EmvBaseViewModel.java | 8 +- ecr/build.gradle | 2 +- .../main/java/com/utsmyanmar/ecr/ECRHelper.kt | 101 +++-- .../paylibs/system/BaseErrorCode.java | 72 +++ .../utils/AuthorizationProcessUtil.java | 5 +- .../com/utsmyanmar/paylibs/utils/POSUtil.java | 53 +++ .../core_utils/SystemParamsOperation.java | 11 + .../core_utils/SystemParamsSettings.java | 6 + .../paylibs/utils/enums/CardScheme.java | 23 +- settings.gradle | 1 + 27 files changed, 1265 insertions(+), 142 deletions(-) create mode 100644 app/src/main/java/com/utsmm/kbz/service/SerialPortService.java create mode 100644 app/src/main/java/com/utsmm/kbz/util/ecr/ECRResultStatus.java create mode 100644 app/src/main/java/com/utsmm/kbz/util/ecr/ECRSetupsCMHL.java diff --git a/app/build.gradle b/app/build.gradle index 60e4d69..12aa58e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -216,6 +216,7 @@ dependencies { implementation project(path: ':xpay') // implementation project(path: ':sunmiui-lib') implementation project(path: ':qrgen-lib') + implementation project(path: ':cmhl') //// implementation project(path: ':samlSirius') // Legacy ECR (kept for backward compatibility during migration) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 2cbf5ff..d1938f4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -35,6 +35,7 @@ + @@ -98,7 +99,14 @@ + + + + \ No newline at end of file diff --git a/app/src/main/java/com/utsmm/kbz/MainFragment.java b/app/src/main/java/com/utsmm/kbz/MainFragment.java index bc2e9dc..bd15c0d 100644 --- a/app/src/main/java/com/utsmm/kbz/MainFragment.java +++ b/app/src/main/java/com/utsmm/kbz/MainFragment.java @@ -1,8 +1,13 @@ 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.RemoteException; @@ -20,6 +25,19 @@ import androidx.lifecycle.Observer; import com.denzcoskun.imageslider.ImageSlider; import com.denzcoskun.imageslider.constants.ScaleTypes; import com.denzcoskun.imageslider.models.SlideModel; +import com.kizzy.cmhl.EcrManager; +import com.kizzy.cmhl.EcrRequestDispatcher; +import com.kizzy.cmhl.EcrRequestListener; +import com.kizzy.cmhl.models.EcrPacket; +import com.kizzy.cmhl.models.PingRequest; +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.SettlementRequest; +import com.kizzy.cmhl.models.VoidQrPaymentRequest; +import com.kizzy.cmhl.models.VoidRequest; import com.nexgo.oaf.apiv3.APIProxy; import com.nexgo.oaf.apiv3.DeviceEngine; import com.nexgo.oaf.apiv3.SdkResult; @@ -29,6 +47,7 @@ import com.nexgo.oaf.apiv3.emv.AidEntity; 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.ecr.ModernECRFactory; //import com.utsmm.kbz.util.ecr.ModernECRManager; @@ -49,6 +68,7 @@ import com.utsmyanmar.paylibs.model.TradeData; import com.utsmyanmar.paylibs.print.PrintHelper; import com.utsmyanmar.paylibs.print.printx.PrintXReceipt; 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.enums.CurrencyType; import com.utsmyanmar.paylibs.utils.enums.TransMenu; @@ -90,6 +110,7 @@ import com.utsmyanmar.paylibs.utils.params.Params; //import com.utsmm.kbz.util.ecr.ModernECRFactory; //import com.utsmm.kbz.util.ecr.ModernECRManager; import androidx.lifecycle.ViewModelProvider; +import androidx.localbroadcastmanager.content.LocalBroadcastManager; @AndroidEntryPoint public class MainFragment extends DataBindingFragment { @@ -134,16 +155,42 @@ public class MainFragment extends DataBindingFragment { // modernECRManager = new ViewModelProvider(this, factory).get(ModernECRManager.class); } + @Override + public void onStart() { + super.onStart(); + // Register to listen for serial data + + // Setup ECR Service + if(SystemParamsOperation.getInstance().getECRStatus()){ + LocalBroadcastManager.getInstance(requireContext()) + .registerReceiver(serialReceiver, + 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)); + } + + LogUtil.d(TAG,"ECR service initialized!"); + } + + } + + @Override + public void onStop() { + super.onStop(); + LocalBroadcastManager.getInstance(requireContext()) + .unregisterReceiver(serialReceiver); + } + @Override public void onResume() { super.onResume(); setNavBarIconWithTitle(getResourceString(R.string.menu_dashboard)); - // Setup ECR Service - if(SystemParamsOperation.getInstance().getECRStatus()){ - setUpECR(); - } + sharedViewModel.isEcrFinished.postValue(true); sharedViewModel.isEcr.postValue(false); @@ -196,7 +243,33 @@ public class MainFragment extends DataBindingFragment { safeNavigateToRouteId(); } } - + + 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 public void onCreate(@Nullable Bundle savedInstanceState) { @@ -260,68 +333,8 @@ public class MainFragment extends DataBindingFragment { // queryAidCAPKList(); queryAidCAPKList(); // generateMockQR(); - DeviceEngine deviceEngine = APIProxy.getDeviceEngine(requireContext()); - - 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("USB", "USB Serial connected"); - String echo = "Hello ECR"; - byte[] data = echo.getBytes(StandardCharsets.UTF_8); - port.send(data, data.length); - - port.clrBuffer(); - - isRunning = true; - startReceiveThread(); - - } else { - - LogUtil.e("USB", "USB Serial connect failed"); - - } } - private void startReceiveThread() { - - 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); - - LogUtil.d("USB", "Received: " + msg); - - requireActivity().runOnUiThread(() -> { - - // update UI here - // example: - // binding.txtResult.setText(msg); - - }); - } - } - - }).start(); - } - - - /* * @param * @@ -366,25 +379,8 @@ public class MainFragment extends DataBindingFragment { }); } - private void setUpECR() { - if (checkECRServiceAppExistOrNot()) { - // Initialize Modern ECR Manager -// modernECRManager.init(); -//// -//// // Observe navigation requests -// modernECRManager.getNavigationRequest().observe(getViewLifecycleOwner(), destinationId -> { -// if (destinationId != null) { -// delayFunctionCall(() -> isRouteValidAndNavigateToRoute(destinationId)); -// } -// }); - - showShortToast("ECR Service initialized"); - } else { - Toast.makeText(getContext(), "ECR Service Not Found!", Toast.LENGTH_SHORT).show(); - } - } - // Legacy ECR methods removed + private void updateButtonStatus() { @@ -761,6 +757,204 @@ public class MainFragment extends DataBindingFragment { } + private void ECRAction(String msg) { + +// LogUtil.d(TAG, "ECR msg here : " + msg); + + String ecrKey = SystemParamsOperation.getInstance().getEcrKey().toUpperCase(); + String pkgName = BuildConfig.APPLICATION_ID; + String serialNo = TerminalUtil.getInstance().getSerialNo(); + + ResultOf result = ECRProcess.INSTANCE.parseECRRequest(ecrKey,pkgName,serialNo,msg); + + if (result instanceof ResultOf.Success) { + Transactions trans = ((ResultOf.Success) result).getValue(); + + + CoreUtils.getInstance(sharedViewModel).logTrans(trans); + + sharedViewModel.ecrCMD.postValue(trans.getCMD()); + sharedViewModel.ecrTrans.postValue(trans); + + switch (Objects.requireNonNull(trans.getCMD())) { + case ECHO: + CoreUtils.getInstance(sharedViewModel).setUpECREchoTest(); + break; + case SALE: + if (CoreUtils.getInstance(sharedViewModel).setUpECRSale(trans)) { + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment)); + } + break; + case VOID: + if(!SystemParamsOperation.getInstance().getVoidStatus()) { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(trans,"Void is disabled!"); + return; + } + if (CoreUtils.getInstance(sharedViewModel).setUpECRVoid(trans)) { + delayFunctionCall(() -> { + if(Objects.requireNonNull(getNavController(Constants.NAV_HOST_ID).getCurrentDestination()).getId() == R.id.nav_main) { + setToolBarTitle(getResourceString(R.string.menu_sale_void)); + } + + isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_inputPasswordFragment); + }); + } + break; + case CASH_ADVANCE: { + + if (CoreUtils.getInstance(sharedViewModel).setUpECRCashAdvance(trans)) { + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment)); + } + + break; + } + case QR_SALE: { + if (CoreUtils.getInstance(sharedViewModel).setUpECRQR(trans)) { + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_QRConnectingFragment)); + } + break; + + } + + case SETTLEMENT: { + if(!SystemParamsOperation.getInstance().getSettlementStatus()) { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(trans,"Settlement is disabled!"); + return; + } + CoreUtils.getInstance(sharedViewModel).setUpECRSettlement(); + + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_inputPasswordFragment)); + + break; + } + + default: + showDeclineDialog("No Action found on \n" + trans.getCMD()); + break; + } + } else { + String errorMsg = ((ResultOf.Failure) result).getMessage(); + showDeclineDialog("No Action found on \n" + errorMsg); + } + + } + + private void ECRActionCHML(byte[] data) { + +// LogUtil.d(TAG, "ECR msg here : " + msg); + try { + EcrPacket ecrPacket = EcrManager.parsePacket(data); + + EcrRequestDispatcher.dispatch(ecrPacket, new EcrRequestListener() { + @Override + public void onPingRequest(PingRequest request) { + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + + CoreUtils.getInstance(sharedViewModel).setupPingRequest(request); + + + } + + @Override + public void onSaleRequest(SaleRequest request) { + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + + if (CoreUtils.getInstance(sharedViewModel).setUpECRSale(request)) { + LogUtil.d(TAG,"Starting to process sale transaction!"); + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment)); + } + + + } + + @Override + public void onVoidRequest(VoidRequest request) { + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + + if (CoreUtils.getInstance(sharedViewModel).setUpECRVoid(request)) { + delayFunctionCall(() -> { + if(Objects.requireNonNull(getNavController(Constants.NAV_HOST_ID).getCurrentDestination()).getId() == R.id.nav_main) { + setToolBarTitle(getResourceString(R.string.menu_sale_void)); + } + + isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_inputPasswordFragment); + }); + } + } + + @Override + public void onSettlementRequest(SettlementRequest request) { +// + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + + CoreUtils.getInstance(sharedViewModel).setUpECRSettlement(); + + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_inputPasswordFragment)); + } + + @Override + public void onPreAuthRequest(PreAuthRequest request) { + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + + if (CoreUtils.getInstance(sharedViewModel).setUpECRPreAuth(request)) { + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment)); + } + + } + + @Override + public void onPreAuthCompletionRequest(PreAuthCompletionRequest request) { + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + + if (CoreUtils.getInstance(sharedViewModel).setUpECRPreAuthComplete(request)) { + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment)); + } + } + + @Override + public void onPreAuthCancellationRequest(PreAuthCancellationRequest request) { + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + + if (CoreUtils.getInstance(sharedViewModel).setUpECRPreAuthVoid(request)) { + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment)); + } + } + + @Override + public void onQrPaymentRequest(QrPaymentRequest request) { + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + + if (CoreUtils.getInstance(sharedViewModel).setUpECRQR(request)) { + delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_QRConnectingFragment)); + } + + } + + @Override + public void onVoidQrPaymentRequest(VoidQrPaymentRequest request) { + + } + + @Override + public void onUnknownRequest(EcrPacket packet) { + System.out.println("command :"+packet.getCommandCode()); + } + }); + + } catch (Exception e) { + e.printStackTrace(); + } + + + } + public class ClickEvent { public void onClickTrans() { diff --git a/app/src/main/java/com/utsmm/kbz/MyApplication.java b/app/src/main/java/com/utsmm/kbz/MyApplication.java index f0ab182..2a77f6e 100644 --- a/app/src/main/java/com/utsmm/kbz/MyApplication.java +++ b/app/src/main/java/com/utsmm/kbz/MyApplication.java @@ -1,6 +1,7 @@ package com.utsmm.kbz; import com.utsmyanmar.baselib.BaseApplication; +import com.utsmyanmar.ecr.ECRHelper; import dagger.hilt.android.HiltAndroidApp; @@ -21,7 +22,7 @@ public class MyApplication extends BaseApplication { super.onCreate(); app = this; - + ECRHelper.INSTANCE.initSerialPort(getApplicationContext()); // emvParamOperation.loadDataFromJSON(); } diff --git a/app/src/main/java/com/utsmm/kbz/service/SerialPortService.java b/app/src/main/java/com/utsmm/kbz/service/SerialPortService.java new file mode 100644 index 0000000..6308756 --- /dev/null +++ b/app/src/main/java/com/utsmm/kbz/service/SerialPortService.java @@ -0,0 +1,112 @@ +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; } +} diff --git a/app/src/main/java/com/utsmm/kbz/ui/core_ui/CardWaitingFragment.java b/app/src/main/java/com/utsmm/kbz/ui/core_ui/CardWaitingFragment.java index c8a9668..94d07af 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/core_ui/CardWaitingFragment.java +++ b/app/src/main/java/com/utsmm/kbz/ui/core_ui/CardWaitingFragment.java @@ -7,6 +7,8 @@ import android.view.View; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.kizzy.cmhl.EcrManager; +import com.kizzy.cmhl.models.SaleResponse; import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum; import com.utsmm.kbz.ui.pinpad.PinPadViewModel; import com.utsmm.kbz.util.TransactionUtil; @@ -20,7 +22,9 @@ import com.utsmyanmar.checkxread.readcard.MPUXReadCard; import com.utsmyanmar.checkxread.readcard.ReadCardResultX; import com.utsmyanmar.checkxread.sdk.NexGoSDK; import com.utsmyanmar.checkxread.util.CardTypeX; +import com.utsmyanmar.ecr.ECRHelper; import com.utsmyanmar.paylibs.model.TradeData; +import com.utsmyanmar.paylibs.system.SystemDateTime; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; import com.utsmm.kbz.BR; @@ -109,10 +113,25 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind private void finishECR() { sharedViewModel.isEcr.postValue(false); - CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans)); sharedViewModel.isEcrFinished.postValue(true); + + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + ECRHelper.INSTANCE.send(generateCHMLResponse()); +// CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + } else { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans)); + } } + private byte[] generateCHMLResponse() { + SaleResponse saleResponse = new SaleResponse.Builder() + .setResponseCode("FF") + .setTime(SystemDateTime.getHHmmss()) + .setDate(SystemDateTime.getMMDD()) + .build(); + + return EcrManager.buildPacket(saleResponse); + } public class ClickEvent { @@ -362,8 +381,15 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind if (sharedViewModel.isEcr.getValue()) { sharedViewModel.isEcr.postValue(false); - CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg); sharedViewModel.isEcrFinished.postValue(true); + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + ECRHelper.INSTANCE.send(generateCHMLResponse()); + +// CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + } else { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg); + } + } } } diff --git a/app/src/main/java/com/utsmm/kbz/ui/core_ui/EmvTransactionFragment.java b/app/src/main/java/com/utsmm/kbz/ui/core_ui/EmvTransactionFragment.java index babb908..f0d2574 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/core_ui/EmvTransactionFragment.java +++ b/app/src/main/java/com/utsmm/kbz/ui/core_ui/EmvTransactionFragment.java @@ -11,6 +11,8 @@ import androidx.appcompat.app.AlertDialog; import androidx.navigation.NavController; import androidx.navigation.NavDestination; +import com.kizzy.cmhl.EcrManager; +import com.kizzy.cmhl.models.SaleResponse; import com.utsmm.kbz.ui.core_viewmodel.CardReadViewModel; import com.utsmm.kbz.ui.pinpad.PinPadViewModel; import com.utsmyanmar.baselib.fragment.DataBindingFragment; @@ -20,8 +22,10 @@ import com.utsmyanmar.baselib.util.CardDetectCallback; import com.utsmyanmar.baselib.util.DataBindingConfig; import com.utsmyanmar.checkxread.sdk.NexGoSDK; import com.utsmyanmar.checkxread.util.CardTypeX; +import com.utsmyanmar.ecr.ECRHelper; import com.utsmyanmar.paylibs.model.PayDetail; import com.utsmyanmar.paylibs.model.TradeData; +import com.utsmyanmar.paylibs.system.SystemDateTime; import com.utsmyanmar.paylibs.utils.POSUtil; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; @@ -392,17 +396,36 @@ public class EmvTransactionFragment extends DataBindingFragment { } + ECRActionCancel(ecrErrorMsg); navigateToError(); }); } + private byte[] generateCHMLResponse() { + SaleResponse saleResponse = new SaleResponse.Builder() + .setResponseCode("FF") + .setTime(SystemDateTime.getHHmmss()) + .setDate(SystemDateTime.getMMDD()) + .build(); + + return EcrManager.buildPacket(saleResponse); + } + private void ECRActionCancel(String message) { if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) { LogUtil.d(TAG, "isECR true"); sharedViewModel.isEcrFinished.postValue(true); - CoreUtils.getInstance(sharedViewModel).responseRejectMsg(message); + sharedViewModel.isEcr.postValue(false); + + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + ECRHelper.INSTANCE.send(generateCHMLResponse()); +// CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + } else { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(message); + } + if (isEmvTrans()) { emvTransactionViewModel.onCancelEmvTransaction(); @@ -411,6 +434,7 @@ public class EmvTransactionFragment extends DataBindingFragment { } + private boolean isEmvTrans() { return sharedViewModel.isEmv.getValue() != null && sharedViewModel.isEmv.getValue(); } diff --git a/app/src/main/java/com/utsmm/kbz/ui/core_ui/ProcessingFragment.java b/app/src/main/java/com/utsmm/kbz/ui/core_ui/ProcessingFragment.java index 6cc28be..16cea4a 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/core_ui/ProcessingFragment.java +++ b/app/src/main/java/com/utsmm/kbz/ui/core_ui/ProcessingFragment.java @@ -9,6 +9,7 @@ import androidx.annotation.Nullable; import androidx.navigation.NavController; import androidx.navigation.NavDestination; +import com.utsmm.kbz.util.ecr.ECRResultStatus; import com.utsmm.kbz.util.tms.TMSUtil; import com.utsmyanmar.baselib.fragment.DataBindingFragment; import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptCardRequest; @@ -17,6 +18,7 @@ import com.utsmyanmar.baselib.fragment.DataBindingFragment; import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest; import com.utsmyanmar.baselib.util.DataBindingConfig; import com.utsmyanmar.baselib.util.TimeoutCallback; +import com.utsmyanmar.ecr.ECRHelper; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmm.kbz.BR; import com.utsmm.kbz.R; @@ -238,15 +240,26 @@ public class ProcessingFragment extends DataBindingFragment { if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) { sharedViewModel.isEcr.postValue(false); - CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg); + sharedViewModel.isEcrFinished.postValue(true); + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + ECRHelper.INSTANCE.send(getECRResponseCMHL()); + +// CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + } else { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg); + } + if(isEmvTrans()) { emvTransactionProcessViewModel.onCancelEmvTransaction(); } } } + private byte[] getECRResponseCMHL() { + return CoreUtils.getInstance(sharedViewModel).generateCMHLResponse(ECRResultStatus.TIME_OUT); + } private void navigateToError() { routeId = R.id.action_processingFragment_to_errorFragment; diff --git a/app/src/main/java/com/utsmm/kbz/ui/core_ui/TransactionResultFragment.java b/app/src/main/java/com/utsmm/kbz/ui/core_ui/TransactionResultFragment.java index 2bf8be7..ac583a0 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/core_ui/TransactionResultFragment.java +++ b/app/src/main/java/com/utsmm/kbz/ui/core_ui/TransactionResultFragment.java @@ -10,6 +10,7 @@ import androidx.appcompat.app.AppCompatActivity; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.google.gson.stream.MalformedJsonException; +import com.utsmm.kbz.util.ecr.ECRResultStatus; import com.utsmyanmar.baselib.emv.EmvParamOperation; import com.utsmyanmar.baselib.fragment.DataBindingFragment; import com.utsmyanmar.baselib.network.model.sirius.SiriusError; @@ -29,6 +30,7 @@ import com.utsmyanmar.paylibs.print.PaperRollStatusCallback; import com.utsmyanmar.paylibs.print.PrintHelper; import com.utsmyanmar.paylibs.print.printx.PrintXStatus; import com.utsmyanmar.paylibs.utils.PrintStatus; +import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; import com.utsmm.kbz.BR; @@ -423,10 +425,23 @@ public class TransactionResultFragment extends DataBindingFragment implements Da return ECRProcess.INSTANCE.generateECRResponse(resp); } + private byte[] getECRResponseCMHL() { + return CoreUtils.getInstance(sharedViewModel).generateCMHLResponse(ECRResultStatus.RESPONSE_RECEIVED); + } private void ecrAction() { - LogUtil.d(TAG,"ECR Response :"+getECRResponseMessage()); - ECRHelper.INSTANCE.send(getECRResponseMessage().getBytes()); + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + LogUtil.d(TAG,"ECR Response :"+ ByteUtil.bytes2HexStr(getECRResponseCMHL())); + + ECRHelper.INSTANCE.send(getECRResponseCMHL()); + + + } else { + LogUtil.d(TAG,"ECR Response :"+getECRResponseMessage()); + + ECRHelper.INSTANCE.send(getECRResponseMessage().getBytes()); + } + ECRHelper.INSTANCE.setOnBindSuccess(() -> { LogUtil.d(TAG, "Send Success!"); @@ -435,6 +450,7 @@ public class TransactionResultFragment extends DataBindingFragment implements Da } + @Override public void onBackPress() { isCardInside(); diff --git a/app/src/main/java/com/utsmm/kbz/ui/kpay/QRConnectingFragment.java b/app/src/main/java/com/utsmm/kbz/ui/kpay/QRConnectingFragment.java index c5128f6..20d3e10 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/kpay/QRConnectingFragment.java +++ b/app/src/main/java/com/utsmm/kbz/ui/kpay/QRConnectingFragment.java @@ -7,6 +7,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.github.gcacace.signaturepad.BR; +import com.kizzy.cmhl.EcrManager; +import com.kizzy.cmhl.models.QrPaymentResponse; import com.utsmyanmar.baselib.fragment.DataBindingFragment; import com.utsmyanmar.baselib.network.model.DemoQRRequest; import com.utsmyanmar.baselib.network.model.KPayQRRequest; @@ -17,7 +19,9 @@ import com.utsmyanmar.ecr.ECRProcess; import com.utsmyanmar.ecr.data.model.TransactionsResp; import com.utsmyanmar.paylibs.model.PayDetail; import com.utsmyanmar.paylibs.model.TradeData; +import com.utsmyanmar.paylibs.system.SystemDateTime; import com.utsmyanmar.paylibs.utils.POSUtil; +import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; import com.utsmm.kbz.R; import com.utsmm.kbz.config.Constants; @@ -220,8 +224,11 @@ public class QRConnectingFragment extends DataBindingFragment implements DataBin private void ecrAction() { - LogUtil.d(TAG,"ECR Response :"+getECRResponseMessage()); - ECRHelper.INSTANCE.send(getECRResponseMessage().getBytes()); + if(!SystemParamsOperation.getInstance().isCMHLEnabled()) { + LogUtil.d(TAG,"ECR Response :"+getECRResponseMessage()); + ECRHelper.INSTANCE.send(getECRResponseMessage().getBytes()); + } + ECRHelper.INSTANCE.setOnBindSuccess(() -> { LogUtil.d(TAG, "Send Success!"); @@ -237,7 +244,14 @@ public class QRConnectingFragment extends DataBindingFragment implements DataBin private void finishECR() { sharedViewModel.isEcr.postValue(false); - CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans)); + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + ECRHelper.INSTANCE.send(generateCHMLResponse()); + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + } else { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans)); + } + sharedViewModel.isEcrFinished.postValue(true); } @@ -246,8 +260,15 @@ public class QRConnectingFragment extends DataBindingFragment implements DataBin if (sharedViewModel.isEcr.getValue()) { sharedViewModel.isEcr.postValue(false); - CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg); sharedViewModel.isEcrFinished.postValue(true); + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + ECRHelper.INSTANCE.send(generateCHMLResponse()); + + CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + } else { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg); + } + } } } @@ -261,6 +282,16 @@ public class QRConnectingFragment extends DataBindingFragment implements DataBin return ECRProcess.INSTANCE.generateECRResponse(resp); } + private byte[] generateCHMLResponse() { + QrPaymentResponse qrPaymentResponse = new QrPaymentResponse.Builder() + .setResponseCode("FF") + .setTime(SystemDateTime.getHHmmss()) + .setDate(SystemDateTime.getMMDD()) + .build(); + + return EcrManager.buildPacket(qrPaymentResponse); + } + @Override public void onBackPress() { if (sharedViewModel.isEcr.getValue() != null) { diff --git a/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java b/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java index 7a490ed..39aba37 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java +++ b/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java @@ -9,6 +9,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.kizzy.cmhl.EcrManager; +import com.kizzy.cmhl.models.QrPaymentResponse; import com.utsmm.kbz.util.EReceiptUtil; import com.utsmm.kbz.util.enums.TransResultStatus; import com.utsmyanmar.baselib.fragment.DataBindingFragment; @@ -21,6 +23,7 @@ import com.utsmyanmar.ecr.ECRHelper; import com.utsmyanmar.ecr.ECRProcess; import com.utsmyanmar.ecr.data.model.TransactionsResp; import com.utsmyanmar.paylibs.model.PayDetail; +import com.utsmyanmar.paylibs.system.SystemDateTime; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmm.kbz.R; import com.utsmm.kbz.BR; @@ -163,8 +166,24 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi private void finishECR() { sharedViewModel.isEcr.postValue(false); - CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans)); sharedViewModel.isEcrFinished.postValue(true); + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + ECRHelper.INSTANCE.send(generateCHMLResponse()); + +// CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + } else { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans)); + } + } + + private byte[] generateCHMLResponse() { + QrPaymentResponse qrPaymentResponse = new QrPaymentResponse.Builder() + .setResponseCode("FF") + .setTime(SystemDateTime.getHHmmss()) + .setDate(SystemDateTime.getMMDD()) + .build(); + + return EcrManager.buildPacket(qrPaymentResponse); } private void ecrActionCancel(String msg) { @@ -476,6 +495,8 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi ); } + + private String getECRResponseMessage() { sharedViewModel.payDetail.setValue(payDetail); @@ -485,7 +506,6 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi return ECRProcess.INSTANCE.generateECRResponse(resp); } - private void ecrAction() { LogUtil.d(TAG, "ECR Response :" + getECRResponseMessage()); diff --git a/app/src/main/java/com/utsmm/kbz/ui/pinpad/PinPadFragment.java b/app/src/main/java/com/utsmm/kbz/ui/pinpad/PinPadFragment.java index 349a318..d430656 100644 --- a/app/src/main/java/com/utsmm/kbz/ui/pinpad/PinPadFragment.java +++ b/app/src/main/java/com/utsmm/kbz/ui/pinpad/PinPadFragment.java @@ -9,12 +9,14 @@ import androidx.annotation.Nullable; import androidx.lifecycle.Observer; +import com.utsmm.kbz.util.ecr.ECRResultStatus; import com.utsmyanmar.baselib.fragment.DataBindingFragment; import com.utsmyanmar.baselib.util.DataBindingConfig; //import com.utsmyanmar.mpulib.readcard.ReadCardProcess; import com.utsmyanmar.checkxread.sdk.NexGoSDK; +import com.utsmyanmar.ecr.ECRHelper; import com.utsmyanmar.paylibs.model.PayDetail; import com.utsmyanmar.paylibs.model.TradeData; import com.utsmyanmar.paylibs.utils.POSUtil; @@ -27,6 +29,7 @@ import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel; import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel; import com.utsmm.kbz.util.ecr.CoreUtils; import com.utsmm.kbz.util.enums.PinPadStatus; +import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; public class PinPadFragment extends DataBindingFragment { @@ -157,13 +160,27 @@ public class PinPadFragment extends DataBindingFragment { }); } + private byte[] getECRResponseCMHL() { + return CoreUtils.getInstance(sharedViewModel).generateCMHLResponse(ECRResultStatus.USER_CANCEL); + } private void ecrActionCancel(String msg) { if (sharedViewModel.isEcr.getValue() != null) { if (sharedViewModel.isEcr.getValue()) { sharedViewModel.isEcr.postValue(false); - CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg); + + sharedViewModel.payDetail.setValue(pinPadViewModel.getPayDetail()); + sharedViewModel.isEcrFinished.postValue(true); + + if(SystemParamsOperation.getInstance().isCMHLEnabled()) { + ECRHelper.INSTANCE.send(getECRResponseCMHL()); + +// CoreUtils.getInstance(sharedViewModel).responseACKCMHL(); + } else { + CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg); + } + } } } diff --git a/app/src/main/java/com/utsmm/kbz/util/TransactionUtil.java b/app/src/main/java/com/utsmm/kbz/util/TransactionUtil.java index 35e0a8e..73b32c4 100644 --- a/app/src/main/java/com/utsmm/kbz/util/TransactionUtil.java +++ b/app/src/main/java/com/utsmm/kbz/util/TransactionUtil.java @@ -6,6 +6,7 @@ import com.utsmyanmar.paylibs.model.CardInfo; import com.utsmyanmar.paylibs.model.MAGCardInfo; import com.utsmyanmar.paylibs.model.PayDetail; import com.utsmyanmar.paylibs.model.TradeData; +import com.utsmyanmar.paylibs.model.enums.TransCVM; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; import com.utsmyanmar.paylibs.utils.params.Params; @@ -98,7 +99,7 @@ public class TransactionUtil { PayDetail payDetail = tradeData.getPayDetail(); payDetail.setCardNo(cardDataX.getPan()); payDetail.setEXPDate(cardDataX.getExp()); - + payDetail.setTransCVM(TransCVM.SIGNATURE); if(cardDataX.getPan().startsWith("4")) { payDetail.setAccountType(VISA_CARD_SCHEME); } else if(cardDataX.getPan().startsWith("5")) { diff --git a/app/src/main/java/com/utsmm/kbz/util/ecr/CoreUtils.java b/app/src/main/java/com/utsmm/kbz/util/ecr/CoreUtils.java index e5e6666..17716f5 100644 --- a/app/src/main/java/com/utsmm/kbz/util/ecr/CoreUtils.java +++ b/app/src/main/java/com/utsmm/kbz/util/ecr/CoreUtils.java @@ -4,12 +4,30 @@ import android.annotation.SuppressLint; import android.text.TextUtils; import android.util.Log; +import com.kizzy.cmhl.EcrManager; +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.PreAuthCompletionResponse; +import com.kizzy.cmhl.models.PreAuthRequest; +import com.kizzy.cmhl.models.PreAuthResponse; +import com.kizzy.cmhl.models.QrPaymentRequest; +import com.kizzy.cmhl.models.QrPaymentResponse; +import com.kizzy.cmhl.models.SaleRequest; +import com.kizzy.cmhl.models.SaleResponse; +import com.kizzy.cmhl.models.SettlementRequest; +import com.kizzy.cmhl.models.SettlementResponse; +import com.kizzy.cmhl.models.VoidQrPaymentRequest; +import com.kizzy.cmhl.models.VoidRequest; +import com.kizzy.cmhl.models.VoidResponse; import com.utsmyanmar.ecr.ECRHelper; import com.utsmyanmar.ecr.ECRProcess; import com.utsmyanmar.ecr.data.RespType; import com.utsmyanmar.ecr.data.model.Transactions; import com.utsmyanmar.ecr.data.model.TransactionsResp; import com.utsmyanmar.paylibs.model.PayDetail; +import com.utsmyanmar.paylibs.system.SystemDateTime; import com.utsmyanmar.paylibs.utils.POSUtil; import com.utsmyanmar.paylibs.utils.enums.TransMenu; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; @@ -25,7 +43,7 @@ import com.utsmyanmar.paylibs.utils.LogUtil; //@Keep -public class CoreUtils implements OldECRSetups,ECRSetups { +public class CoreUtils implements OldECRSetups,ECRSetups,ECRSetupsCMHL { private static final String TAG = CoreUtils.class.getSimpleName(); @@ -166,7 +184,9 @@ public class CoreUtils implements OldECRSetups,ECRSetups { return resp; } - + public void responseACKCMHL() { + ECRHelper.INSTANCE.send(new byte[]{0x06}); + } public void responseRejectMsg(String actionName) { @@ -215,6 +235,183 @@ public class CoreUtils implements OldECRSetups,ECRSetups { ECRResponseAction(msg); } + @Override + public void setupPingRequest(PingRequest trans) { + PingResponse pingResponse = new PingResponse.Builder() + .setResponseCode("00") + .build(); + + byte[] packet = EcrManager.buildPacket(pingResponse); + ECRHelper.INSTANCE.send(packet); + } + + @Override + public boolean setUpECRSale(SaleRequest trans) { + try{ + + LogUtil.d(TAG, "amount is "+trans.getAmount()); + if (trans.getAmount() == null && Long.parseLong(trans.getAmount()) <= 0) { + + LogUtil.d(TAG,"Amount field is invalid!"); + return false; + } + +// int amount = reduceTrailingZeros(trans.getAMT()); + + long amount = Long.parseLong(trans.getAmount()); + + sharedViewModel.isEcrFinished.postValue(false); + sharedViewModel.isEcr.postValue(true); + sharedViewModel.amount.postValue(String.valueOf(amount)); + sharedViewModel.transactionsType.postValue(TransactionsType.SALE); + sharedViewModel.processCode.postValue(ProcessCode.SALE_PURCHASE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT); + return true; + }catch (Exception e){ + return false; + } + } + + @Override + public boolean setUpECRQR(QrPaymentRequest trans) { + try{ + + LogUtil.d(TAG, "amount is "+trans.getAmount()); + if (trans.getAmount() == null && Long.parseLong(trans.getAmount()) <= 0) { + + LogUtil.d(TAG,"Amount field is invalid!"); + return false; + } + + long amount = Long.parseLong(trans.getAmount()); + + sharedViewModel.isEcrFinished.postValue(false); + sharedViewModel.isEcr.postValue(true); + sharedViewModel.amount.postValue(String.valueOf(amount)); + sharedViewModel.transactionsType.postValue(TransactionsType.MMQR); + return true; + }catch (Exception e){ + return false; + } + } + + @Override + public boolean setUpECRQRVoid(VoidQrPaymentRequest trans) { + return false; + } + + @Override + public boolean setUpECRVoid(VoidRequest trans) { + try{ + if (trans.getInvoiceNumber()== null && trans.getInvoiceNumber().isEmpty()) { + LogUtil.d(TAG,"Trace field is invalid!"); + return false; + } + + sharedViewModel.isEcrFinished.postValue(false); + sharedViewModel.isEcr.postValue(true); + sharedViewModel.traceNo.postValue(trans.getInvoiceNumber()); + sharedViewModel.transactionName.postValue("SALE"); + sharedViewModel.transactionsType.postValue(TransactionsType.VOID); + sharedViewModel.processCode.postValue(ProcessCode.SALE_VOID + ProcessCode.SMART + ProcessCode.TO_ACCOUNT); + return true; + }catch (Exception e){ + return false; + } + } + + @Override + public boolean setUpECRPreAuth(PreAuthRequest trans) { + try{ + + LogUtil.d(TAG, "amount is "+trans.getAmount()); + if (trans.getAmount() == null && Long.parseLong(trans.getAmount()) <= 0) { + + LogUtil.d(TAG,"Amount field is invalid!"); + return false; + } + +// int amount = reduceTrailingZeros(trans.getAMT()); + + long amount = Long.parseLong(trans.getAmount()); + + sharedViewModel.isEcrFinished.postValue(false); + sharedViewModel.isEcr.postValue(true); + sharedViewModel.amount.postValue(String.valueOf(amount)); + sharedViewModel.transactionsType.postValue(TransactionsType.PRE_AUTH_SALE); + sharedViewModel.processCode.postValue(ProcessCode.PRE_AUTH_SALE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT); + return true; + }catch (Exception e){ + return false; + } + } + + @Override + public boolean setUpECRPreAuthVoid(PreAuthCancellationRequest trans) { + try{ + + LogUtil.d(TAG, "approval code is "+trans.getApprovalCode()); + LogUtil.d(TAG, "reference num is "+trans.getApprovalCode()); + if (trans.getApprovalCode() == null ) { + + LogUtil.d(TAG,"Amount field is invalid!"); + return false; + } + +// int amount = reduceTrailingZeros(trans.getAMT()); + + String approval = trans.getApprovalCode(); + String rrn = trans.getReferenceNumber(); + String cardType = trans.getCardType(); + + sharedViewModel.isEcrFinished.postValue(false); + sharedViewModel.isEcr.postValue(true); + sharedViewModel.rrNNo.postValue(rrn); + sharedViewModel.approvalCode.postValue(approval); + + sharedViewModel.transactionsType.postValue(TransactionsType.PRE_AUTH_VOID); + sharedViewModel.processCode.postValue(ProcessCode.PRE_AUTH_VOID + ProcessCode.SMART + ProcessCode.TO_ACCOUNT); + return true; + }catch (Exception e){ + return false; + } + } + + @Override + public boolean setUpECRPreAuthComplete(PreAuthCompletionRequest trans) { + try{ + + LogUtil.d(TAG, "approval code is "+trans.getApprovalCode()); + LogUtil.d(TAG, "reference num is "+trans.getApprovalCode()); + if (trans.getApprovalCode() == null ) { + + LogUtil.d(TAG,"Amount field is invalid!"); + return false; + } + +// int amount = reduceTrailingZeros(trans.getAMT()); + + String approval = trans.getApprovalCode(); + String rrn = trans.getReferenceNumber(); + String cardType = trans.getCardType(); + + sharedViewModel.isEcrFinished.postValue(false); + sharedViewModel.isEcr.postValue(true); + sharedViewModel.rrNNo.postValue(rrn); + sharedViewModel.approvalCode.postValue(approval); + + sharedViewModel.transactionsType.postValue(TransactionsType.PRE_AUTH_COMPLETE); + sharedViewModel.processCode.postValue(ProcessCode.PRE_AUTH_COMPLETE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT); + return true; + }catch (Exception e){ + return false; + } + } + + @Override + public void setUpECRSettlement(SettlementRequest trans) { + + } + @Override public boolean setUpECRSale(Transactions trans) { @@ -661,4 +858,219 @@ public class CoreUtils implements OldECRSetups,ECRSetups { sharedViewModel.processCode.postValue(ProcessCode.REFUND + ProcessCode.SMART + ProcessCode.TO_ACCOUNT); return true; } + + public byte[] generateCMHLResponse(ECRResultStatus ecrResultStatus) { + Transactions trans = sharedViewModel.ecrTrans.getValue(); + PayDetail payDetail = sharedViewModel.payDetail.getValue(); + TransactionsType transactionsType = sharedViewModel.transactionsType.getValue(); + + boolean isApproved = false; + + if(payDetail.getTradeAnswerCode() != null) { + isApproved = TextUtils.equals(payDetail.getTradeAnswerCode(),"000") || TextUtils.equals(payDetail.getTradeAnswerCode(),"00"); + } +// boolean isApproved = TextUtils.equals(payDetail.getTradeAnswerCode(),"000") || TextUtils.equals(payDetail.getTradeAnswerCode(),"00"); + + byte[] responsePacket; + switch (transactionsType) { + case SALE: + SaleResponse response; + if(ecrResultStatus == ECRResultStatus.RESPONSE_RECEIVED) { + + + if (isApproved) { + response = new SaleResponse.Builder() + .setResponseCode(POSUtil.getInstance().responseCodeConverter(payDetail.getTradeAnswerCode())) + .setAmount(POSUtil.getInstance().formatAmount(payDetail.getAmount())) + .setPan(payDetail.getCardNo()) + .setExpDate(payDetail.getEXPDate()) + .setTid(payDetail.getTerminalNo()) + .setMid(payDetail.getMerchantNo()) + .setTime(SystemDateTime.getHHmmss()) // for urgent testing purpose + .setDate(payDetail.getTradeDate()) + .setReferenceNum(payDetail.getReferNo()) + .setApprovalCode(payDetail.getApprovalCode()) + .setInvoiceNumber(payDetail.getInvoiceNo()) + .setStan(payDetail.getVoucherNo()) + .setEntry(POSUtil.getInstance().getEntryCode(payDetail)) + .setCardType(POSUtil.getInstance().getCardType(payDetail)) + .setCurrency(payDetail.getCurrencyCode()) + .build(); + } else { + response = new SaleResponse.Builder() + .setResponseCode(POSUtil.getInstance().responseCodeConverter(payDetail.getTradeAnswerCode())) + .setTime(SystemDateTime.getHHmmss()) + .setDate(payDetail.getTradeDate()) + .build(); + } + } else if(ecrResultStatus == ECRResultStatus.USER_CANCEL){ + + response = new SaleResponse.Builder() + .setResponseCode("FF") + .setTime(SystemDateTime.getHHmmss()) + .setDate(payDetail.getTradeDate()) + .build(); + } else { + response = new SaleResponse.Builder() + .setResponseCode("FF") + .setTime(SystemDateTime.getHHmmss()) + .setDate(payDetail.getTradeDate()) + .build(); + } + + responsePacket = EcrManager.buildPacket(response); + break; + case VOID: + VoidResponse voidResponse; + if(ecrResultStatus == ECRResultStatus.RESPONSE_RECEIVED) { + if (isApproved) { + voidResponse = new VoidResponse.Builder() + .setResponseCode(POSUtil.getInstance().responseCodeConverter(payDetail.getTradeAnswerCode())) + .setAmount(POSUtil.getInstance().formatAmount(payDetail.getAmount())) + .setVoucherNumber(payDetail.getVoucherNo()) + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .setApprovalCode(payDetail.getApprovalCode()) + .setReferenceNum(payDetail.getReferNo()) + .setTid(payDetail.getTerminalNo()) + .setMid(payDetail.getMerchantNo()) + .setEntry(POSUtil.getInstance().getEntryCode(payDetail)) + .build(); + } else { + voidResponse = new VoidResponse.Builder() + .setResponseCode(POSUtil.getInstance().responseCodeConverter(payDetail.getTradeAnswerCode())) + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .build(); + } + } else if (ecrResultStatus == ECRResultStatus.USER_CANCEL) { + voidResponse = new VoidResponse.Builder() + .setResponseCode("FF") + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .build(); + } else { + voidResponse = new VoidResponse.Builder() + .setResponseCode("NR") + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .build(); + } + + + responsePacket = EcrManager.buildPacket(voidResponse); + break; + case SETTLEMENT: + SettlementResponse settlementResponse = new SettlementResponse.Builder() + .setResponseCode(POSUtil.getInstance().responseCodeConverter(payDetail.getTradeAnswerCode())) + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .setTid(payDetail.getTerminalNo()) + .setMid(payDetail.getMerchantNo()) + .build(); + responsePacket = EcrManager.buildPacket(settlementResponse); + break; + case MMQR: + QrPaymentResponse qrPaymentRequest; + if(payDetail.getQrTransStatus() == 1) { + qrPaymentRequest = new QrPaymentResponse.Builder() + .setResponseCode("00") + .setAmount(POSUtil.getInstance().formatAmount(payDetail.getAmount())) + .setPan("0000000000000000000") + .setExpDate("0000") + .setTid(payDetail.getTerminalNo()) + .setMid(payDetail.getMerchantNo()) + .setTime(SystemDateTime.getHHmmss()) + .setDate(payDetail.getTradeDate()) + .setApprovalCode(payDetail.getQrTransId().substring(2,8)) + .setRrn(payDetail.getQrReferNo()) + .setPosEntryMode("000") + .setInvoiceNumber(payDetail.getInvoiceNo()) + .setStan(payDetail.getVoucherNo()) + .setPaymentType(payDetail.getCustomerMobile()) + .setCurrencyCode(payDetail.getCurrencyCode()) + .build(); + } else { + qrPaymentRequest = new QrPaymentResponse.Builder() + .setResponseCode("05") + .setTime(SystemDateTime.getHHmmss()) + .setDate(payDetail.getTradeDate()) + .build(); + } + + responsePacket = EcrManager.buildPacket(qrPaymentRequest); + break; +// case WAVEPAY_REFUND: +// break; + case PRE_AUTH_SALE: + PreAuthResponse preAuthResponse; + if(isApproved) { + preAuthResponse = new PreAuthResponse.Builder() + .setResponseCode(payDetail.getTradeAnswerCode()) + .setAmount(POSUtil.getInstance().formatAmount(payDetail.getAmount())) + .setPan(payDetail.getCardNo()) + .setTid(payDetail.getTerminalNo()) + .setMid(payDetail.getMerchantNo()) + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .setApprovalCode(payDetail.getApprovalCode()) + .setInvoiceNumber(payDetail.getInvoiceNo()) + .setStan(payDetail.getVoucherNo()) + .setRrn(payDetail.getReferNo()) + .setEntry(POSUtil.getInstance().getEntryCode(payDetail)) + .setCardType(POSUtil.getInstance().getCardType(payDetail)) + .build(); + } else { + preAuthResponse = new PreAuthResponse.Builder() + .setResponseCode(payDetail.getTradeAnswerCode()) + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .build(); + } + + responsePacket = EcrManager.buildPacket(preAuthResponse); + break; + case PRE_AUTH_COMPLETE: + PreAuthCompletionResponse preAuthCompletionResponse; + if(isApproved) { + preAuthCompletionResponse = new PreAuthCompletionResponse.Builder() + .setResponseCode(payDetail.getTradeAnswerCode()) + .setAmount(POSUtil.getInstance().formatAmount(payDetail.getAmount())) + .setPan(payDetail.getCardNo()) + .setTid(payDetail.getTerminalNo()) + .setMid(payDetail.getMerchantNo()) + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .setApprovalCode(payDetail.getApprovalCode()) + .setInvoiceNumber(payDetail.getInvoiceNo()) + .setStan(payDetail.getVoucherNo()) + .setRrn(payDetail.getReferNo()) + .setEntry(POSUtil.getInstance().getEntryCode(payDetail)) + .build(); + } else { + preAuthCompletionResponse = new PreAuthCompletionResponse.Builder() + .setResponseCode(payDetail.getTradeAnswerCode()) + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .build(); + } + + responsePacket = EcrManager.buildPacket(preAuthCompletionResponse); + break; + default: + SaleResponse saleResponses = new SaleResponse.Builder() + .setResponseCode(payDetail.getTradeAnswerCode()) + .setTime(payDetail.getTradeTime()) + .setDate(payDetail.getTradeDate()) + .build(); + + + responsePacket = EcrManager.buildPacket(saleResponses); + break; + } + + + return responsePacket; + + } } diff --git a/app/src/main/java/com/utsmm/kbz/util/ecr/ECRResultStatus.java b/app/src/main/java/com/utsmm/kbz/util/ecr/ECRResultStatus.java new file mode 100644 index 0000000..693eae3 --- /dev/null +++ b/app/src/main/java/com/utsmm/kbz/util/ecr/ECRResultStatus.java @@ -0,0 +1,12 @@ +package com.utsmm.kbz.util.ecr; + +public enum ECRResultStatus { + + + USER_CANCEL, + TIME_OUT, + + RESPONSE_RECEIVED + + +} diff --git a/app/src/main/java/com/utsmm/kbz/util/ecr/ECRSetupsCMHL.java b/app/src/main/java/com/utsmm/kbz/util/ecr/ECRSetupsCMHL.java new file mode 100644 index 0000000..a0afd10 --- /dev/null +++ b/app/src/main/java/com/utsmm/kbz/util/ecr/ECRSetupsCMHL.java @@ -0,0 +1,35 @@ +package com.utsmm.kbz.util.ecr; + + +import com.kizzy.cmhl.models.PingRequest; +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.SettlementRequest; +import com.kizzy.cmhl.models.VoidQrPaymentRequest; +import com.kizzy.cmhl.models.VoidRequest; + +public interface ECRSetupsCMHL { + + void setUpECREchoTest(); + + void setupPingRequest(PingRequest trans); + + boolean setUpECRSale(SaleRequest trans); + + boolean setUpECRQR(QrPaymentRequest trans); + boolean setUpECRQRVoid(VoidQrPaymentRequest trans); + + boolean setUpECRVoid(VoidRequest trans); + + boolean setUpECRPreAuth(PreAuthRequest trans); + + boolean setUpECRPreAuthVoid(PreAuthCancellationRequest trans); + + boolean setUpECRPreAuthComplete(PreAuthCompletionRequest trans); + + void setUpECRSettlement(SettlementRequest trans); + +} diff --git a/app/src/main/java/com/utsmm/kbz/util/tms/TMSSetupsImpl.java b/app/src/main/java/com/utsmm/kbz/util/tms/TMSSetupsImpl.java index e3d9e11..a789467 100644 --- a/app/src/main/java/com/utsmm/kbz/util/tms/TMSSetupsImpl.java +++ b/app/src/main/java/com/utsmm/kbz/util/tms/TMSSetupsImpl.java @@ -649,6 +649,8 @@ public class TMSSetupsImpl implements TMSSetups{ } else if(TextUtils.equals(name, "printer_enabled")){ SystemParamsOperation.getInstance().setPrinterEnabled(parseBoolean(data)); + } else if (TextUtils.equals(name,"cmhl_enabled")) { + SystemParamsOperation.getInstance().setCMHLEnable(parseBoolean(data)); } } diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/viewModel/EmvBaseViewModel.java b/baselib/src/main/java/com/utsmyanmar/baselib/viewModel/EmvBaseViewModel.java index 4d31828..f836b2c 100644 --- a/baselib/src/main/java/com/utsmyanmar/baselib/viewModel/EmvBaseViewModel.java +++ b/baselib/src/main/java/com/utsmyanmar/baselib/viewModel/EmvBaseViewModel.java @@ -316,8 +316,8 @@ public abstract class EmvBaseViewModel extends BaseViewModel { return; } try { - LogUtil.d(TAG, "Selected :" + position); - emvHandler.onSetSelAppResponse(position); + LogUtil.d(TAG, "Selected :" + position+1); + emvHandler.onSetSelAppResponse(position+1); } catch (Exception e) { LogUtil.e(TAG, "Exception during app selection: " + e.getMessage()); e.printStackTrace(); @@ -751,6 +751,10 @@ public abstract class EmvBaseViewModel extends BaseViewModel { byte[] tlv_50 = emvHandler.getTlv(new byte[]{(byte) 0x50}, EmvDataSourceEnum.FROM_KERNEL); LogUtil.d(TAG, "tlv_50--" + ByteUtils.byteArray2HexString(tlv_50)); + byte[] tlv_9B = emvHandler.getTlv(new byte[]{(byte) 0x9B}, EmvDataSourceEnum.FROM_KERNEL); + LogUtil.d(TAG, "tlv_9B--" + ByteUtils.byteArray2HexString(tlv_9B)); + + switch (retCode) { case SdkResult.Emv_Success_Arpc_Fail: case SdkResult.Success: diff --git a/ecr/build.gradle b/ecr/build.gradle index 1892cc1..3a52af9 100644 --- a/ecr/build.gradle +++ b/ecr/build.gradle @@ -34,7 +34,7 @@ dependencies { // implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.appcompat:appcompat:1.3.1' - + 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') diff --git a/ecr/src/main/java/com/utsmyanmar/ecr/ECRHelper.kt b/ecr/src/main/java/com/utsmyanmar/ecr/ECRHelper.kt index 3e6ce3e..c24cf8d 100644 --- a/ecr/src/main/java/com/utsmyanmar/ecr/ECRHelper.kt +++ b/ecr/src/main/java/com/utsmyanmar/ecr/ECRHelper.kt @@ -1,19 +1,25 @@ package com.utsmyanmar.ecr +import android.content.Context import android.os.Bundle import android.widget.Toast +import com.nexgo.oaf.apiv3.APIProxy +import com.nexgo.oaf.apiv3.SdkResult +import com.nexgo.oaf.apiv3.device.serialport.SerialCfgEntity +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 java.nio.charset.StandardCharsets - object ECRHelper { val TAG = ECRHelper::class.java.simpleName private var ecrService: ECRService? = null + private var serialPort: SerialPortDriver? = null var onBindSuccess: () -> Unit = { } var onBindFailure: () -> Unit = { } @@ -26,6 +32,70 @@ object ECRHelper { var onECRReceive: (bytes: ByteArray) -> Unit = { } + // ─── Serial Port Init (call this once, e.g. in Application or Activity) ─── + + fun initSerialPort(context: Context) { + try { + val deviceEngine = APIProxy.getDeviceEngine(context) + val port = deviceEngine.getSerialPortDriver(0) + + val entity = SerialCfgEntity().apply { + baudRate = 115200 + dataBits = 8 + parity = 'n' + stopBits = 1 + } + + val result = port.connect(entity) + if (result == SdkResult.Success) { + serialPort = port + LogUtil.d(TAG, "USB Serial connected") + } else { + LogUtil.e(TAG, "USB Serial connect failed: $result") + onSendFailure(result, "Serial port connect failed") + } + } catch (ex: Throwable) { + ex.printStackTrace() + 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) { + try { + val port = serialPort + if (port != null) { + val result = port.send(bytes, bytes.size) + if (result == SdkResult.Success) { + LogUtil.d(TAG, "Serial send success") + onSendSuccess() + } else { + LogUtil.e(TAG, "Serial send failed: $result") + onSendFailure(result, "Serial send failed") + } + } else { + LogUtil.e(TAG, "Serial port not initialized") + onSendFailure(-100, "Serial port not initialized") + } + } catch (ex: Throwable) { + ex.printStackTrace() + onSendFailure(-200, ex.localizedMessage ?: "") + } + } + + // ─── Everything below is unchanged ──────────────────────────────────────── + fun connect(bundle: Bundle) { call { anyExecute(ecrService) { @@ -51,59 +121,39 @@ object ECRHelper { } private val ecrListener = object : ECRListener.Stub() { - - override fun onReceive(byteArray: ByteArray ? ) { + override fun onReceive(byteArray: ByteArray?) { if (byteArray != null) { val string = String(byteArray, StandardCharsets.UTF_8) Logger.e(TAG, "onReceive string: $string") onECRReceive(byteArray) } } - - } - - fun send(bytes: ByteArray) { - try { - val bridgeService = ecrService - if (bridgeService != null) { - bridgeService.send(bytes, requestCallback) - } else { - onECRDisconnected(-100, "The bind ECRService failure") - } - } catch (ex: Throwable) { - ex.printStackTrace() - onSendFailure(-200, ex.localizedMessage ?: "") - } } private val requestCallback = object : ECRRequestCallback.Stub() { - override fun onSuccess() { Logger.e(TAG, "onSuccess") onSendSuccess() } - override fun onFailure(code: Int, massage: String ? ) { + 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 ? ) { + override fun onDisconnected(code: Int, massage: String?) { Logger.d(TAG, "onDisconnected code: $code massage: $massage") ECRUtil.connected = false onECRDisconnected(code, massage ?: "failure") } - } fun bindECRService() { @@ -111,7 +161,6 @@ object ECRHelper { } private val connectionCallback = object : ECRServiceKernel.ConnectionCallback { - override fun onServiceConnected() { Logger.e(TAG, "onServiceConnected") ecrService = ECRServiceKernel.getInstance().ecrService @@ -124,7 +173,6 @@ object ECRHelper { ecrService = null onBindFailure() } - } private fun call(block: () -> Unit) { @@ -140,5 +188,4 @@ object ECRHelper { onECRDisconnected(-200, ex.localizedMessage ?: "") } } - } \ No newline at end of file diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/system/BaseErrorCode.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/system/BaseErrorCode.java index 3ccde43..ff14658 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/system/BaseErrorCode.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/system/BaseErrorCode.java @@ -9,7 +9,64 @@ import java.util.Map; public class BaseErrorCode { + private static final Map ISO_93_TO_87_MAP = new HashMap<>(); + static { + // --- APPROVALS (000-099) --- + ISO_93_TO_87_MAP.put("000", "00"); // Approved + ISO_93_TO_87_MAP.put("001", "08"); // Honour with identification + ISO_93_TO_87_MAP.put("002", "10"); // Approved for partial amount + ISO_93_TO_87_MAP.put("003", "11"); // Approved (VIP) + ISO_93_TO_87_MAP.put("004", "16"); // Approved, update track 3 + ISO_93_TO_87_MAP.put("007", "00"); // Approved, update ICC (Map to 00 generic) + + // --- DECLINES: No Pickup (100-199) --- + ISO_93_TO_87_MAP.put("100", "05"); // Do not honour + ISO_93_TO_87_MAP.put("101", "54"); // Expired card (Standard 87 code is 54, sometimes 33) + ISO_93_TO_87_MAP.put("102", "59"); // Suspected fraud + ISO_93_TO_87_MAP.put("103", "60"); // Card acceptor contact acquirer + ISO_93_TO_87_MAP.put("104", "62"); // Restricted card + ISO_93_TO_87_MAP.put("105", "66"); // Call security + ISO_93_TO_87_MAP.put("106", "75"); // PIN tries exceeded (Also 38 in v87) + ISO_93_TO_87_MAP.put("107", "01"); // Refer to card issuer + ISO_93_TO_87_MAP.put("108", "02"); // Refer to special conditions + ISO_93_TO_87_MAP.put("109", "03"); // Invalid merchant + ISO_93_TO_87_MAP.put("110", "13"); // Invalid amount + ISO_93_TO_87_MAP.put("111", "14"); // Invalid card number + ISO_93_TO_87_MAP.put("112", "06"); // PIN required (Generic Error 06 mapped) + ISO_93_TO_87_MAP.put("114", "39"); // No account of type requested (No credit account) + ISO_93_TO_87_MAP.put("115", "40"); // Requested function not supported + ISO_93_TO_87_MAP.put("116", "51"); // Not sufficient funds + ISO_93_TO_87_MAP.put("117", "55"); // Incorrect PIN + ISO_93_TO_87_MAP.put("118", "56"); // No card record + ISO_93_TO_87_MAP.put("119", "57"); // Transaction not permitted to cardholder + ISO_93_TO_87_MAP.put("120", "58"); // Transaction not permitted to terminal + ISO_93_TO_87_MAP.put("121", "61"); // Exceeds withdrawal amount limit + ISO_93_TO_87_MAP.put("122", "63"); // Security violation + ISO_93_TO_87_MAP.put("123", "65"); // Exceeds withdrawal frequency limit + ISO_93_TO_87_MAP.put("125", "12"); // Card not effective (Mapped to Invalid Transaction) + ISO_93_TO_87_MAP.put("129", "59"); // Suspected counterfeit (Mapped to Suspected Fraud) + + // --- DECLINES: Pickup Required (200-299) --- + ISO_93_TO_87_MAP.put("200", "04"); // Do not honour (Pickup) -> 04 Pick-up + ISO_93_TO_87_MAP.put("201", "33"); // Expired card (Pickup) -> 33 Expired + ISO_93_TO_87_MAP.put("202", "34"); // Suspected fraud (Pickup) -> 34 Suspected Fraud + ISO_93_TO_87_MAP.put("203", "35"); // Contact acquirer (Pickup) + ISO_93_TO_87_MAP.put("204", "36"); // Restricted card (Pickup) + ISO_93_TO_87_MAP.put("208", "41"); // Lost card + ISO_93_TO_87_MAP.put("209", "43"); // Stolen card + + // --- SYSTEM ERRORS (900-999) --- + ISO_93_TO_87_MAP.put("902", "12"); // Invalid transaction + ISO_93_TO_87_MAP.put("903", "19"); // Re-enter transaction + ISO_93_TO_87_MAP.put("904", "30"); // Format error + ISO_93_TO_87_MAP.put("907", "91"); // Issuer or switch inoperative + ISO_93_TO_87_MAP.put("908", "92"); // Router not found + ISO_93_TO_87_MAP.put("909", "96"); // System malfunction + ISO_93_TO_87_MAP.put("911", "91"); // Time out (Mapped to Issuer inoperative) + ISO_93_TO_87_MAP.put("913", "94"); // Duplicate transmission + ISO_93_TO_87_MAP.put("923", "09"); // Request in progress + } public static String getCode(String code) { if (instance == null) instance = new BaseErrorCode(); @@ -25,6 +82,21 @@ public class BaseErrorCode { } + public static String convert93to87(String code1993) { + if (code1993 == null) return "06"; // Default Error + + if (ISO_93_TO_87_MAP.containsKey(code1993)) { + return ISO_93_TO_87_MAP.get(code1993); + } + + if (code1993.startsWith("0")) return "00"; + + if (code1993.startsWith("1") || code1993.startsWith("2")) return "05"; + + if (code1993.startsWith("9")) return "96"; + + return "06"; // Default "Error" for unknown ranges + } public static String getErrorMessage(String code) { if (instance == null) instance = new BaseErrorCode(); String errorMsg = instance.errorCode.get(code); diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/AuthorizationProcessUtil.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/AuthorizationProcessUtil.java index b2de037..ff2c949 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/AuthorizationProcessUtil.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/AuthorizationProcessUtil.java @@ -154,7 +154,7 @@ public class AuthorizationProcessUtil { hexValues[i] = value; } int status; - String f055Data = getF055Data(); + LogUtil.d(TAG,"is equal:"+equals); LogUtil.d(TAG,"Emv Online Result:"+emvOnlineResult); if (equals) { @@ -177,7 +177,7 @@ public class AuthorizationProcessUtil { LogUtil.e(Constant.TAG, "scriptResult: " + scriptResult); payDetail.setScriptResult(scriptResult); - + String f055Data = getF055Data(); LogUtil.e(Constant.TAG, "f055Data: " + f055Data); // if (status >= 0) { @@ -205,6 +205,7 @@ public class AuthorizationProcessUtil { private void importOnlineProcessStatus(int sdkResult,EmvOnlineResultEntity emvOnlineResult) { LogUtil.d(TAG, "importOnlineProcessStatus sdkResult:"+sdkResult); LogUtil.d(TAG, "importOnlineProcessStatus emvOnlineResult:"+emvOnlineResult.toString()); + PayLibNex.getInstance().deviceEngine.getEmvHandler2("app2").onSetOnlineProcResponse(sdkResult, emvOnlineResult); } diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/POSUtil.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/POSUtil.java index f22c086..ae9bf4b 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/POSUtil.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/POSUtil.java @@ -6,9 +6,11 @@ import android.text.TextUtils; import com.utsmyanmar.paylibs.Constant; import com.utsmyanmar.paylibs.R; import com.utsmyanmar.paylibs.model.PayDetail; +import com.utsmyanmar.paylibs.model.enums.TransCVM; import com.utsmyanmar.paylibs.system.BaseErrorCode; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.enums.BaseCardType; +import com.utsmyanmar.paylibs.utils.enums.CardScheme; import com.utsmyanmar.paylibs.utils.enums.InvalidAmount; import com.utsmyanmar.paylibs.utils.enums.TransMenu; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; @@ -93,6 +95,33 @@ public class POSUtil { return numberFormat.format(amount); } + public String getEntryCode(PayDetail payDetail) { + String value; + if (BaseCardType.MAGNETIC.getValue() == payDetail.getCardType()) { // 磁条 + value = "02"; + } else if (BaseCardType.NFC.getValue() == payDetail.getCardType()) { // NFC + value = "07"; + } else if (BaseCardType.IC.getValue() == payDetail.getCardType()) { // IC + value = "05"; + } else if (-9 == payDetail.getCardType()){ // Fallback + value = "08"; + } else { // Hand-in card number + value = "01"; + } + + + if(payDetail.getTransCVM() == TransCVM.OFFLINE_PIN) { + value += "9"; + } else { + if (payDetail.getPINCipher() != null && !payDetail.getPINCipher().trim().isEmpty()) { + value += "1"; + } else { + value += "2"; + } + } + return value; + } + public String getCurrentDateAndTime() { SimpleDateFormat dfm = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.getDefault()); String currentTime = dfm.format(new Date()); @@ -124,6 +153,25 @@ public class POSUtil { } + public String responseCodeConverter(String responseCode) { + return BaseErrorCode.convert93to87(responseCode); + } + + public String getCardType(PayDetail payDetail) { + int value = 0; + + if(payDetail.getAccountType().equals(CardScheme.VISA.name)) { + value = CardScheme.VISA.value; + } else if(payDetail.getAccountType().equals(CardScheme.MASTERCARD.name)) { + value = CardScheme.MASTERCARD.value; + } else if(payDetail.getAccountType().equals(CardScheme.UPI.name)) { + value = CardScheme.UPI.value; + } else if(payDetail.getAccountType().equals(CardScheme.MPU.name)) { + value = CardScheme.MPU.value; + } + return String.valueOf(value); + } + public String getMerchantName() { return SystemParamsOperation.getInstance().getMerchantName(); } @@ -135,6 +183,11 @@ public class POSUtil { // return formatter.format(amt); } + public String formatAmount(long amount) { + + return String.format("%012d", amount/100); + } + public String currencyCodeToText(String currencyCode) { String currencyText = "MMK"; switch (currencyCode) { diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsOperation.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsOperation.java index 89b2073..028cb02 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsOperation.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsOperation.java @@ -1761,4 +1761,15 @@ public class SystemParamsOperation { SystemParamsSettings paramsSettings = getSystemParamsSettings(); return paramsSettings.getPrinterEnabled(); } + + public void setCMHLEnable(boolean cmhlEnabled) { + SystemParamsSettings params = getSystemParamsSettings(); + params.setCmhlEnabled(cmhlEnabled); + saveSystemParamsSettings(params); + } + + public boolean isCMHLEnabled() { + SystemParamsSettings paramsSettings = getSystemParamsSettings(); + return paramsSettings.isCmhlEnabled(); + } } \ No newline at end of file diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsSettings.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsSettings.java index 2531c0e..94e834d 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsSettings.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/core_utils/SystemParamsSettings.java @@ -159,6 +159,8 @@ public class SystemParamsSettings implements Serializable { private boolean fallbackEnabled = true; + private boolean cmhlEnabled = false; + private boolean manualUpdate = false; private boolean emvEnabled = false; @@ -484,6 +486,10 @@ public class SystemParamsSettings implements Serializable { protected String getLastTransTime() { return lastTransTime; } protected boolean isClearBatch() {return isClearBatch;} + protected boolean isCmhlEnabled() {return cmhlEnabled; } + + protected void setCmhlEnabled(boolean cmhlEnabled) { this.cmhlEnabled = cmhlEnabled; } + protected void setClearBatch(boolean isClearBatch) {this.isClearBatch = isClearBatch;} protected void setRandomPinPad(boolean randomPinPad) { this.isRandomPinPad = randomPinPad;} diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/enums/CardScheme.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/enums/CardScheme.java index bd63a94..6aa6998 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/enums/CardScheme.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/enums/CardScheme.java @@ -2,19 +2,22 @@ package com.utsmyanmar.paylibs.utils.enums; public enum CardScheme { - VISA("VISA"), - MASTERCARD("MASTER"), - UPI("UnionPay"), - JCB("JCB"), - AE("AmericanExpress"), - MPU("MPU"), - RUPAY("RuPay"), - PURE("Pure"), - MPU_CTLS("MPU Ctls"); + VISA("VISA",1), + MASTERCARD("MASTER",2), + UPI("UnionPay",5), + JCB("JCB",3), + AE("AmericanExpress",0), + MPU("MPU",4), + RUPAY("RuPay",0), + PURE("Pure",0), + MPU_CTLS("MPU Ctls",4); public final String name; - CardScheme(String name){ + public final int value; + + CardScheme(String name,int value){ this.name = name; + this.value = value; } } diff --git a/settings.gradle b/settings.gradle index 457b0f5..53bde9e 100644 --- a/settings.gradle +++ b/settings.gradle @@ -39,3 +39,4 @@ include ':ecr-service-lib' include ':link-service-lib' include ':qrgen-lib' include ':nexdlkey-lib' +include ':cmhl'