From f070ad1c109c1f3f51b31d9eb19a1f9eb16ce099 Mon Sep 17 00:00:00 2001 From: kizzy Date: Thu, 11 Jun 2026 15:41:30 +0700 Subject: [PATCH 1/8] MPU still in progress only left preauth test cases --- .../ui/sending_to_host/SendingToHostRoute.kt | 24 ++++++--- .../ui/settlement/SettlementViewModel.kt | 1 + .../utsmyanmar/paylibs/network/ISOSocket.java | 51 ++++--------------- .../paylibs/utils/iso_utils/BitmapConfig.java | 2 +- .../paylibs/utils/params/Params.java | 1 + 5 files changed, 28 insertions(+), 51 deletions(-) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt index 5c8836e..11627a3 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt @@ -16,6 +16,7 @@ import androidx.compose.runtime.collectAsState import com.mob.utsmyanmar.model.TransactionStatus import com.mob.utsmyanmar.ui.settlement.SettlementViewModel import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType +import kotlinx.coroutines.channels.Channel private const val MOCK_HOST_DELAY_MS = 2000L @@ -34,19 +35,28 @@ fun ProcessingRoute( val settlementStatus by settlementViewModel.uiState.collectAsStateWithLifecycle() + val settlementStatusResult by settlementViewModel.events.collectAsStateWithLifecycle(Channel.BUFFERED) + if(sharedViewModel.transactionsType.value == TransactionsType.SETTLEMENT) { LaunchedEffect(Unit) { settlementViewModel.startSettlementProcess() } + + LaunchedEffect(settlementStatusResult) { + when(settlementStatusResult) { + TransactionStatus.ON_ERROR, + TransactionStatus.ON_SUCCESS -> onNavigateTransactionResult() + else -> {} + } + } } else { LaunchedEffect(Unit) { transProcessViewModel.resetTransactionStatus() transProcessViewModel.startOnlineProcess() } - } - LaunchedEffect(transStatus) { + LaunchedEffect(transStatus) { when(transStatus) { TransResultStatus.SUCCESS -> { sharedViewModel.payDetail.value = transProcessViewModel.payDetailResult.value @@ -61,17 +71,15 @@ fun ProcessingRoute( TransResultStatus.REVERSAL_FAIL -> onNavigateMain() else -> {} } - } - - LaunchedEffect(settlementStatus.status) { - when(settlementStatus.status) { - TransactionStatus.ON_SUCCESS -> onNavigateTransactionResult() - else -> {} } } + + + + if(sharedViewModel.transactionsType.value == TransactionsType.SETTLEMENT) { ProcessingScreen(settlementStatus.processingState) } else { diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt index 2ddae78..7a6ac3a 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt @@ -232,6 +232,7 @@ class SettlementViewModel @Inject constructor( deleteTrans.clear() } + fun startSettlementProcess() { _uiState.update { it.copy(isLoading = true) diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java index 1da0f01..7847ed3 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java @@ -152,7 +152,7 @@ public class ISOSocket { private SSLSocketFactory getSSLSocketFactory() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException { CertificateFactory cf = CertificateFactory.getInstance("X.509"); - InputStream caInput = context.getResources().openRawResource(R.raw.mpu_crt_2026); // this cert file stored in \app\src\main\res\raw folder path + InputStream caInput = context.getResources().openRawResource(R.raw.mob_uat); // this cert file stored in \app\src\main\res\raw folder path Certificate ca = cf.generateCertificate(caInput); caInput.close(); @@ -179,7 +179,7 @@ public class ISOSocket { private OkHttpClient getClient() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException { CertificateFactory cf = CertificateFactory.getInstance("X.509"); - InputStream caInput = context.getResources().openRawResource(R.raw.mpu_crt_2026); // this cert file stored in \app\src\main\res\raw folder path + InputStream caInput = context.getResources().openRawResource(R.raw.mob_uat); // this cert file stored in \app\src\main\res\raw folder path Certificate ca = cf.generateCertificate(caInput); caInput.close(); @@ -402,6 +402,8 @@ public class ISOSocket { if (SystemParamsOperation.getInstance().isSslOn()) { try { + + // For MPU TrustManager[] trustAll = new TrustManager[]{new X509TrustManager() { public void checkClientTrusted(X509Certificate[] chain, String authType) {} public void checkServerTrusted(X509Certificate[] chain, String authType) {} @@ -412,52 +414,17 @@ public class ISOSocket { SSLSocketFactory factory = ctx.getSocketFactory(); -// try (SSLSocket sslsock = (SSLSocket) factory.createSocket()) { -// -// sslsock.setEnabledProtocols(new String[]{"TLSv1.2"}); -//// while (!isSSLOnline(timeout,subscriber)) { -//// Thread.sleep(150); -//// subscriber.onError(new Throwable("java.net.SocketTimeoutException: connect timed out")); -//// } -// -// sslsock.setSoTimeout(60000); -// sslsock.connect(new InetSocketAddress(serverIP, serverPort), connectTimeout); -// -// sslsock.startHandshake(); -// -// SSLSession session = sslsock.getSession(); -// -// LogUtil.d(TAG, "SSL handshake success to " + serverIP + ":" + serverPort + "\n"); -// LogUtil.d(TAG, "TLS handshake success to " + serverIP + ":" + serverPort + "\n"); -// LogUtil.d(TAG, "TLS version: " + session.getProtocol() + "\n"); -// LogUtil.d(TAG,"Cipher suite: " + session.getCipherSuite() + "\n"); -// -// try { -// java.security.cert.Certificate[] chain = session.getPeerCertificates(); -// if (chain != null && chain.length > 0) { -// LogUtil.d(TAG,"Peer certificates:\n"); -// for (int i = 0; i < chain.length; i++) { -// X509Certificate x = (X509Certificate) chain[i]; -// LogUtil.d(TAG, " [" + i + "] Subject: " + x.getSubjectX500Principal().getName() + "\n"); -// LogUtil.d(TAG," Issuer: " + x.getIssuerX500Principal().getName() + "\n"); -// LogUtil.d(TAG," Valid: " + formatDate(x.getNotBefore()) + " - " + formatDate(x.getNotAfter()) + "\n"); -// } -// } -// } catch (Exception ignored) { } -// } -// OkHttpClient client = getClient(); + + sslSocket = (SSLSocket) factory.createSocket(); sslSocket.setEnabledProtocols(new String[]{"TLSv1.2"}); -// sslSocket.setEnabledProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"}); -// while (!isSSLOnline(timeout,subscriber)) { -// Thread.sleep(150); -// subscriber.onError(new Throwable("java.net.SocketTimeoutException: connect timed out")); -// } + sslSocket.setSoTimeout(60000); sslSocket.connect(new InetSocketAddress(serverIP, serverPort), connectTimeout); + // MPU sslSocket.startHandshake(); SSLSession session = sslSocket.getSession(); @@ -512,7 +479,7 @@ public class ISOSocket { subscriber.onComplete(); - } catch ( IOException | + } catch (IOException | NoSuchAlgorithmException | KeyManagementException e) { e.printStackTrace(); subscriber.onError(e); diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java index e2c52e8..94cb21c 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java @@ -176,7 +176,7 @@ public class BitmapConfig { // 703C058008C08000 7038058028C00000 public static final String MPU_NEW_REFUND ="703C058008C08000"; - public static final String MPU_NEW_PRE_AUTH ="7020058020C08000"; + public static final String MPU_NEW_PRE_AUTH ="7020058020C09000"; diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java index bccfaf8..0c767da 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java @@ -83,6 +83,7 @@ public class Params { payDetail.transNum = System.currentTimeMillis() / 1000; // need to add host logic in another place payDetail.setHostName("MPU"); +// payDetail.setHostName("MOB"); payDetail.setOriginalTransDate(SystemDateTime.getMMDD()+SystemDateTime.getYYYY()); From 3b7354fc3f7147b35f70f00e80a896a3e715a232 Mon Sep 17 00:00:00 2001 From: kizzy Date: Mon, 15 Jun 2026 14:37:22 +0700 Subject: [PATCH 2/8] MPU Certification latest --- .../utsmyanmar/ui/navigation/AppNavGraph.kt | 48 ++++++-- .../utsmyanmar/ui/pinpad/PinPadViewModel.kt | 26 ++-- .../ui/print_receipt/PrintReceiptScreen.kt | 1 + .../utsmyanmar/ui/refund_rrn/InputRrnRoute.kt | 102 +++++++++++++++- .../utsmyanmar/ui/refund_rrn/RRNViewModel.kt | 56 +++++++++ .../ui/sale_void/VoidTraceScreen.kt | 11 +- .../ui/sending_to_host/SendingToHostRoute.kt | 12 +- .../ui/settlement/SettlementViewModel.kt | 2 + .../ui/tms_setup/TmsSetupViewModel.kt | 4 + .../mob/utsmyanmar/utils/tms/TMSSetupsImpl.kt | 1 + .../viewmodel/TransProcessViewModel.kt | 40 ++++++- .../paylibs/print/printx/BaseXPrint.java | 2 +- .../paylibs/sign_on/SignOnProcess.java | 6 +- .../transactions/TransactionsOperation.java | 11 +- .../paylibs/utils/host_utils/HostUtils.java | 2 +- .../paylibs/utils/iso_utils/FieldUtils.java | 11 +- .../paylibs/utils/params/Params.java | 1 + paylibs/src/main/res/raw/mob.crt | 21 ++++ paylibs/src/main/res/raw/mpu_crt_2026.crt | 23 ---- paylibs/src/main/res/raw/mpucert.crt | Bin 992 -> 0 bytes paylibs/src/main/res/raw/my_cert.crt | Bin 943 -> 0 bytes paylibs/src/main/res/raw/smile_uat.crt | 113 ------------------ .../src/main/res/raw/star_yomabank_net.crt | 113 ------------------ 23 files changed, 303 insertions(+), 303 deletions(-) create mode 100644 app/src/main/java/com/mob/utsmyanmar/ui/refund_rrn/RRNViewModel.kt create mode 100644 paylibs/src/main/res/raw/mob.crt delete mode 100644 paylibs/src/main/res/raw/mpu_crt_2026.crt delete mode 100644 paylibs/src/main/res/raw/mpucert.crt delete mode 100644 paylibs/src/main/res/raw/my_cert.crt delete mode 100644 paylibs/src/main/res/raw/smile_uat.crt delete mode 100644 paylibs/src/main/res/raw/star_yomabank_net.crt diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt index 9ab79a9..fe47f0d 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt @@ -38,12 +38,14 @@ import com.mob.utsmyanmar.ui.settlement.SettlementViewModel import com.mob.utsmyanmar.ui.transaction_result.TransactionResultEvent import com.mob.utsmyanmar.ui.transaction_result.TransactionResultViewModel import com.mob.utsmyanmar.ui.functions.FunctionsScreen +import com.mob.utsmyanmar.ui.refund_rrn.RRNViewModel import com.mob.utsmyanmar.ui.tms_setup.TmsSetupRoute import com.mob.utsmyanmar.ui.tms_setup.TmsSetupViewModel import com.mob.utsmyanmar.ui.version.VersionScreen import com.mob.utsmyanmar.viewmodel.SharedViewModel import com.mob.utsmyanmar.viewmodel.TransProcessViewModel import com.utsmyanmar.ecr.data.TransType +import com.utsmyanmar.paylibs.model.TradeData import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType @SuppressLint("ContextCastToActivity") @@ -112,16 +114,27 @@ fun AppNavGraph( } composable(Routes.SeeMore.route) { + val sharedViewModel: SharedViewModel = hiltViewModel(activity) SeeMoreScreen( onBack = { navController.popBackStack() }, onNavigateAmount = { action -> - if (action == "Void") { - navController.navigate(Routes.VoidTrace.route) { - launchSingleTop = true + when (action) { + "Void" -> { + sharedViewModel.transactionsType.value = TransactionsType.VOID + navController.navigate(Routes.VoidTrace.route) { + launchSingleTop = true + } } - } else { - navController.navigate(Routes.Amount.createRoute(action)) { - launchSingleTop = true + "Pre-Auth Complete Void" -> { + sharedViewModel.transactionsType.value = TransactionsType.PRE_AUTH_COMPLETE_VOID + navController.navigate(Routes.VoidTrace.route) { + launchSingleTop = true + } + } + else -> { + navController.navigate(Routes.Amount.createRoute(action)) { + launchSingleTop = true + } } } } @@ -144,8 +157,9 @@ fun AppNavGraph( composable(Routes.VoidTrace.route) { val voidViewModel: VoidViewModel = hiltViewModel() - + val sharedViewModel: SharedViewModel = hiltViewModel(activity) VoidTraceScreen( + sharedViewModel = sharedViewModel, voidViewModel = voidViewModel, onNavigateTranDetail = { trace -> navController.navigate(Routes.VoidTranDetail.createRoute(trace)) { @@ -194,8 +208,19 @@ fun AppNavGraph( trace = trace, onBack = { navController.popBackStack() }, onProceedVoid = { payDetail -> - sharedViewModel.transactionsType.value = TransactionsType.VOID - transProcessViewModel.setTransType(TransactionsType.VOID) + if(sharedViewModel.transactionsType.value == TransactionsType.VOID) { + transProcessViewModel.setTransType(TransactionsType.VOID) + payDetail.transType = TransactionsType.VOID.name + payDetail.transactionType = TransactionsType.VOID.value + } else { + transProcessViewModel.setTransType(TransactionsType.PRE_AUTH_COMPLETE_VOID) + payDetail.transType = TransactionsType.PRE_AUTH_COMPLETE_VOID.name + payDetail.transactionType = TransactionsType.PRE_AUTH_COMPLETE_VOID.value + } + + val tradeData = TradeData() + tradeData.payDetail = payDetail + transProcessViewModel.setTradeData(tradeData) sharedViewModel.payDetail.value = payDetail navController.navigate(Routes.Processing.route) { popUpTo(Routes.VoidTranDetail.route) { @@ -392,8 +417,11 @@ fun AppNavGraph( composable(Routes.InputRrn.route) { val sharedViewModel: SharedViewModel = hiltViewModel(activity) - + val rrnViewModel: RRNViewModel = hiltViewModel(activity) + val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity) InputRrnRoute( + transProcessViewModel = transProcessViewModel, + rrnViewModel = rrnViewModel, sharedViewModel = sharedViewModel, onBack = { navController.popBackStack() }, onNavigateProcessing = { diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt index cc05eb6..8914840 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt @@ -405,8 +405,19 @@ class PinPadViewModel @Inject constructor( ON_CONFIRM_CLICK -> { LogUtil.d(TAG, "ON CLICK CONFIRM") - isTerminalStateReached = true - _pinStatus.value = PinPadStatus.ON_CONFIRM + + if ( + transType.value == TransactionsType.PRE_AUTH_COMPLETE || + transType.value == TransactionsType.PRE_AUTH_VOID || + transType.value == TransactionsType.REFUND + ) { + isTerminalStateReached = true + _pinStatus.value = PinPadStatus.ON_NEXT_SCREEN + } else { + isTerminalStateReached = true + _pinStatus.value = PinPadStatus.ON_CONFIRM + } + } ON_CANCEL_CLICK -> { @@ -488,18 +499,11 @@ class PinPadViewModel @Inject constructor( payDetail?.pinCipher = "" } - if ( - transType.value == TransactionsType.PRE_AUTH_COMPLETE || - transType.value == TransactionsType.PRE_AUTH_VOID || - transType.value == TransactionsType.REFUND - ) { - isTerminalStateReached = true - _pinStatus.value = PinPadStatus.ON_NEXT_SCREEN - } else { + handler.obtainMessage( ON_CONFIRM_CLICK ).sendToTarget() - } + } override fun onCancel() { diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/print_receipt/PrintReceiptScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/print_receipt/PrintReceiptScreen.kt index c989aa5..fc7a3d4 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/print_receipt/PrintReceiptScreen.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/print_receipt/PrintReceiptScreen.kt @@ -200,6 +200,7 @@ fun ReceiptPreview( ReceiptDivider() ReceiptRow("Merchant", state.payDetail?.merchantName.toString() ) ReceiptRow("Terminal ID", state.payDetail?.terminalNo.toString() ) + ReceiptRow("Trace No", state.payDetail?.voucherNo.toString() ) ReceiptRow("Transaction", state.payDetail?.transType.toString()) ReceiptRow("Amount", POSUtil.getInstance().getDecimalAmountSeparatorFormat(state.payDetail?.amount?:0)) ReceiptRow("Card Type", state.payDetail?.accountType.toString()) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/refund_rrn/InputRrnRoute.kt b/app/src/main/java/com/mob/utsmyanmar/ui/refund_rrn/InputRrnRoute.kt index 53df0e2..4a4d646 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/refund_rrn/InputRrnRoute.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/refund_rrn/InputRrnRoute.kt @@ -6,14 +6,22 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.mob.utsmyanmar.ui.components.NumericEntryScreen import com.mob.utsmyanmar.viewmodel.SharedViewModel +import com.mob.utsmyanmar.viewmodel.TransProcessViewModel +import com.utsmyanmar.paylibs.model.PayDetail +import com.utsmyanmar.paylibs.model.TradeData import com.utsmyanmar.paylibs.utils.POSUtil +import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType +import sunmi.sunmiui.utils.LogUtil private const val RRN_MAX_LENGTH = 12 @Composable fun InputRrnRoute( + transProcessViewModel: TransProcessViewModel, + rrnViewModel: RRNViewModel, sharedViewModel: SharedViewModel, onBack: () -> Unit, onNavigateProcessing: () -> Unit @@ -28,6 +36,75 @@ fun InputRrnRoute( errorMessage = null } + val payDetailState by rrnViewModel.payDetailState.collectAsStateWithLifecycle() + + + fun processPreAuthComp(payDetail: PayDetail) { + val newPay = transProcessViewModel.payDetail + + + + newPay?.setReferNo(payDetail.referNo) + newPay?.setApprovalCode(payDetail.getApprovalCode()) + newPay?.setTradeTime(payDetail.getTradeTime()) + newPay?.setTradeDate(payDetail.getTradeDate()) + + + val tradeData = TradeData() + tradeData.payDetail = newPay + transProcessViewModel.setOldTransPayDetail(payDetail) + transProcessViewModel.setTradeData(tradeData) + + rrnViewModel.resetState() + onNavigateProcessing() + + } + + fun processPreAuthVoid(payDetail: PayDetail) { + val newPay = transProcessViewModel.payDetail + + newPay?.setReferNo(payDetail.referNo) + + + val tradeData = TradeData() + tradeData.payDetail = newPay + transProcessViewModel.setOldTransPayDetail(payDetail) + transProcessViewModel.setTradeData(tradeData) + + rrnViewModel.resetState() + onNavigateProcessing() + } + + + + + LaunchedEffect(payDetailState) { + LogUtil.d("RRN","paydetail state: $payDetailState") + when (val state = payDetailState) { + + is RRNViewModel.PayDetailState.Success -> { + + + sharedViewModel.payDetail.value = state.data + sharedViewModel.rrNNo.value = state.data.referNo + + if(sharedViewModel.transactionsType.value == TransactionsType.PRE_AUTH_COMPLETE) { + processPreAuthComp(state.data) + } else if(sharedViewModel.transactionsType.value == TransactionsType.PRE_AUTH_VOID) { + processPreAuthVoid(state.data) + } + + } + is RRNViewModel.PayDetailState.Error -> { + errorMessage = state.message + rrnViewModel.resetState() + // show dialog + // navigate to home + } + else -> Unit + } + } + NumericEntryScreen( title = "Input RRN", prompt = "Enter RRN", @@ -38,17 +115,32 @@ fun InputRrnRoute( onCancelClick = onBack, onConfirmClick = { val trimmedRrn = rrn.trim() + if (POSUtil.getInstance().checkNumberField(trimmedRrn)) { errorMessage = "Invalid RRN" return@NumericEntryScreen } - sharedViewModel.rrNNo.value = trimmedRrn - sharedViewModel.payDetail.value?.let { payDetail -> - payDetail.referNo = trimmedRrn - sharedViewModel.payDetail.value = payDetail + + + if(sharedViewModel.transactionsType.value == TransactionsType.REFUND ) { + val newPay = transProcessViewModel.payDetail + + newPay?.setReferNo(trimmedRrn) + val tradeData = TradeData() + tradeData.payDetail = newPay + transProcessViewModel.setTradeData(tradeData) + rrnViewModel.resetState() + onNavigateProcessing() + } else{ + rrnViewModel.searchPayDetail( + trimmedRrn, + sharedViewModel.payDetail.value?.cardNo?:"" + ) } - onNavigateProcessing() + + + }, onKeyClick = { value -> rrn = appendRrnValue(rrn, value) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/refund_rrn/RRNViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/ui/refund_rrn/RRNViewModel.kt new file mode 100644 index 0000000..b27a476 --- /dev/null +++ b/app/src/main/java/com/mob/utsmyanmar/ui/refund_rrn/RRNViewModel.kt @@ -0,0 +1,56 @@ +package com.mob.utsmyanmar.ui.refund_rrn + +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.lifecycle.ViewModel +import androidx.lifecycle.asFlow +import androidx.lifecycle.viewModelScope +import com.utsmyanmar.baselib.repo.Repository +import com.utsmyanmar.paylibs.model.PayDetail +import com.utsmyanmar.paylibs.system.SingleLiveEvent +import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch +import javax.inject.Inject + + +@HiltViewModel +class RRNViewModel @Inject constructor( + private val repository: Repository +) : ViewModel() { + + sealed class PayDetailState { + object Idle : PayDetailState() + object Loading : PayDetailState() + data class Success(val data: PayDetail) : PayDetailState() + data class Error(val message: String) : PayDetailState() + } + + private val _payDetailState = MutableStateFlow(PayDetailState.Idle) + val payDetailState: StateFlow = _payDetailState + + fun searchPayDetail(refNo: String, cardNo: String) { + _payDetailState.value = PayDetailState.Loading + viewModelScope.launch { + try { + repository.searchPayDetail(cardNo, refNo) + .asFlow() + .filterNotNull() + .first() + .let { result -> + _payDetailState.value = PayDetailState.Success(result) + } + } catch (e: Exception) { + _payDetailState.value = PayDetailState.Error(e.message ?: "Search failed") + } + } + } + + fun resetState() { + _payDetailState.value = PayDetailState.Idle + } + +} diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/sale_void/VoidTraceScreen.kt b/app/src/main/java/com/mob/utsmyanmar/ui/sale_void/VoidTraceScreen.kt index e870e51..e37309a 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/sale_void/VoidTraceScreen.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/sale_void/VoidTraceScreen.kt @@ -40,11 +40,14 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import com.mob.utsmyanmar.ui.components.appbar.AppBar import com.mob.utsmyanmar.ui.theme.Color +import com.mob.utsmyanmar.viewmodel.SharedViewModel import com.utsmyanmar.paylibs.model.PayDetail import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType +import sunmi.sunmiui.utils.LogUtil @Composable fun VoidTraceScreen( + sharedViewModel: SharedViewModel, voidViewModel: VoidViewModel, onNavigateTranDetail: (String) -> Unit, onBack: () -> Unit = {} @@ -57,12 +60,18 @@ fun VoidTraceScreen( val recentTransactions by voidViewModel.getLastThreeTransactions().observeAsState(emptyList()) val transactionSource: LiveData = remember(searchedTrace) { + val transType = if(sharedViewModel.transactionsType.value == TransactionsType.VOID) { + TransactionsType.SALE.value + } else { + TransactionsType.PRE_AUTH_COMPLETE.value; + } + LogUtil.d("void screen","transaction type : $transType and trace number : $searchedTrace") if (searchedTrace.isBlank()) { MutableLiveData(null) } else { @Suppress("UNCHECKED_CAST") voidViewModel.getVoidTrans( - TransactionsType.SALE.value, + transType, searchedTrace ) as LiveData } diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt index 11627a3..15a0619 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt @@ -35,18 +35,18 @@ fun ProcessingRoute( val settlementStatus by settlementViewModel.uiState.collectAsStateWithLifecycle() - val settlementStatusResult by settlementViewModel.events.collectAsStateWithLifecycle(Channel.BUFFERED) - - if(sharedViewModel.transactionsType.value == TransactionsType.SETTLEMENT) { LaunchedEffect(Unit) { settlementViewModel.startSettlementProcess() } - LaunchedEffect(settlementStatusResult) { - when(settlementStatusResult) { + LaunchedEffect(settlementStatus.status) { + when(settlementStatus.status) { TransactionStatus.ON_ERROR, - TransactionStatus.ON_SUCCESS -> onNavigateTransactionResult() + TransactionStatus.ON_SUCCESS -> { + sharedViewModel.payDetail.value = settlementViewModel.getPayDetail() + onNavigateTransactionResult() + } else -> {} } } diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt index 7a6ac3a..d9f0f90 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt @@ -205,6 +205,7 @@ class SettlementViewModel @Inject constructor( } } + fun getPayDetail() = payDetail fun setSettlementType(type: SettlementType) { _uiState.update { it.copy(settlementType = type) @@ -351,6 +352,7 @@ class SettlementViewModel @Inject constructor( totalERefundAmount } + payDetail = currentPayDetail tradeData.payDetail = currentPayDetail tradeData.field60 = field60 diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/tms_setup/TmsSetupViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/ui/tms_setup/TmsSetupViewModel.kt index 886252b..09d89e7 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/tms_setup/TmsSetupViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/tms_setup/TmsSetupViewModel.kt @@ -53,6 +53,7 @@ class TmsSetupViewModel @Inject constructor( init { viewModelScope.launch { waitForHardware() + TMSUtil.getInstance().generateFinalVersion() downloadConfigs() } } @@ -62,6 +63,8 @@ class TmsSetupViewModel @Inject constructor( it.copy(isLoading = true, isError = false, statusText = "Connecting to TMS server...") } + + val disposable = repository.getParams(buildRequest()) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) @@ -103,6 +106,7 @@ class TmsSetupViewModel @Inject constructor( delay(500) elapsed += 500 } + } private fun onConfigApplied() { diff --git a/app/src/main/java/com/mob/utsmyanmar/utils/tms/TMSSetupsImpl.kt b/app/src/main/java/com/mob/utsmyanmar/utils/tms/TMSSetupsImpl.kt index e340302..e5550a7 100644 --- a/app/src/main/java/com/mob/utsmyanmar/utils/tms/TMSSetupsImpl.kt +++ b/app/src/main/java/com/mob/utsmyanmar/utils/tms/TMSSetupsImpl.kt @@ -267,6 +267,7 @@ class TMSSetupsImpl : TMSSetups { } catch (e: Exception) { "?" } + SystemParamsOperation.getInstance().setFinalVersion("PHV$phv-RV$rv-SV$sv") return "PHV$phv-RV$rv-SV$sv" } private fun parseBoolean(data: String): Boolean = diff --git a/app/src/main/java/com/mob/utsmyanmar/viewmodel/TransProcessViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/viewmodel/TransProcessViewModel.kt index acac75a..ad40565 100644 --- a/app/src/main/java/com/mob/utsmyanmar/viewmodel/TransProcessViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/viewmodel/TransProcessViewModel.kt @@ -3,7 +3,6 @@ package com.mob.utsmyanmar.viewmodel import android.text.TextUtils import androidx.lifecycle.ViewModel import com.mob.utsmyanmar.model.TransResultStatus -import com.mob.utsmyanmar.ui.processing_card.ProcessingCardState import com.mob.utsmyanmar.ui.sending_to_host.ProcessingState import com.utsmyanmar.baselib.repo.Repository import com.utsmyanmar.paylibs.model.PayDetail @@ -109,6 +108,12 @@ class TransProcessViewModel @Inject constructor( fun setOldTransPayDetail(payDetail: PayDetail) { oldTransPayDetail = payDetail } + + fun setNewPayDetail(payDetail: PayDetail) { + this.payDetail = payDetail + tradeData = TradeData() + tradeData.payDetail = payDetail + } private val _state = MutableStateFlow(ProcessingState()) val state = _state.asStateFlow() @@ -263,9 +268,36 @@ class TransProcessViewModel @Inject constructor( ) } - override fun processPreVoidDb(payResult: PayDetail) {} - override fun processPreCompDb(payResult: PayDetail) {} - override fun processPreCompVoidDb(payResult: PayDetail) {} + override fun processPreVoidDb(payResult: PayDetail) { + oldTransPayDetail?.apply { + isCanceled = true + repository.updatePayDetail(oldTransPayDetail!!) + } + + + repository.insertPayDetail(updateCurrentDateAndTime(payResult)) + } + override fun processPreCompDb(payResult: PayDetail) { + if (oldTransPayDetail?.getAmount() == payResult.getAmount()) { + oldTransPayDetail?.apply { + isCanceled = true + repository.updatePayDetail(this) + } + } else { + oldTransPayDetail?.apply { + isCanceled = false + repository.updatePayDetail(this) + } + } + repository.insertPayDetail(updateCurrentDateAndTime(payResult)) + } + override fun processPreCompVoidDb(payResult: PayDetail) { + payDetail?.apply { + isCanceled = true + repository.updatePayDetail(this) + } + repository.insertPayDetail(updateCurrentDateAndTime(payResult)) + } /* * Reversal diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/BaseXPrint.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/BaseXPrint.java index 7441fad..7c15376 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/BaseXPrint.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/BaseXPrint.java @@ -206,7 +206,7 @@ public abstract class BaseXPrint { String finalVersion = SystemParamsOperation.getInstance().getFinalVersion(); sunmiPrinterService.setFontSize(textSize, innerResultCallback); - sunmiPrinterService.printText("***** MERCHANT COPY *****" + "\n", innerResultCallback); +// sunmiPrinterService.printText("***** MERCHANT COPY *****" + "\n", innerResultCallback); sunmiPrinterService.printText(finalVersion + "\n", innerResultCallback); sunmiPrinterService.printText(receiptFooter + "\n", innerResultCallback); } catch (RemoteException e) { diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/sign_on/SignOnProcess.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/sign_on/SignOnProcess.java index 497f791..3bc0ef8 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/sign_on/SignOnProcess.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/sign_on/SignOnProcess.java @@ -50,7 +50,7 @@ public class SignOnProcess { private SignOnProcess() { tradeData = Params.newTrade(true); // payDetail = tradeData.getPayDetail(); - isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.MPU) + isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.CARDZONE) .build(); } @@ -59,7 +59,7 @@ public class SignOnProcess { flag = false; return listener -> { // LogUtil.d(TAG, "Starting TX SignOn"); - HostName hostName = HostName.MPU; + HostName hostName = HostName.CARDZONE; PayDetail payDetail = tradeData.getPayDetail(); payDetail.setProcessCode(TransactionsType.SIGN_ON.processCode); @@ -67,7 +67,7 @@ public class SignOnProcess { payDetail.setTransactionType(TransactionsType.SIGN_ON.value); payDetail.setHostName(hostName.name); - byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.MPU_NEW_SIGN_ON, MessageType.NETWORK_MANAGEMENT); + byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.CZ_SIGN_ON, MessageType.NETWORK_MANAGEMENT); ISOSocket.getInstance().enqueue(sendBytes, sendBytes.length,false, new ISOCallback() { @Override public void onReceive(byte[] bytes, int length) { diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/transactions/TransactionsOperation.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/transactions/TransactionsOperation.java index 50a1c9c..35e9f04 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/transactions/TransactionsOperation.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/transactions/TransactionsOperation.java @@ -174,8 +174,8 @@ public class TransactionsOperation { if (responseMap.get("F038") != null) { transPayDetail.setApprovalCode(Objects.requireNonNull(responseMap.get("F038")).getDataStr()); } else { - transPayDetail.setIsNeedReversal(true); - return; +// transPayDetail.setIsNeedReversal(true); +// return; } if (responseMap.get("F046") != null) { @@ -376,7 +376,6 @@ public class TransactionsOperation { newPay.setTransCVM(TransCVM.SIGNATURE); if((oldPay.getAccountType().equals(CardScheme.MASTERCARD.name) || oldPay.getAccountType().equals(CardScheme.VISA.name))) { - newPay.setProcessCode(TransactionsType.PRE_AUTH_SALE.processCode); } // for manual entry reversal which need de 35 @@ -391,12 +390,14 @@ public class TransactionsOperation { newPay.setReferNo(oldPay.getReferNo()); newPay.setTempKSN(oldPay.getTempKSN()); newPay.setTransCVM(oldPay.getTransCVM()); //added on 26 Nov 2025 + newPay.setApprovalCode(oldPay.getApprovalCode()); + newPay.setTradeTime(oldPay.getTradeTime()); // mpu + newPay.setTradeDate(oldPay.getTradeDate()); // mpu } else if (transactionsType == TransactionsType.PRE_AUTH_COMPLETE_VOID) { newPay.setVoucherNo(oldPay.getVoucherNo()); newPay.setCustomOrderNo(oldPay.getVoucherNo()); newPay.setReferNo(oldPay.getReferNo()); newPay.setCardInfo(oldPay.getCardInfo()); - /* * new requirements */ newPay.setCardType(AidlConstants.CardType.IC.getValue()); @@ -406,7 +407,7 @@ public class TransactionsOperation { if(oldPay.getAccountType().equals(CardScheme.MPU.name) || oldPay.getAccountType().equals(CardScheme.MPU_CTLS.name)){ - newPay.setTransCVM(TransCVM.NO_CVM); + newPay.setTransCVM(TransCVM.SIGNATURE); } newTrade.setPayDetail(newPay); diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java index ed32139..880f88b 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java @@ -130,7 +130,7 @@ public class HostUtils { if (hostName == HostName.BPC) { msgType = MessageType.REVERSAL; } else { - msgType = MessageType.FINANCIAL; + msgType = MessageType.REVERSAL; } break; case SETTLEMENT: diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java index 16a4cde..5af4b8e 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java @@ -374,13 +374,10 @@ public class FieldUtils { 08 – mail order/telephone order * */ // Service point condition code Fill in 00 for ordinary consumer transactions and mobile phone chip transactions, fill in 08 for order consumer transactions, fill in 64 for installment transactions, fill in 65 for points consumption transactions, fill in 67 for mobile phone card-free reservations -// if (payDetail.getTransactionType() == PRE_AUTH_VOID.value) { -// field.setDataStr("06"); -// } else { -// field.setDataStr("00"); -// } - - if(payDetail.getTransactionType() == REFUND.value) { + if (payDetail.getTransactionType() == PRE_AUTH_SALE.value) { + field.setDataStr("06"); + } + else if(payDetail.getTransactionType() == REFUND.value) { field.setDataStr("00"); // MPU } else if(payDetail.getCardType() == -1) { field.setDataStr("08"); diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java index 0c767da..bf8807b 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java @@ -82,6 +82,7 @@ public class Params { payDetail.setIsCanceled(false); payDetail.transNum = System.currentTimeMillis() / 1000; // need to add host logic in another place +// payDetail.setHostName("MPU"); payDetail.setHostName("MPU"); // payDetail.setHostName("MOB"); diff --git a/paylibs/src/main/res/raw/mob.crt b/paylibs/src/main/res/raw/mob.crt new file mode 100644 index 0000000..1b2e164 --- /dev/null +++ b/paylibs/src/main/res/raw/mob.crt @@ -0,0 +1,21 @@ +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIETeycDjANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJt +eTELMAkGA1UECBMCa2wxDDAKBgNVBAcTA2trbDERMA8GA1UEChMIY2FyZHpvbmUx +ETAPBgNVBAsTCGNhcmR6b25lMREwDwYDVQQDEwhjYXJkem9uZTAeFw0yMTA3MDcw +ODU5MzlaFw0zMTA3MDUwODU5MzlaMGExCzAJBgNVBAYTAm15MQswCQYDVQQIEwJr +bDEMMAoGA1UEBxMDa2tsMREwDwYDVQQKEwhjYXJkem9uZTERMA8GA1UECxMIY2Fy +ZHpvbmUxETAPBgNVBAMTCGNhcmR6b25lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA2v7WJjmr0b9WpbcsTtk6llJDA5XeReWc3in0sirutMQi+9jLUdgJ +0Kdr0Cro0vbJAcVWTBYnMqnqh7oJQYs6vpIFKJA175ZhclQFAcL2jth+Tsqx9Av1 +DxbuuB7yxU7ErkhXe+/B0R8zOag866R3Xg7u09GG4mlQMx5zmo1Hn3lqMU0lxEXM +vhkzVXLUMLhVwu/oJk98u+6pPXoCzXPjBCgy3iR+BaGIR6aiflz8Bi1Rn3XgfnMi +PzOzxKRZu5mNBRijs7ztcjA8Pc2uNI0ux3+jUJTgu2JRIBJs+7BkNcJeLzpW5psz +qfFdwxTKkgfqU9gJwuPaEbdnP0j7Rv2MBwIDAQABoyEwHzAdBgNVHQ4EFgQUOF7s +btNCxmv9HSAkSAPVAHpDXY4wDQYJKoZIhvcNAQELBQADggEBADOJaUnRiVucIb8q +jxplpSE0gOHMng+BMq2gKcqqc+QRc/mgM3n0J8F1A3rzj3udbzen3/9TnOiH17uy +FGLH12sJ7dJWMGAJ2p15N307ckrCab3+3Y1w6OQJLZ8t3eeXFGPVWQJtiOUbyX73 +3Fv+TpNl6X1uEdQ0zNDiAvWZQ/e6ynYGF/tSgZLJvgV+8UY5ShCA0Ypousm6sPqb +KQXPCs3kRn1eMgMy8PcmUlZK/5qhD+xZswWgNiQ6EyCWmwpB4O0N9wQbLBTFZkGA +bDke78LVS1nUam9czcNvSDYyjWsk9ud8mo9JfF21qmwCR68btqDgeU0hM9W6lEQo +ezrrz9k= +-----END CERTIFICATE----- diff --git a/paylibs/src/main/res/raw/mpu_crt_2026.crt b/paylibs/src/main/res/raw/mpu_crt_2026.crt deleted file mode 100644 index bf7b7b0..0000000 --- a/paylibs/src/main/res/raw/mpu_crt_2026.crt +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID3DCCAsSgAwIBAgIJAIuL4ypXInCoMA0GCSqGSIb3DQEBBQUAMGcxCzAJBgNV -BAYTAk1SMQswCQYDVQQIDAJNUjEMMAoGA1UECgwDTVBVMQwwCgYDVQQLDANNUFUx -DTALBgNVBAMMBHRlc3QxIDAeBgkqhkiG9w0BCQEWEXdhaXlhbkBmcHQuY29tLnZu -MB4XDTIxMDIwMzE3MTExMloXDTIyMDIwMzE3MTExMlowdzELMAkGA1UEBhMCTVIx -DzANBgNVBAgMBllhbmdvbjEPMA0GA1UEBwwGWWFuZ29uMQwwCgYDVQQKDANNUFUx -DDAKBgNVBAsMA01QVTENMAsGA1UEAwwEdGVzdDEbMBkGCSqGSIb3DQEJARYMdGVz -dEBtcHUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAujLe6mWJ -GXliGUoLdJEA37VyBOQ7zLpge7u2QM2UMQXnKosdtZzMzXnVrnctJ6ehzLnhL0Lv -Oissr7qo53haXsJJccHeqcTH5cFkh96IswOrc8/1MMrb4zMjnNjOZaxmB4HeGHKk -KjNLKTTO8It3v/MziBhxUEEKVrN4npeUfsGVPfrvYnZXSWuRLhzYYLtEz/LFg4Yh -28pCXqk2vmGNV62oZ2+SDisoiYdIVEOMRqb/7cJg+cd0JRdvxHsTNuYRHGtJOM10 -lEnoI+moE5OIUpp8Z+i4ZcvyThpNbRWf9sRzB8oc32fZ2UWnlN5+bVRLCjlk2jNO -SGdMuMaF0bs3GwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1P -cGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUipyzRYfqRc2P -QCJ0FJp6eAvI1wkwHwYDVR0jBBgwFoAUvYEAOtcvUt4CxCp+9zRG2oJqos8wDQYJ -KoZIhvcNAQEFBQADggEBAAjBQroy74ACyyJCZJ50KBTYQI3Sk82hO/+zZFqsJgWm -mNum31TtfwhvQmi94sXQSar0UsqLTmLC3UTucwEdSKOPzXF5BK4EEbkYgMm78hNK -2zqhGvcWlqun+KPxmnMRFoVmN3Ck2PkcgudvAeV0G3rm0OdLUwLoK2TcREVf1Cwg -C7jX5QtGOgVqnKDZBuoSvdbV30ka7pKkdJAy/Wus4N9hHH+bR2FNkLgTDoXnV8LL -E2dRKVYAh9TtuXiW/ejhPtEc14sMP+8JpCFX3DYx4yRW8ZeMl5jal4LhRFXdDbVl -Wm99KcWM+TNw/nzKwv0zUJXy0HlN82tvLX1/wbBUo8M= ------END CERTIFICATE----- diff --git a/paylibs/src/main/res/raw/mpucert.crt b/paylibs/src/main/res/raw/mpucert.crt deleted file mode 100644 index 040c8f71e1fbbc6560bcbb63e88b0bfc76e5068e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 992 zcmXqLV!mV0#B^i_C*_cCF z*o2vUgJ2vE9uSAefD0tU#l!3y5DMdQLwLLf+#oq-9+r~S;u1pz139?4oQz_E<%yY< ziFpob1togP`MG*!c?NRgyherwMh3=)=7xrbMo~bn5fay+9A-DfA^bpx0?p^(VT(-6 zOV7_UgbJ|31xRq6w1FhD>v%v;cE~L#1-Z?jiBSnTP#9Smn41{+8GzzkOihf847-f( zy-MwrtW1*h;x3uUaDQtN%My zo!(n%>#X0k;(0|>+#%1xgZEY*IsWuuO8dQz&CIKd&wn*Ib^Ecg@|+vzQrD!hH{O#d zTB2p_t!Z-ZLwEW9&&C}Rg#nISVVf)FO`lSCaH{RE_eo{pp4k)iWNswvb~*p)Xmgw5 z?Nd&1E6w&L_J*%rk)A(^Pg|q2-6O=g$8FjFw}%pb9xqW9&p%QvZ1zl0Cfn2EY{?YQ z7s@YJ2v6<^npKnjVn^!fPkvIqxuWyG9Vuo%C38Rh=1te-Q|{H}hIn&Xrra|2^GNsE zajf;?ZgXiSW=00a#nlFt;B+D@%)(^AV4%asnb79J*!IJTk(WhYOxC|3H7_{WN5MTc zFSRJKBsE3BIkl)HGc7Y2$T5%wMx`ttix`VY*PP9+?XO(V_B$w*h|H?0;68Dk(?A|1 zt;`}}Al4wVw~@i>x_;0-rXyN)-%Z?ZHDxV2j~qR~Gz*L#Mh1?9PP>fWH!z)6a!Q$3 zq9Jm_q4(0{vkR^NZ%&C?qsF>y#_eVIL*CYN&?WRP@7C0){94VUJwJ^L{?(j1^w&6G>Zc2pzMr%6b!+PnZU|X?7y#Ev BZ_)q& diff --git a/paylibs/src/main/res/raw/my_cert.crt b/paylibs/src/main/res/raw/my_cert.crt deleted file mode 100644 index 38ba4378d121e350c89a70554504e0febeb69f87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 943 zcmXqLVqR^~#58#UGZP~d6DLD=_hYSarGmu_&^*E9(Lc##Jt4ZB10YnE|3Tp53_GTD2&Gq;qe-9gXEZbSVCNbLktxR zwTwl;|br=jxT^8OVwA8W|WE8k!hb8d{iGL;<Bg30n*OonYDVxszLaeIvj#tAjVaJDib|2q$!~N8z za}L}$4$I4~5~y-`u;4_h>*}MsZRESw-${D8=K8lK97S<6ejibenV}J>IiLR=vn|t$ zM|ZY4)E;=(YVyEd%kIwqRTsM1bS5y`t0ZgASkL~Aue$E@Zm~IUe(OGZ^>d}dMy1WI zJZn}I*Ir&Ro#SHIg0{f;^eOBMZtZ*hB5{G55LG9p*>TYP2Nk2oL^zKLN1-7 z&Z6|XpUgU?It6+kR+c5I<+Zf+O?taPor#%|fpKwwfuDgaFq&ogSj1RF zRz9CR_bSU)nM=ENnm<`J^X)h5DTxO1AZcY52?MbP> Date: Mon, 15 Jun 2026 14:39:32 +0700 Subject: [PATCH 3/8] added signature for all MPU transactions --- .../utsmyanmar/paylibs/transactions/TransactionsOperation.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/transactions/TransactionsOperation.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/transactions/TransactionsOperation.java index 35e9f04..2734d0e 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/transactions/TransactionsOperation.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/transactions/TransactionsOperation.java @@ -295,7 +295,7 @@ public class TransactionsOperation { if(payDetail.getAccountType().equals(MPU)){ // payDetail.setIsFreeSign(true); - payDetail.setTransCVM(TransCVM.NO_CVM); + payDetail.setTransCVM(TransCVM.SIGNATURE); } return tradeData; } From 349d1eed2c19d1f943b883beb4da7ff1fbeb4a6f Mon Sep 17 00:00:00 2001 From: kizzy Date: Thu, 18 Jun 2026 12:09:04 +0700 Subject: [PATCH 4/8] integration with cz host --- .../java/com/mob/utsmyanmar/utils/MockCard.kt | 23 ++++- .../utsmyanmar/baselib/TerminalKeyUtil.java | 4 +- .../paylibs/isobuilder/builderx/ISOMsgX.java | 1 + .../utsmyanmar/paylibs/network/ISOSocket.java | 83 +++---------------- .../paylibs/sign_on/SignOnProcess.java | 2 + .../paylibs/utils/enums/HostName.java | 3 +- .../paylibs/utils/host_utils/HostUtils.java | 2 +- .../paylibs/utils/iso_utils/BitmapConfig.java | 1 + .../paylibs/utils/iso_utils/FieldConfig.java | 2 +- .../paylibs/utils/iso_utils/FieldUtils.java | 5 ++ .../paylibs/utils/params/Params.java | 2 +- 11 files changed, 47 insertions(+), 81 deletions(-) diff --git a/app/src/main/java/com/mob/utsmyanmar/utils/MockCard.kt b/app/src/main/java/com/mob/utsmyanmar/utils/MockCard.kt index 4dcad04..043ce7b 100644 --- a/app/src/main/java/com/mob/utsmyanmar/utils/MockCard.kt +++ b/app/src/main/java/com/mob/utsmyanmar/utils/MockCard.kt @@ -13,12 +13,29 @@ data class MockCardData( object MockData { +// private val mockCardData: MockCardData = MockCardData( +// cardNo="9503712156912514", +// expDate="2912", +// cardScheme="MPU", +// cardHolderName="Htin Kyaw Win", +// iccData="9503712156912514=29121010000000000000" +// ) + +// production card +// private val mockCardData: MockCardData = MockCardData( +// cardNo="9503220100322798", +// expDate="2912", +// cardScheme="MPU", +// cardHolderName="Htin Kyaw Win", +// iccData="9503220100322798=300110100000942" +// ) + private val mockCardData: MockCardData = MockCardData( - cardNo="9503712156912514", - expDate="2912", + cardNo="9503032443884321", + expDate="3102", cardScheme="MPU", cardHolderName="Htin Kyaw Win", - iccData="9503712156912514=29121010000000000000" + iccData="9503032443884321=310220100" ) fun generateMPUCard(): CardDataX = CardDataX().apply { diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/TerminalKeyUtil.java b/baselib/src/main/java/com/utsmyanmar/baselib/TerminalKeyUtil.java index 3dbf2a7..be0ca8c 100644 --- a/baselib/src/main/java/com/utsmyanmar/baselib/TerminalKeyUtil.java +++ b/baselib/src/main/java/com/utsmyanmar/baselib/TerminalKeyUtil.java @@ -28,7 +28,8 @@ public final class TerminalKeyUtil { SecurityOptV2 mSecurityOptV2 = BaseApplication.getInstance().mSecurityOptV2; byte[] cvByte = ByteUtil.hexStr2Bytes("B7B520"); - byte[] dataByte = ByteUtil.hexStr2Bytes("e121249099a677e8b7d4f6a9d49fe8d1".toUpperCase()); +// byte[] dataByte = ByteUtil.hexStr2Bytes("e121249099a677e8b7d4f6a9d49fe8d1".toUpperCase()); // mpu + byte[] dataByte = ByteUtil.hexStr2Bytes("05FFB893726A5F1E59692D24E72E36AC"); byte[] makBytes = ByteUtil.hexStr2Bytes("250738083EC15BD3BA67D66B8A7AA13B"); // byte[] makCvBytes = ByteUtil.hexStr2Bytes("204E449B97"); @@ -46,6 +47,7 @@ public final class TerminalKeyUtil { int result = 0; SystemParamsOperation.getInstance().setTMKIndex("9"); +// SystemParamsOperation.getInstance().setInjectOnce(false); if(!SystemParamsOperation.getInstance().isInjectOnce()) { try { // result = mSecurityOptV2.saveKeyDukpt(AidlConstantsV2.Security.KEY_TYPE_DUPKT_IPEK,IPEKByte,IPEKKCVByte,KSNByte,AidlConstantsV2.Security.KEY_ALG_TYPE_3DES,9); diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/builderx/ISOMsgX.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/builderx/ISOMsgX.java index 363ede8..4cd0c31 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/builderx/ISOMsgX.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/builderx/ISOMsgX.java @@ -124,6 +124,7 @@ public class ISOMsgX extends BaseISOMsgX{ Map map = FieldUtils.fillEachFieldValue(rm, tradeData); + tradeData.payDetail.setMsgType(MTI); return packByte(map, MTI,hostName,isoMode); } diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java index 7847ed3..9f5d0cc 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java @@ -26,14 +26,11 @@ import java.security.KeyManagementException; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.text.SimpleDateFormat; import java.util.Arrays; -import java.util.Date; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.regex.Matcher; @@ -67,7 +64,6 @@ import sunmi.sunmiui.utils.LogUtil; public class ISOSocket { - private static final String TAG = ISOSocket.class.getSimpleName(); private static final int DEFAULT_TIMEOUT = 30 * 1000; private String serverIP; private int serverPort; @@ -152,7 +148,7 @@ public class ISOSocket { private SSLSocketFactory getSSLSocketFactory() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException { CertificateFactory cf = CertificateFactory.getInstance("X.509"); - InputStream caInput = context.getResources().openRawResource(R.raw.mob_uat); // this cert file stored in \app\src\main\res\raw folder path + InputStream caInput = context.getResources().openRawResource(R.raw.mob); // this cert file stored in \app\src\main\res\raw folder path Certificate ca = cf.generateCertificate(caInput); caInput.close(); @@ -179,7 +175,7 @@ public class ISOSocket { private OkHttpClient getClient() throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException { CertificateFactory cf = CertificateFactory.getInstance("X.509"); - InputStream caInput = context.getResources().openRawResource(R.raw.mob_uat); // this cert file stored in \app\src\main\res\raw folder path + InputStream caInput = context.getResources().openRawResource(R.raw.mob); // this cert file stored in \app\src\main\res\raw folder path Certificate ca = cf.generateCertificate(caInput); caInput.close(); @@ -330,16 +326,9 @@ public class ISOSocket { } return port; } - private String formatDate(Date d) { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(d); } public void switchIp() { isSwitchIp = true; -// serverIP = "posuat.myanmarorientalbank.com"; -// serverPort = 5033; -// serverIP = "192.168.0.100"; -// serverPort = 5001; -// serverIP = "103.84.101.82"; -// serverPort = 60147; serverIP = getSecondaryIp(); serverPort = getSecondaryPort(); } @@ -360,13 +349,6 @@ public class ISOSocket { if (!isSwitchIp) { serverIP = getIp(); serverPort = getPort(); -// serverIP = "192.168.0.100"; -// serverPort = 5001; -// serverIP = "103.84.101.82"; -// serverPort = 60147; -// SystemParamsOperation.getInstance().setSslSwitchStatus(true); -// serverIP = "posuat.myanmarorientalbank.com"; -// serverPort = 5033; } else { isSwitchIp = false; } @@ -402,51 +384,16 @@ public class ISOSocket { if (SystemParamsOperation.getInstance().isSslOn()) { try { - - // For MPU - TrustManager[] trustAll = new TrustManager[]{new X509TrustManager() { - public void checkClientTrusted(X509Certificate[] chain, String authType) {} - public void checkServerTrusted(X509Certificate[] chain, String authType) {} - public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } - }}; - SSLContext ctx = SSLContext.getInstance("TLS"); - ctx.init(null, trustAll, new SecureRandom()); - - SSLSocketFactory factory = ctx.getSocketFactory(); - - - - - sslSocket = (SSLSocket) factory.createSocket(); - sslSocket.setEnabledProtocols(new String[]{"TLSv1.2"}); - + OkHttpClient client = getClient(); + sslSocket = (SSLSocket) client.sslSocketFactory().createSocket(); +// while (!isSSLOnline(timeout,subscriber)) { +// Thread.sleep(150); +// subscriber.onError(new Throwable("java.net.SocketTimeoutException: connect timed out")); +// } sslSocket.setSoTimeout(60000); sslSocket.connect(new InetSocketAddress(serverIP, serverPort), connectTimeout); - // MPU - sslSocket.startHandshake(); - - SSLSession session = sslSocket.getSession(); - - LogUtil.d(TAG, "SSL handshake success to " + serverIP + ":" + serverPort + "\n"); - LogUtil.d(TAG, "TLS handshake success to " + serverIP + ":" + serverPort + "\n"); - LogUtil.d(TAG, "TLS version: " + session.getProtocol() + "\n"); - LogUtil.d(TAG,"Cipher suite: " + session.getCipherSuite() + "\n"); - - try { - java.security.cert.Certificate[] chain = session.getPeerCertificates(); - if (chain != null && chain.length > 0) { - LogUtil.d(TAG,"Peer certificates:\n"); - for (int i = 0; i < chain.length; i++) { - X509Certificate x = (X509Certificate) chain[i]; - LogUtil.d(TAG, " [" + i + "] Subject: " + x.getSubjectX500Principal().getName() + "\n"); - LogUtil.d(TAG," Issuer: " + x.getIssuerX500Principal().getName() + "\n"); - LogUtil.d(TAG," Valid: " + formatDate(x.getNotBefore()) + " - " + formatDate(x.getNotAfter()) + "\n"); - } - } - } catch (Exception ignored) { } - inputStream = sslSocket.getInputStream(); outputStream = sslSocket.getOutputStream(); @@ -460,11 +407,6 @@ public class ISOSocket { int len = -1; if (reversalTestCaseFlag) { len = inputStream.read(recBuff); - } else { - int lenn = inputStream.read(recBuff); - - String received = ByteUtil.bytes2HexStr(recBuff); - LogUtil.d(TAG,"Received Response :"+received); } rLen = len; @@ -479,7 +421,7 @@ public class ISOSocket { subscriber.onComplete(); - } catch (IOException | + } catch (CertificateException | KeyStoreException | IOException | NoSuchAlgorithmException | KeyManagementException e) { e.printStackTrace(); subscriber.onError(e); @@ -516,17 +458,12 @@ public class ISOSocket { int len = -1; if (reversalTestCaseFlag) { len = inputStream.read(recBuff); - } else { - int lenn = inputStream.read(recBuff); - - String received = ByteUtil.bytes2HexStr(recBuff); - LogUtil.d(TAG,"Received Response :"+received); } rLen = len; if (rLen == -1) { - reversalTestCaseFlag = true; + reversalTestCaseFlag = true; subscriber.onError(new Throwable("length -1")); } else { subscriber.onNext(recBuff); diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/sign_on/SignOnProcess.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/sign_on/SignOnProcess.java index 3bc0ef8..d327dc3 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/sign_on/SignOnProcess.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/sign_on/SignOnProcess.java @@ -94,6 +94,7 @@ public class SignOnProcess { System.arraycopy(field62, 0, encryptedPIK, 0, 8); System.arraycopy(field62, 0, encryptedPIK, 8, 8); +// System.arraycopy(field62, 0, encryptedPIK, 0, 16); try { byte[] kcv = ByteUtil.hexStr2Bytes(TriDes.getKcv(encryptedPIK)); LogUtil.d(TAG, "Encrypted PIK:" + ByteUtil.bytes2HexStr(encryptedPIK)); @@ -122,6 +123,7 @@ public class SignOnProcess { System.arraycopy(field62, 0, encryptedPIK, 0, 8); System.arraycopy(field62, 0, encryptedPIK, 8, 8); + // System.arraycopy(field62, 0, encryptedPIK, 0, 16); try { diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/enums/HostName.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/enums/HostName.java index 12696b7..d70567a 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/enums/HostName.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/enums/HostName.java @@ -5,7 +5,8 @@ public enum HostName { FINEXUS("FINEXUS"), CARDZONE("CARDZONE"), - MPU("MPU"); + MPU("MPU"), + MOB("MOB"); public final String name; diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java index 880f88b..3e4ca4f 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java @@ -44,7 +44,7 @@ public class HostUtils { if (hostName == HostName.MPU) { bitmap = BitmapConfig.MPU_NEW_VOID; } else { - bitmap = BitmapConfig.FINEXUS_VOID; + bitmap = BitmapConfig.CZ_VOID; } break; case SETTLEMENT: diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java index 94cb21c..dcb8b89 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java @@ -193,6 +193,7 @@ public class BitmapConfig { public static final String MPU_NEW_CASH_ADVANCE="7020058020C09000"; public static final String CZ_SALE="7020058020C09000"; + public static final String CZ_VOID="723805802CC08010"; public static final String UPI_SALE = "7020058020C09200"; diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldConfig.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldConfig.java index 62a4ee0..6339241 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldConfig.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldConfig.java @@ -247,7 +247,7 @@ public class FieldConfig { // for TTIP MPU // /* FLD 35 */ {2, SDK_8583_LEN_BCD, 37, SDK_8583_DATA_BCD, SDK_8583_ALIGN_L, '0'}, - /* FLD 35 */ {2, SDK_8583_LEN_BCD, 37, SDK_8583_DATA_BCD, SDK_8583_ALIGN_R, '0'}, + /* FLD 35 */ {2, SDK_8583_LEN_BCD, 37, SDK_8583_DATA_BCD, SDK_8583_ALIGN_R, ' '}, /* FLD 36 */ {3, SDK_8583_LEN_BCD, 999, SDK_8583_DATA_BIT, SDK_8583_ALIGN_L, '0'}, /* FLD 37 */ {0, SDK_8583_LEN_BCD, 12, SDK_8583_DATA_ASC, SDK_8583_ALIGN_R, '0'}, diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java index 5af4b8e..0bf2ddb 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java @@ -4,11 +4,13 @@ import android.text.TextUtils; import com.sunmi.pay.hardware.aidl.AidlConstants; import com.utsmyanmar.paylibs.Constant; +import com.utsmyanmar.paylibs.batch_upload.BatchUploadProcess; import com.utsmyanmar.paylibs.model.MsgField; import com.utsmyanmar.paylibs.model.PayDetail; import com.utsmyanmar.paylibs.model.TradeData; import com.utsmyanmar.paylibs.model.enums.TransCVM; import com.utsmyanmar.paylibs.utils.enums.CardScheme; +import com.utsmyanmar.paylibs.utils.enums.HostName; import java.io.UnsupportedEncodingException; import java.util.Iterator; @@ -504,9 +506,12 @@ public class FieldUtils { break; case 60: //Private(oldMPU) //original Amount Void(new MPU) + String field60 = tradeData.getField60(); String lengthValue = String.format(Locale.getDefault(),"%04d", field60.length())+field60; field.setDataStr(lengthValue); + + break; case 61: // TODO diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java index bf8807b..816540d 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/params/Params.java @@ -83,7 +83,7 @@ public class Params { payDetail.transNum = System.currentTimeMillis() / 1000; // need to add host logic in another place // payDetail.setHostName("MPU"); - payDetail.setHostName("MPU"); + payDetail.setHostName("MOB"); // payDetail.setHostName("MOB"); payDetail.setOriginalTransDate(SystemDateTime.getMMDD()+SystemDateTime.getYYYY()); From f42ecdf6318037ff0e0834d023d7966b69a083bb Mon Sep 17 00:00:00 2001 From: kizzy Date: Wed, 24 Jun 2026 02:24:40 +0700 Subject: [PATCH 5/8] only left, pre auth functions for cz host --- .../utsmyanmar/ui/navigation/AppNavGraph.kt | 5 ++++- .../utsmyanmar/ui/pinpad/PinPadViewModel.kt | 6 +++++- .../ui/sending_to_host/SendingToHostRoute.kt | 2 +- .../ui/settlement/SettlementViewModel.kt | 5 +++++ .../java/com/mob/utsmyanmar/utils/MockCard.kt | 9 +++++++++ .../utsmyanmar/baselib/TerminalKeyUtil.java | 7 ++++--- .../batch_upload/BatchUploadProcess.java | 4 ++-- .../paylibs/isobuilder/DecodePackage.java | 3 ++- .../paylibs/isobuilder/EncodePackage.java | 1 + .../paylibs/isobuilder/builderx/ISOMsgX.java | 3 +++ .../utsmyanmar/paylibs/network/ISOSocket.java | 6 +----- .../paylibs/print/printx/PrintXImpl.java | 4 ++-- .../paylibs/reversal/ReversalAction.java | 6 +++--- .../utsmyanmar/paylibs/utils/MessageType.java | 1 + .../paylibs/utils/host_utils/HostUtils.java | 2 +- .../paylibs/utils/iso_utils/BitmapConfig.java | 5 ++++- .../paylibs/utils/iso_utils/FieldUtils.java | 17 ++++++++++++----- .../src/main/res/drawable/mob_print_logo.jpeg | Bin 0 -> 135190 bytes 18 files changed, 60 insertions(+), 26 deletions(-) create mode 100644 paylibs/src/main/res/drawable/mob_print_logo.jpeg diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt index fe47f0d..7080bbb 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt @@ -75,7 +75,10 @@ fun AppNavGraph( } composable(Routes.Dashboard.route) { - val sharedViewModel: SharedViewModel = hiltViewModel(activity); + val sharedViewModel: SharedViewModel = hiltViewModel(activity) + val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity) + + transProcessViewModel.resetTransactionStatus() DashboardScreen2( onNavigateAmount = { action -> if(action == "Sale"){ diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt index 8914840..e1fec34 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/pinpad/PinPadViewModel.kt @@ -8,6 +8,7 @@ import android.view.View import android.view.ViewTreeObserver import android.widget.TextView import androidx.lifecycle.ViewModel +import com.kizzy.cmhl.utils.ByteUtils import com.mob.utsmyanmar.config.Constants import com.mob.utsmyanmar.config.SunmiPayManager import com.mob.utsmyanmar.model.PinPadStatus @@ -554,10 +555,13 @@ class PinPadViewModel @Inject constructor( private fun getPanBytes(pan: String): ByteArray { + LogUtil.d(TAG,"pan : $pan") if (pan.length < 13) { return ByteArray(0) } - + LogUtil.d(TAG,"pan bytes : ${ByteUtils.byteArrayToHexString(pan + .substring(pan.length - 13, pan.length - 1) + .toByteArray(StandardCharsets.US_ASCII))}") return pan .substring(pan.length - 13, pan.length - 1) .toByteArray(StandardCharsets.US_ASCII) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt index 15a0619..ff5d20e 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/sending_to_host/SendingToHostRoute.kt @@ -52,7 +52,7 @@ fun ProcessingRoute( } } else { LaunchedEffect(Unit) { - transProcessViewModel.resetTransactionStatus() +// transProcessViewModel.resetTransactionStatus() transProcessViewModel.startOnlineProcess() } diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt b/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt index d9f0f90..236edc3 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/settlement/SettlementViewModel.kt @@ -341,6 +341,11 @@ class SettlementViewModel @Inject constructor( currentPayDetail.settleData = settlementData currentPayDetail.amount = totalAmount } else { + + LogUtil.d(TAG,"sale count :$totalSaleCount") + LogUtil.d(TAG,"sale amount :$totalSaleAmount") + LogUtil.d(TAG,"refund count :$totalRefundCount") + LogUtil.d(TAG,"refund amount :$totalRefundAmount") currentPayDetail.settleData = totalSaleCount + totalSaleAmount + diff --git a/app/src/main/java/com/mob/utsmyanmar/utils/MockCard.kt b/app/src/main/java/com/mob/utsmyanmar/utils/MockCard.kt index 043ce7b..43047d1 100644 --- a/app/src/main/java/com/mob/utsmyanmar/utils/MockCard.kt +++ b/app/src/main/java/com/mob/utsmyanmar/utils/MockCard.kt @@ -30,6 +30,7 @@ object MockData { // iccData="9503220100322798=300110100000942" // ) + //debit private val mockCardData: MockCardData = MockCardData( cardNo="9503032443884321", expDate="3102", @@ -38,6 +39,14 @@ object MockData { iccData="9503032443884321=310220100" ) +// private val mockCardData: MockCardData = MockCardData( +// cardNo="6244310039574344", +// expDate="3011", +// cardScheme="MPU", +// cardHolderName="Htin Kyaw Win", +// iccData="6244310039574344=30112011558125900000" +// ) + fun generateMPUCard(): CardDataX = CardDataX().apply { pan = mockCardData.cardNo exp = mockCardData.expDate diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/TerminalKeyUtil.java b/baselib/src/main/java/com/utsmyanmar/baselib/TerminalKeyUtil.java index be0ca8c..3d295b6 100644 --- a/baselib/src/main/java/com/utsmyanmar/baselib/TerminalKeyUtil.java +++ b/baselib/src/main/java/com/utsmyanmar/baselib/TerminalKeyUtil.java @@ -29,7 +29,8 @@ public final class TerminalKeyUtil { SecurityOptV2 mSecurityOptV2 = BaseApplication.getInstance().mSecurityOptV2; byte[] cvByte = ByteUtil.hexStr2Bytes("B7B520"); // byte[] dataByte = ByteUtil.hexStr2Bytes("e121249099a677e8b7d4f6a9d49fe8d1".toUpperCase()); // mpu - byte[] dataByte = ByteUtil.hexStr2Bytes("05FFB893726A5F1E59692D24E72E36AC"); +// byte[] dataByte = ByteUtil.hexStr2Bytes("05FFB893726A5F1E59692D24E72E36AC"); + byte[] dataByte = ByteUtil.hexStr2Bytes("DB7887664E3A06873342B753171896B1"); byte[] makBytes = ByteUtil.hexStr2Bytes("250738083EC15BD3BA67D66B8A7AA13B"); // byte[] makCvBytes = ByteUtil.hexStr2Bytes("204E449B97"); @@ -47,11 +48,11 @@ public final class TerminalKeyUtil { int result = 0; SystemParamsOperation.getInstance().setTMKIndex("9"); -// SystemParamsOperation.getInstance().setInjectOnce(false); + SystemParamsOperation.getInstance().setInjectOnce(false); if(!SystemParamsOperation.getInstance().isInjectOnce()) { try { // result = mSecurityOptV2.saveKeyDukpt(AidlConstantsV2.Security.KEY_TYPE_DUPKT_IPEK,IPEKByte,IPEKKCVByte,KSNByte,AidlConstantsV2.Security.KEY_ALG_TYPE_3DES,9); - result = mSecurityOptV2.savePlaintextKey(AidlConstantsV2.Security.KEY_TYPE_TMK,dataByte,cvByte,AidlConstantsV2.Security.KEY_ALG_TYPE_3DES,9); + result = mSecurityOptV2.savePlaintextKey(AidlConstantsV2.Security.KEY_TYPE_TMK,dataByte,null,AidlConstantsV2.Security.KEY_ALG_TYPE_3DES,9); LogUtil.d(ContentValues.TAG, "save TMK result:" + result); if (result != 0) { LogUtil.d(TAG, "save TMK fail"); diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/batch_upload/BatchUploadProcess.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/batch_upload/BatchUploadProcess.java index 2611391..66c4a70 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/batch_upload/BatchUploadProcess.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/batch_upload/BatchUploadProcess.java @@ -42,7 +42,7 @@ public class BatchUploadProcess { } private BatchUploadProcess() { - isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.BOTH_HEADER_TPDU,HostName.BPC) + isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.CARDZONE) .build(); } @@ -78,7 +78,7 @@ public class BatchUploadProcess { public void startBatchUpload(BatchListener batchListener) { HostName hostName = HostName.BPC; LogUtil.d(TAG, "Starting Batch Upload"); - byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.BPC_BATCH_UPLOAD, MessageType.BATCH_UPLOAD); + byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.CZ_BATCH_UPLOAD, MessageType.BATCH_UPLOAD); ISOSocket.getInstance().enqueue(sendBytes, sendBytes.length,false, new ISOCallback() { @Override public void onReceive(byte[] bytes, int length) { diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/DecodePackage.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/DecodePackage.java index 64c0894..32ae247 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/DecodePackage.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/DecodePackage.java @@ -409,7 +409,8 @@ public class DecodePackage { if(hostName == HostName.BPC) { System.arraycopy(body, tmpLen, nextData, 0, datLen); } else { - System.arraycopy(body, tmpLen, nextData, 0, body.length-tmpLen); +// System.arraycopy(body, tmpLen, nextData, 0, body.length-tmpLen); + System.arraycopy(body, tmpLen, nextData, 0, datLen); } // diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/EncodePackage.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/EncodePackage.java index 537b932..ac45800 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/EncodePackage.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/EncodePackage.java @@ -280,6 +280,7 @@ public class EncodePackage { System.arraycopy(fieldBody.getBytes(StandardCharsets.ISO_8859_1), 0, body, index, fieldBody.length()); index += fieldBody.length(); } else { + // MPU String fieldHead = msgField.getDataStr().substring(0,4); int bcdLen = (fieldHead.length() / 2) + (fieldHead.length() % 2); byte dat[] = new byte[bcdLen]; diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/builderx/ISOMsgX.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/builderx/ISOMsgX.java index 4cd0c31..bd7c630 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/builderx/ISOMsgX.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/isobuilder/builderx/ISOMsgX.java @@ -106,6 +106,9 @@ public class ISOMsgX extends BaseISOMsgX{ MTI = "0400"; // MTI = "0420"; break; + case CZ_REVERSAL: + MTI = "0420"; + break; case NETWORK_MANAGEMENT: MTI = "0800"; break; diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java index 9f5d0cc..879082c 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/network/ISOSocket.java @@ -356,11 +356,7 @@ public class ISOSocket { reversalSwitchFlag = SystemParamsOperation.getInstance().isReversalOn(); if (reversalSwitchFlag) { - if (reversalTrans) { - reversalTestCaseFlag = true; - } else { - reversalTestCaseFlag = false; - } + reversalTestCaseFlag = reversalTrans; } else { reversalTestCaseFlag = true; } diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/PrintXImpl.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/PrintXImpl.java index a7dfafc..b51dddf 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/PrintXImpl.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/PrintXImpl.java @@ -58,14 +58,14 @@ public class PrintXImpl extends BaseXPrint implements PrintX { opts.inJustDecodeBounds = true; // Step 1: Only read dimensions first - BitmapFactory.decodeResource(resources, R.drawable.print_logo_mpu, opts); + BitmapFactory.decodeResource(resources, R.drawable.mob_print_logo, opts); // Step 2: Calculate sample size so width <= 384px opts.inSampleSize = calculateInSampleSize(opts, 384, 384); opts.inJustDecodeBounds = false; // Step 3: Decode scaled-down bitmap - bitmap = BitmapFactory.decodeResource(resources, R.drawable.print_logo_mpu, opts); + bitmap = BitmapFactory.decodeResource(resources, R.drawable.mob_print_logo, opts); } @Override diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/reversal/ReversalAction.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/reversal/ReversalAction.java index 3060ccd..3588fda 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/reversal/ReversalAction.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/reversal/ReversalAction.java @@ -50,14 +50,14 @@ public class ReversalAction { } private ReversalAction() { - isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.FINEXUS) + isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.CARDZONE) .build(); } public ReversalAction setData(TradeData tradeData) { this.tradeData = tradeData; payDetail = tradeData.getPayDetail(); - payDetail.setTransactionType(TransactionType.REVERSAL); + payDetail.setTransactionType(TransactionsType.REVERSAL.value); // payDetail.setTransType(REVERSAL); if (TextUtils.equals(payDetail.getAccountType(), MPU)) { BITMAP = getBitmapMPU(payDetail); @@ -129,7 +129,7 @@ public class ReversalAction { public void startReversal(ReversalListener reversalListener) { HostName hostName = HostName.BPC; LogUtil.d(TAG, "Starting Reversal...."); - byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.MPU_NEW_REVERSAL, MessageType.REVERSAL); + byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.CZ_REVERSAL, MessageType.CZ_REVERSAL); // byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.BPC_AUTOMATIC_REVERSAL, MessageType.REVERSAL); ISOSocket.getInstance().enqueue(sendBytes, sendBytes.length,true, new ISOCallback() { @Override diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/MessageType.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/MessageType.java index 8873087..c1220d9 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/MessageType.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/MessageType.java @@ -5,6 +5,7 @@ public enum MessageType { AUTHORIZATION, AUTHORIZATION_COMPLETE, REVERSAL, + CZ_REVERSAL, NETWORK_MANAGEMENT, TC_ADVICE, BATCH_UPLOAD, diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java index 3e4ca4f..04499bc 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java @@ -86,7 +86,7 @@ public class HostUtils { if (hostName == HostName.MPU) { bitmap = BitmapConfig.MPU_NEW_REFUND; } else { - bitmap = BitmapConfig.CZ_SALE; + bitmap = BitmapConfig.CZ_REFUND; } break; case TIP_ADJUSTMENT: diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java index dcb8b89..db99191 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java @@ -193,7 +193,10 @@ public class BitmapConfig { public static final String MPU_NEW_CASH_ADVANCE="7020058020C09000"; public static final String CZ_SALE="7020058020C09000"; - public static final String CZ_VOID="723805802CC08010"; + public static final String CZ_VOID="7038058008C08010"; + public static final String CZ_REFUND="703C058008C08000"; + public static final String CZ_REVERSAL="7020078000C08000"; + public static final String CZ_BATCH_UPLOAD="703805800CC00010"; public static final String UPI_SALE = "7020058020C09200"; diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java index 0bf2ddb..d84bc0b 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/FieldUtils.java @@ -361,7 +361,7 @@ public class FieldUtils { // } else { // iterator.remove(); // } - field.setDataStr("001"); + field.setDataStr("000"); break; case 24: //Network International Identifier NII @@ -379,8 +379,9 @@ public class FieldUtils { if (payDetail.getTransactionType() == PRE_AUTH_SALE.value) { field.setDataStr("06"); } - else if(payDetail.getTransactionType() == REFUND.value) { - field.setDataStr("00"); // MPU + else if(payDetail.getTransactionType() == REFUND.value || payDetail.getTransactionType() == REVERSAL.value) { +// field.setDataStr("00"); // MPU + field.setDataStr("61"); // CZ } else if(payDetail.getCardType() == -1) { field.setDataStr("08"); } @@ -506,12 +507,16 @@ public class FieldUtils { break; case 60: //Private(oldMPU) //original Amount Void(new MPU) - +// String field60 = tradeData.getField60(); String lengthValue = String.format(Locale.getDefault(),"%04d", field60.length())+field60; field.setDataStr(lengthValue); + // for CardZone +// String field60 = tradeData.getField60(); +// String lengthValue = String.format(Locale.getDefault(),"%04d", field60.length())+field60; +// field.setDataStr(field60); break; case 61: // TODO @@ -538,7 +543,9 @@ public class FieldUtils { break; case 63: //Private Use String settleData = payDetail.getSettleData(); - field.setDataStr(settleData); + String settleValue = String.format(Locale.getDefault(),"%04d", settleData.length())+settleData; + field.setDataStr(settleValue); +// field.setDataStr(settleData); break; case 64: //Message Authentication Code (MAC) Required when the 39 field in the response message is "00" field.setDataStr("0000000000000000"); diff --git a/paylibs/src/main/res/drawable/mob_print_logo.jpeg b/paylibs/src/main/res/drawable/mob_print_logo.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..c5557f24531854a09f36a540ef436092457b6b2d GIT binary patch literal 135190 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∓Ut<{Whprf{{pxPln2rLDn`uwHdEzyC?Z#XZ)E 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

@Ql&Wqb^SuTV<)b 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 Date: Wed, 24 Jun 2026 19:41:12 +0700 Subject: [PATCH 6/8] cz_latest --- .../utsmyanmar/paylibs/utils/host_utils/HostUtils.java | 8 ++++---- .../utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java | 4 ++++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java index 04499bc..f903392 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/host_utils/HostUtils.java @@ -58,28 +58,28 @@ public class HostUtils { if (hostName == HostName.MPU) { bitmap = BitmapConfig.MPU_NEW_PRE_AUTH; } else { - bitmap = BitmapConfig.FUND_TRANSFER_PRE_CHECK; + bitmap = BitmapConfig.CZ_PRE_AUTH; } break; case PRE_AUTH_VOID: if (hostName == HostName.MPU) { bitmap = BitmapConfig.MPU_NEW_PRE_AUTH_CANCEL; } else { - bitmap = BitmapConfig.CZ_SALE; + bitmap = BitmapConfig.CZ_PRE_AUTH_VOID; } break; case PRE_AUTH_COMPLETE: if (hostName == HostName.MPU) { bitmap = BitmapConfig.MPU_NEW_PRE_AUTH_COMPLETE_BITMAP; } else { - bitmap = BitmapConfig.CZ_SALE; + bitmap = BitmapConfig.CZ_PRE_AUTH_COMP; } break; case PRE_AUTH_COMPLETE_VOID: if (hostName == HostName.MPU) { bitmap = BitmapConfig.MPU_NEW_PRE_AUTH_COMPLETE_CANCEL; } else { - bitmap = BitmapConfig.FINEXUS_PRE_AUTH_VOID; + bitmap = BitmapConfig.CZ_PRE_AUTH_COMP_VOID; } break; case REFUND: diff --git a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java index db99191..f36a75b 100644 --- a/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java +++ b/paylibs/src/main/java/com/utsmyanmar/paylibs/utils/iso_utils/BitmapConfig.java @@ -197,6 +197,10 @@ public class BitmapConfig { public static final String CZ_REFUND="703C058008C08000"; public static final String CZ_REVERSAL="7020078000C08000"; public static final String CZ_BATCH_UPLOAD="703805800CC00010"; + public static final String CZ_PRE_AUTH="7020058020C09000"; + public static final String CZ_PRE_AUTH_VOID="7038058028C08000"; + public static final String CZ_PRE_AUTH_COMP="703805802CC08000"; + public static final String CZ_PRE_AUTH_COMP_VOID="703805802CC08004"; public static final String UPI_SALE = "7020058020C09200"; From ac33bbd61f2e788ffe989476344746a37ec59e54 Mon Sep 17 00:00:00 2001 From: moon <56061215+MgKyawLay@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:34:58 +0630 Subject: [PATCH 7/8] fix nav graph --- .../utsmyanmar/ui/navigation/AppNavGraph.kt | 43 +++++++++---------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt index 7080bbb..8a77c6d 100644 --- a/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt +++ b/app/src/main/java/com/mob/utsmyanmar/ui/navigation/AppNavGraph.kt @@ -4,47 +4,46 @@ import android.annotation.SuppressLint import androidx.activity.ComponentActivity import androidx.compose.runtime.Composable import androidx.compose.ui.platform.LocalContext -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import androidx.navigation.NavType import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.navArgument import com.mob.utsmyanmar.model.ProcessCode -import com.mob.utsmyanmar.ui.input_amount.AmountRoute import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel import com.mob.utsmyanmar.ui.dashboard.DashboardScreen2 import com.mob.utsmyanmar.ui.dashboard.SeeMoreScreen import com.mob.utsmyanmar.ui.device_info.DeviceInfoViewModel +import com.mob.utsmyanmar.ui.functions.FunctionsScreen +import com.mob.utsmyanmar.ui.input_amount.AmountRoute import com.mob.utsmyanmar.ui.pinpad.PinPadRoute +import com.mob.utsmyanmar.ui.pinpad.PinPadViewModel +import com.mob.utsmyanmar.ui.print_receipt.PrintReceiptScreen import com.mob.utsmyanmar.ui.processing_card.ProcessingCardRoute import com.mob.utsmyanmar.ui.processing_card.ProcessingCardViewModel -import com.mob.utsmyanmar.ui.print_receipt.PrintReceiptScreen import com.mob.utsmyanmar.ui.refund_rrn.InputRrnRoute -import com.mob.utsmyanmar.ui.sign_on.SignOnResultScreen -import com.mob.utsmyanmar.ui.sign_on.SignOnRoute +import com.mob.utsmyanmar.ui.refund_rrn.RRNViewModel +import com.mob.utsmyanmar.ui.sale_void.TranDetailPage +import com.mob.utsmyanmar.ui.sale_void.VoidTraceScreen +import com.mob.utsmyanmar.ui.sale_void.VoidViewModel import com.mob.utsmyanmar.ui.sending_to_host.ProcessingRoute import com.mob.utsmyanmar.ui.settlement.SettlementScreen -import com.mob.utsmyanmar.ui.transaction_result.TransactionResultRoute -import com.mob.utsmyanmar.ui.sale_void.TranDetailPage -import com.mob.utsmyanmar.ui.sale_void.VoidViewModel -import com.mob.utsmyanmar.ui.sale_void.VoidTraceScreen -import com.mob.utsmyanmar.viewmodel.CardReaderViewModel -import com.mob.utsmyanmar.viewmodel.EmvTransactionProcessViewModel -import com.mob.utsmyanmar.ui.pinpad.PinPadViewModel import com.mob.utsmyanmar.ui.settlement.SettlementViewModel -import com.mob.utsmyanmar.ui.transaction_result.TransactionResultEvent -import com.mob.utsmyanmar.ui.transaction_result.TransactionResultViewModel -import com.mob.utsmyanmar.ui.functions.FunctionsScreen -import com.mob.utsmyanmar.ui.refund_rrn.RRNViewModel +import com.mob.utsmyanmar.ui.sign_on.SignOnResultScreen +import com.mob.utsmyanmar.ui.sign_on.SignOnRoute import com.mob.utsmyanmar.ui.tms_setup.TmsSetupRoute import com.mob.utsmyanmar.ui.tms_setup.TmsSetupViewModel +import com.mob.utsmyanmar.ui.transaction_result.TransactionResultEvent +import com.mob.utsmyanmar.ui.transaction_result.TransactionResultRoute +import com.mob.utsmyanmar.ui.transaction_result.TransactionResultViewModel import com.mob.utsmyanmar.ui.version.VersionScreen +import com.mob.utsmyanmar.viewmodel.CardReaderViewModel +import com.mob.utsmyanmar.viewmodel.EmvTransactionProcessViewModel import com.mob.utsmyanmar.viewmodel.SharedViewModel import com.mob.utsmyanmar.viewmodel.TransProcessViewModel -import com.utsmyanmar.ecr.data.TransType import com.utsmyanmar.paylibs.model.TradeData import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType @@ -70,7 +69,8 @@ fun AppNavGraph( } launchSingleTop = true } - } + }, + onNavigateDisable = {} ) } @@ -89,17 +89,14 @@ fun AppNavGraph( navController.navigate(Routes.Amount.createRoute(action)) { launchSingleTop = true } + }, onNavigateSignOn = { navController.navigate(Routes.SignOn.route) { launchSingleTop = true } }, - onNavigateSeeMore = { - navController.navigate(Routes.SeeMore.route) { - launchSingleTop = true - } - }, + onNavigateSettlement = { navController.navigate(Routes.Settlement.route) { launchSingleTop = true From 070c1589856b3d7b9f6565d1b97a4e77fea507cb Mon Sep 17 00:00:00 2001 From: moon <56061215+MgKyawLay@users.noreply.github.com> Date: Sun, 28 Jun 2026 18:35:05 +0630 Subject: [PATCH 8/8] Delete DashboardScreen2.kt --- .../ui/dashboard/DashboardScreen2.kt | 928 ------------------ 1 file changed, 928 deletions(-) delete mode 100644 app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt diff --git a/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt b/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt deleted file mode 100644 index fde1201..0000000 --- a/app/src/main/java/com/mob/utsmyanmar/ui/dashboard/DashboardScreen2.kt +++ /dev/null @@ -1,928 +0,0 @@ -package com.mob.utsmyanmar.ui.dashboard - -import android.os.Handler -import android.os.Looper -import androidx.compose.animation.core.tween -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.layout.width -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.foundation.pager.HorizontalPager -import androidx.compose.foundation.pager.rememberPagerState -import androidx.compose.foundation.shape.CircleShape -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.AccountBalanceWallet -import androidx.compose.material.icons.filled.BarChart -import androidx.compose.material.icons.filled.Check -import androidx.compose.material.icons.filled.ChevronRight -import androidx.compose.material.icons.filled.CreditCard -import androidx.compose.material.icons.filled.Lock -import androidx.compose.material.icons.filled.LockOpen -import androidx.compose.material.icons.filled.Menu -import androidx.compose.material.icons.filled.Notifications -import androidx.compose.material.icons.filled.Replay -import androidx.compose.material.icons.filled.SwapHoriz -import androidx.compose.material.icons.filled.Sync -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Card -import androidx.compose.material3.CardDefaults -import androidx.compose.material3.DrawerValue -import androidx.compose.material3.HorizontalDivider -import androidx.compose.material3.Icon -import androidx.compose.material3.IconButton -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.ModalDrawerSheet -import androidx.compose.material3.ModalNavigationDrawer -import androidx.compose.material3.Scaffold -import androidx.compose.material3.Switch -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.material3.VerticalDivider -import androidx.compose.material3.rememberDrawerState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.runtime.setValue -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.layout.ContentScale -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow -import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.compose.ui.unit.sp -import coil3.compose.AsyncImage -import com.mob.utsmyanmar.R -import com.mob.utsmyanmar.ui.components.appbar.AppBar -import com.mob.utsmyanmar.ui.device_info.DeviceInfoUiState -import com.mob.utsmyanmar.ui.preview.P2Preview -import com.mob.utsmyanmar.ui.preview.P3Preview -import com.mob.utsmyanmar.ui.theme.Color -import com.utsmyanmar.paylibs.sign_on.EchoTestProcess -import com.utsmyanmar.paylibs.sign_on.SignOnListener -import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch -import kotlin.time.Duration.Companion.milliseconds - -@Composable -fun DashboardScreen2( - onNavigateAmount: (String) -> Unit = {}, - onNavigateSignOn: () -> Unit = {}, - onNavigateSettlement: () -> Unit = {}, - onNavigateVersion: () -> Unit = {}, - onNavigateFunctions: () -> Unit = {}, - onNavigateAction: (String) -> Unit = {}, - onNavigateNotifications: () -> Unit = {}, - dashboardUiState: DashboardUiState = DashboardUiState(), - deviceInfo: DeviceInfoUiState = DeviceInfoUiState() -) { - - val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) - val scope = rememberCoroutineScope() - val mainHandler = remember { Handler(Looper.getMainLooper()) } - var showHostActionDialog by remember { mutableStateOf(false) } - var activeHostAction by remember { mutableStateOf("Log-On") } - var isHostActionRunning by remember { mutableStateOf(false) } - var dialogMessage by remember { mutableStateOf("") } - var reversalEnabled by remember { mutableStateOf(runCatching { SystemParamsOperation.getInstance().isReversalOn }.getOrDefault(false)) } - - val isOnline = true - - fun confirmationMessage(action: String) = "Do you want to start ${action.lowercase()}?" - fun processingMessage(action: String) = "Sending ${action.lowercase()} request to host..." - fun successMessage(action: String) = "$action success." - fun failureMessage(action: String, resultCode: Int?) = - "$action failed. Response code: ${resultCode ?: -1}" - - fun networkFailureMessage(action: String) = "Network error during $action." - fun openHostActionDialog(action: String) { - activeHostAction = action - isHostActionRunning = false - dialogMessage = confirmationMessage(action) - showHostActionDialog = true - } - - if (showHostActionDialog) { - AlertDialog( - onDismissRequest = { - if (!isHostActionRunning) { - showHostActionDialog = false - } - }, title = { - Text( - text = activeHostAction, color = Color.LegacyRed, fontWeight = FontWeight.Bold - ) - }, text = { - Text(text = dialogMessage) - }, confirmButton = { - TextButton( - onClick = { - if (isHostActionRunning) return@TextButton - - if (dialogMessage != confirmationMessage(activeHostAction)) { - showHostActionDialog = false - dialogMessage = confirmationMessage(activeHostAction) - return@TextButton - } - - isHostActionRunning = true - dialogMessage = processingMessage(activeHostAction) - - val signOnProcess = EchoTestProcess.getInstance() - val request = when (activeHostAction) { - "Echo Test" -> signOnProcess.enqueue(false) - "Log-Off" -> signOnProcess.enqueueLogOff() - else -> signOnProcess.enqueueLogOn() - } - - request.startSignOn(object : SignOnListener { - override fun onSuccessSignOn() { - mainHandler.post { - isHostActionRunning = false - dialogMessage = successMessage(activeHostAction) - } - } - - override fun onFailureSignOn(resultCode: Int?) { - mainHandler.post { - isHostActionRunning = false - mainHandler.post { - isHostActionRunning = false - dialogMessage = failureMessage(activeHostAction, resultCode) - } - } - } - - - override fun onNetworkFailSignOn(message: String?) { - mainHandler.post { - isHostActionRunning = false - dialogMessage = message?.takeIf { it.isNotBlank() } - ?: networkFailureMessage(activeHostAction) - } - } - }) - }) { - Text( - text = when { - isHostActionRunning -> "Processing" - dialogMessage == confirmationMessage(activeHostAction) -> "Start" - else -> "Close" - }, color = Color.LegacyRed - ) - } - }, dismissButton = { - if (!isHostActionRunning) { - TextButton( - onClick = { - showHostActionDialog = false - dialogMessage = confirmationMessage(activeHostAction) - }) { - Text(text = "Cancel", color = Color.Gray) - } - } - }, containerColor = Color.White - ) - } - - ModalNavigationDrawer( - drawerState = drawerState, drawerContent = { - ModalDrawerSheet( - modifier = Modifier.fillMaxWidth(0.78f), - drawerContainerColor = Color.White, - drawerShape = RoundedCornerShape(topEnd = 24.dp, bottomEnd = 24.dp) - ) { - Column( - modifier = Modifier - .fillMaxWidth() - .background(Color.IvoryBeige) - .padding(horizontal = 20.dp, vertical = 28.dp) - ) { - Row { - Box( - modifier = Modifier - .size(80.dp) - .clip(CircleShape) - .background(Color.White), contentAlignment = Alignment.Center - ) { - Image( - painter = painterResource(R.drawable.logo_mob), - contentDescription = "mob logo", - modifier = Modifier - .size(100.dp) - .padding(16.dp), - contentScale = ContentScale.Fit - ) - } - - Column { - Text( - text = "MOB Merchant", - color = Color.CrimsonRed, - fontSize = 12.sp, - fontWeight = FontWeight.Bold - ) - Text( - text = "S/N:${deviceInfo.serialNumber}", - color = Color.Black, - fontSize = 12.sp, - fontWeight = FontWeight.Bold - ) - Text( - text = if (isOnline) "Online" else "Offline", - color = if (isOnline) Color.Success else Color.Error, - fontSize = 12.sp, - fontWeight = FontWeight.Bold - ) - } - } - } - - Spacer(modifier = Modifier.height(10.dp)) - Text( - text = "Connection Settings", - fontWeight = FontWeight.Medium, - modifier = Modifier.padding(horizontal = 16.dp) - ) - - Item( - title = "Echo Test", subTitle = "Test Connection Status", - onClick = { - scope.launch { drawerState.close() } - openHostActionDialog("Echo Test") - }, - leadingIcon = { - Icon( - painterResource(R.drawable.ic_up_down_arrow), - contentDescription = "icon", - tint = Color.LegacyRed - ) - }, - trailingIcon = {}, - ) - Item( - title = "Log-On", subTitle = "Log on to System", - onClick = { - scope.launch { drawerState.close() } - openHostActionDialog("Log-On") - }, - leadingIcon = { - Icon( - painterResource(R.drawable.ic_lock), - contentDescription = "icon", - tint = Color.LegacyRed - ) - }, - trailingIcon = {}, - ) - Item( - title = "Log-Off", subTitle = "Log off from System", - onClick = { - scope.launch { drawerState.close() } - openHostActionDialog("Log-Off") - }, - leadingIcon = { - Icon( - painterResource(R.drawable.ic_cancel_circle), - contentDescription = "icon", - tint = Color.LegacyRed - ) - }, - trailingIcon = {}, - ) - Item( - title = "Reversal", subTitle = "Enable / Disable Reversal", - onClick = { - reversalEnabled = !reversalEnabled - runCatching { SystemParamsOperation.getInstance().setReversalFlag(reversalEnabled) } - }, - leadingIcon = { - Icon( - Icons.Default.Sync, - contentDescription = "icon", - tint = Color.LegacyRed - ) - }, - trailingIcon = { - Switch( - checked = reversalEnabled, - onCheckedChange = { isChecked -> - reversalEnabled = isChecked - runCatching { SystemParamsOperation.getInstance().setReversalFlag(isChecked) } - } - ) - }, - ) - - Text( - text = "System Management", - fontWeight = FontWeight.Medium, - modifier = Modifier.padding(horizontal = 16.dp) - ) - - Item( - title = "Functions", subTitle = "System Function Settings", - onClick = { - scope.launch { drawerState.close() } - onNavigateFunctions() - }, - leadingIcon = { - Icon( - painterResource(R.drawable.ic_four_boxes), - contentDescription = "icon", - tint = Color.LegacyRed, - modifier = Modifier.size(16.dp) - ) - }, - trailingIcon = {}, - ) - Item( - title = "Version", subTitle = "View App Version Info", - onClick = { - scope.launch { drawerState.close() } - onNavigateVersion() - }, - leadingIcon = { - Icon( - painterResource(R.drawable.ic_version), - contentDescription = "icon", - tint = Color.LegacyRed - ) - }, - trailingIcon = {}, - ) - - } - }) { -//body start - Scaffold( - containerColor = Color.IvoryBeige, topBar = { - AppBar( - title = "Dashboard", - icon = Icons.Default.Menu, - onIconClick = { scope.launch { drawerState.open() } }, - actions = { - IconButton(onClick = onNavigateNotifications) { - Box { - Icon( - imageVector = Icons.Default.Notifications, - contentDescription = "Notifications", - tint = Color.White - ) - Box( - modifier = Modifier - .size(8.dp) - .background(Color.GoldenGlow, CircleShape) - .align(Alignment.TopEnd) - .offset(x = 2.dp, y = (-2).dp) - ) - } - } - } - ) - }) { paddingValues -> - Column( - modifier = Modifier - .padding(paddingValues) - .fillMaxSize() - ) { - //top section - Box( - modifier = Modifier - .weight(1f) - .fillMaxWidth(), - ) { - AdvertisingArea() - } - //center section - Box( - modifier = Modifier - .weight(1f) - .fillMaxWidth(), - contentAlignment = Alignment.Center - ) { - SummaryCard() - } - //pager section - Box( - modifier = Modifier - .weight(1.3f) - .fillMaxWidth(), - ) { - MenuPager( - items = buildMenuItems( - onNavigateAmount = onNavigateAmount, - onNavigateSignOn = onNavigateSignOn, - onNavigateSettlement = onNavigateSettlement, - onNavigateAction = onNavigateAction - ), - modifier = Modifier.fillMaxSize() - ) - } - //transactions section - RecentTransactions( - transactions = dashboardUiState.recentTransactions, - modifier = Modifier - .weight(1.2f) - .fillMaxWidth() - ) - } - } - } -} - -@Composable -private fun AdvertisingArea() { - - val imageArray = listOf( - "https://i.ytimg.com/vi/eRUVxGRp1Ms/maxresdefault.jpg", - "https://i.ytimg.com/vi/AwvmgTPd7qw/maxresdefault.jpg", - "https://mma.prnewswire.com/media/2080956/SUNMI_3rd_generation_products_T3_PRO_series_V3_MIX.jpg?p=facebook" - ) - val pageState = rememberPagerState(pageCount = { imageArray.size }) - - LaunchedEffect(pageState) { - while (true) { - delay(10000.milliseconds) - val nextPage = (pageState.currentPage + 1) % imageArray.size - - pageState.animateScrollToPage( - page = nextPage, animationSpec = tween(durationMillis = 700) - ) - } - } - - Card( - modifier = Modifier.fillMaxSize(), - shape = RoundedCornerShape(0.dp), - colors = CardDefaults.cardColors(containerColor = Color.White), - ) { - HorizontalPager( - state = pageState, modifier = Modifier.fillMaxSize() - ) { page -> - AsyncImage( - model = imageArray[page], - contentDescription = "ads images", - modifier = Modifier.fillMaxSize(), - contentScale = ContentScale.Crop - ) - } - } -} - -@Composable -private fun SummaryCard() { - Card( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp), - shape = RoundedCornerShape(16.dp), - colors = CardDefaults.cardColors(containerColor = Color.White), - elevation = CardDefaults.cardElevation(4.dp) - ) { - Row(verticalAlignment = Alignment.CenterVertically) { - Column(modifier = Modifier.weight(1f)) { - SummaryItem( - title = "Sales Today", - value = "MMK 2,000,000", - subtitle = "47 Transactions", - icon = Icons.Default.BarChart, - iconBg = Color.CrimsonRed - ) - - HorizontalDivider( - color = Color.Gray, - modifier = Modifier.padding(vertical = 6.dp, horizontal = 6.dp) - ) - - SummaryItem( - title = "Settlement", - value = "Completed", - subtitle = "Today 11:00 PM", - icon = Icons.Default.Check, - iconBg = Color.CrimsonRed - ) - } - - VerticalDivider(color = Color.Gray, modifier = Modifier.height(160.dp)) - - Column( - modifier = Modifier - .weight(0.75f) - .padding(start = 18.dp), - horizontalAlignment = Alignment.Start - ) { - Row(verticalAlignment = Alignment.Bottom) { - Text( - text = "Last Sync", fontSize = 12.sp - ) - IconCircle(Icons.Default.Sync, Color.CrimsonRed) - } - - Spacer(Modifier.height(6.dp)) - - Text( - text = "5 mins ago", - fontSize = 18.sp, - color = Color.LegacyRed, - fontWeight = FontWeight.SemiBold - ) - } - } - } -} - -@Composable -private fun SummaryItem( - title: String, - value: String, - subtitle: String, - icon: ImageVector, - iconBg: androidx.compose.ui.graphics.Color -) { - Row( - verticalAlignment = Alignment.Top, modifier = Modifier.padding(6.dp) - ) { - Column(modifier = Modifier.weight(1f)) { - Text(title, fontSize = 12.sp) - Text( - value, fontSize = 14.sp, color = Color.LegacyRed, fontWeight = FontWeight.Bold - ) - Text(subtitle, fontSize = 12.sp) - } - IconCircle(icon, iconBg) - } -} - -@Composable -private fun IconCircle( - icon: ImageVector, color: androidx.compose.ui.graphics.Color -) { - Box( - modifier = Modifier - .size(38.dp) - .clip(CircleShape) - .background(color.copy(alpha = 0.1f)), - contentAlignment = Alignment.Center - ) { - Icon( - imageVector = icon, - contentDescription = null, - tint = color, - modifier = Modifier.size(22.dp) - ) - } -} - -private class DashboardMenuItem( - val title: String, - val iconContent: @Composable () -> Unit, - val onClick: () -> Unit -) - -@Composable -private fun buildMenuItems( - onNavigateAmount: (String) -> Unit, - onNavigateSignOn: () -> Unit, - onNavigateSettlement: () -> Unit, - onNavigateAction: (String) -> Unit -): List = listOf( - DashboardMenuItem("Sale", { Icon(painterResource(R.drawable.ic_terminal), contentDescription = null, modifier = Modifier.size(40.dp), tint = Color.LegacyRed) }) { onNavigateAmount("Sale") }, - DashboardMenuItem("MMQR", { Image(painter = painterResource(R.drawable.ic_mmqr_logo), contentDescription = null, modifier = Modifier.height(48.dp)) }) { }, - DashboardMenuItem("History", { Icon(painterResource(R.drawable.ic_history), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { }, - DashboardMenuItem("Sign On", { Icon(painterResource(R.drawable.ic_sign_on), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateSignOn() }, - DashboardMenuItem("Settlement", { Icon(painterResource(R.drawable.ic_settlement), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateSettlement() }, - DashboardMenuItem("Void", { Icon(Icons.Default.Lock, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Void") }, - DashboardMenuItem("Refund", { Icon(Icons.Default.Replay, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Refund") }, - DashboardMenuItem("Pre-Auth", { Icon(Icons.Default.Lock, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth") }, - DashboardMenuItem("Pre-Auth Void", { Icon(Icons.Default.LockOpen, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Void") }, - DashboardMenuItem("Pre-Auth Complete", { Icon(Icons.Default.CreditCard, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Complete") }, - DashboardMenuItem("Pre-Auth Complete Void", { Icon(Icons.Default.SwapHoriz, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Complete Void") }, - DashboardMenuItem("Cash Out", { Icon(Icons.Default.AccountBalanceWallet, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Cash Out") }, -) - -@Composable -private fun MenuPager( - items: List, - modifier: Modifier = Modifier -) { - val pages = items.chunked(6) - val pagerState = rememberPagerState(pageCount = { pages.size }) - - Column(modifier = modifier) { - HorizontalPager( - state = pagerState, - modifier = Modifier.weight(1f) - ) { pageIndex -> - MenuPage(items = pages[pageIndex]) - } - - Row( - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 8.dp), - horizontalArrangement = Arrangement.Center, - verticalAlignment = Alignment.CenterVertically - ) { - repeat(pages.size) { index -> - val selected = pagerState.currentPage == index - Box( - modifier = Modifier - .padding(horizontal = 4.dp) - .size(if (selected) 8.dp else 6.dp) - .background( - color = if (selected) Color.LegacyRed else Color.Gray.copy(alpha = 0.4f), - shape = CircleShape - ) - ) - } - } - } -} - -@Composable -private fun MenuPage(items: List) { - Column( - verticalArrangement = Arrangement.spacedBy(10.dp), - modifier = Modifier.padding(horizontal = 16.dp) - ) { - Spacer(Modifier.height(8.dp)) - items.chunked(3).forEach { rowItems -> - Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) { - rowItems.forEach { item -> - MenuCard( - title = item.title, - icon = item.iconContent, - modifier = Modifier.weight(1f), - onClick = item.onClick - ) - } - repeat(3 - rowItems.size) { - Spacer(modifier = Modifier.weight(1f)) - } - } - } - } -} - -@Composable -private fun MenuCard( - title: String, - icon: @Composable () -> Unit, - modifier: Modifier = Modifier, - onClick: (() -> Unit)? = null -) { - Card( - modifier = modifier - .height(100.dp) - .then( - if (onClick != null) { - Modifier.clickable(onClick = onClick) - } else { - Modifier - } - ), - shape = RoundedCornerShape(14.dp), - colors = CardDefaults.cardColors(containerColor = Color.White), - elevation = CardDefaults.cardElevation(5.dp) - ) { - Box( - modifier = Modifier - .fillMaxSize() - .padding(6.dp) - ) { - Column { - icon() - Spacer(modifier = Modifier.weight(1f)) - - Row( - modifier = Modifier.fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = title, - fontSize = 12.sp, - color = Color.Black, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - modifier = Modifier.weight(1f) - ) - Icon( - imageVector = Icons.Default.ChevronRight, - contentDescription = null, - tint = Color.LegacyRed, - modifier = Modifier.size(28.dp) - ) - } - } - } - } -} - -@Composable -private fun RecentTransactions( - transactions: List, - modifier: Modifier = Modifier -) { - Column(modifier = modifier) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 16.dp, vertical = 6.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = "Recent Transactions", - fontWeight = FontWeight.SemiBold, - fontSize = 14.sp - ) - } - HorizontalDivider( - modifier = Modifier.padding(horizontal = 16.dp), - color = Color.Gray.copy(alpha = 0.2f) - ) - LazyColumn(modifier = Modifier.fillMaxSize()) { - if (transactions.isEmpty()) { - item { - Text( - text = "No recent transactions", - color = Color.Gray, - fontSize = 13.sp, - textAlign = TextAlign.Center, - modifier = Modifier - .fillMaxWidth() - .padding(vertical = 24.dp) - ) - } - } else { - items(items = transactions, key = { it.pid }) { record -> - TrnxRow(record = record) - } - } - } - } -} - -@Composable -private fun TrnxRow(record: TrnxRecord) { - Row( - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 12.dp, vertical = 4.dp) - .clip(RoundedCornerShape(10.dp)) - .background(Color.White) - .padding(horizontal = 12.dp, vertical = 10.dp), - verticalAlignment = Alignment.CenterVertically - ) { - Box( - modifier = Modifier - .size(36.dp) - .background(Color.LegacyRed.copy(alpha = 0.1f), CircleShape), - contentAlignment = Alignment.Center - ) { - Text( - text = record.typeLabel.take(1), - color = Color.LegacyRed, - fontWeight = FontWeight.Bold, - fontSize = 15.sp - ) - } - - Spacer(Modifier.width(10.dp)) - - Column(modifier = Modifier.weight(1f)) { - Text( - text = if (record.isVoided) "${record.typeLabel} (Voided)" else record.typeLabel, - fontSize = 13.sp, - fontWeight = FontWeight.SemiBold, - color = if (record.isVoided) Color.Gray else Color.Black - ) - Text( - text = record.maskedCard, - fontSize = 11.sp, - color = Color.Gray - ) - } - - Column(horizontalAlignment = Alignment.End) { - Text( - text = record.amountDisplay, - fontSize = 13.sp, - fontWeight = FontWeight.Bold, - color = if (record.isVoided) Color.Gray else Color.LegacyRed - ) - Text( - text = record.dateTime, - fontSize = 10.sp, - color = Color.Gray - ) - } - } -} - -private val previewTransactions = listOf( - TrnxRecord(1L, "Sale", "MMK 10,000", "**** 1234", "06/10 14:32", isVoided = false, isApproved = true), - TrnxRecord(2L, "Void", "MMK 5,500", "**** 5678", "06/10 13:10", isVoided = true, isApproved = false), - TrnxRecord(3L, "Refund", "MMK 2,000", "**** 9012", "06/09 09:45", isVoided = false, isApproved = true), - TrnxRecord(4L, "Sale", "MMK 30,000", "**** 3456", "06/09 08:00", isVoided = false, isApproved = true), - TrnxRecord(5L, "Settlement", "MMK 0", "----", "06/08 18:00", isVoided = false, isApproved = true), -) - -@P3Preview -@P2Preview -@Composable -fun PreviewDashboardScreen2() { - DashboardScreen2(dashboardUiState = DashboardUiState(previewTransactions)) -} - -@Preview -@Composable -fun PreviewItem() { - Item( - onClick = {}, - title = "title", - subTitle = "sub-title" - ) -} - - -@Composable -fun Item( - onClick: () -> Unit, - title: String, - subTitle: String, - leadingIcon: (@Composable () -> Unit)? = null, - trailingIcon: (@Composable () -> Unit)? = null, -) { - Button( - onClick = onClick, - colors = ButtonDefaults.buttonColors( - containerColor = Color.White, - contentColor = Color.Black - ), - modifier = Modifier.fillMaxWidth() - ) { - Row( - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.SpaceBetween, - modifier = Modifier - .fillMaxWidth() - ) { - // Square icon background - leadingIcon?.let { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .size(40.dp) - .clip(RoundedCornerShape(16.dp)) // change to RectangleShape for sharp corners - .background(Color.LegacyRed.copy(alpha = 0.1f)) - .padding(8.dp) - ) { - it() - } - } - - Spacer(modifier = Modifier.width(12.dp)) - - Column( - modifier = Modifier - .weight(1f) - .padding(horizontal = 8.dp) - ) { - Text(text = title) - Text( - text = subTitle, - style = MaterialTheme.typography.bodySmall, - color = Color.Gray - ) - } - - trailingIcon?.invoke() - } - } -} \ No newline at end of file