search void tran

This commit is contained in:
moon 2026-05-21 23:53:12 +06:30
parent dbc5424aab
commit 0f0bd49709
6 changed files with 136 additions and 19 deletions

View File

@ -24,7 +24,8 @@ import com.mob.utsmyanmar.ui.sign_on.SignOnResultScreen
import com.mob.utsmyanmar.ui.sign_on.SignOnRoute import com.mob.utsmyanmar.ui.sign_on.SignOnRoute
import com.mob.utsmyanmar.ui.sending_to_host.SendingToHostRoute import com.mob.utsmyanmar.ui.sending_to_host.SendingToHostRoute
import com.mob.utsmyanmar.ui.transaction_result.TransactionResultRoute import com.mob.utsmyanmar.ui.transaction_result.TransactionResultRoute
import com.mob.utsmyanmar.ui.void_trace.VoidTraceScreen 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.CardReaderViewModel
import com.mob.utsmyanmar.viewmodel.EmvTransactionProcessViewModel import com.mob.utsmyanmar.viewmodel.EmvTransactionProcessViewModel
import com.mob.utsmyanmar.ui.pinpad.PinPadViewModel import com.mob.utsmyanmar.ui.pinpad.PinPadViewModel
@ -83,10 +84,10 @@ fun AppNavGraph(
} }
composable(Routes.VoidTrace.route) { composable(Routes.VoidTrace.route) {
val sharedViewModel: SharedViewModel = hiltViewModel(activity) val voidViewModel: VoidViewModel = hiltViewModel()
VoidTraceScreen( VoidTraceScreen(
sharedViewModel = sharedViewModel, voidViewModel = voidViewModel,
onBack = { navController.popBackStack() } onBack = { navController.popBackStack() }
) )
} }
@ -259,7 +260,10 @@ fun AppNavGraph(
} }
composable(Routes.SendingToHost.route) { composable(Routes.SendingToHost.route) {
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
SendingToHostRoute( SendingToHostRoute(
sharedViewModel = sharedViewModel,
onNavigateTransactionResult = { onNavigateTransactionResult = {
navController.navigate(Routes.TransactionResult.route) { navController.navigate(Routes.TransactionResult.route) {
popUpTo(Routes.SendingToHost.route) { popUpTo(Routes.SendingToHost.route) {

View File

@ -83,6 +83,7 @@ class PinPadViewModel @Inject constructor(
MutableStateFlow<PinPadStatus?>(null) MutableStateFlow<PinPadStatus?>(null)
val pinStatus = _pinStatus.asStateFlow() val pinStatus = _pinStatus.asStateFlow()
private var isTerminalStateReached = false
/* /*
* Trade Data * Trade Data
@ -121,6 +122,7 @@ class PinPadViewModel @Inject constructor(
_alertMsg.value = null _alertMsg.value = null
_errorCode.value = null _errorCode.value = null
_pinStatus.value = null _pinStatus.value = null
isTerminalStateReached = false
} }
/* /*
@ -178,8 +180,10 @@ class PinPadViewModel @Inject constructor(
fun cancelPinPad() { fun cancelPinPad() {
try { try {
mPinPadOptV2?.cancelInputPin() if (!isTerminalStateReached) {
Log.d(TAG, "PinPad Canceled") mPinPadOptV2?.cancelInputPin()
Log.d(TAG, "PinPad Canceled")
}
} catch (e: RemoteException) { } catch (e: RemoteException) {
throw RuntimeException(e) throw RuntimeException(e)
} }
@ -401,17 +405,21 @@ class PinPadViewModel @Inject constructor(
ON_CONFIRM_CLICK -> { ON_CONFIRM_CLICK -> {
LogUtil.d(TAG, "ON CLICK CONFIRM") LogUtil.d(TAG, "ON CLICK CONFIRM")
isTerminalStateReached = true
_pinStatus.value = PinPadStatus.ON_CONFIRM _pinStatus.value = PinPadStatus.ON_CONFIRM
} }
ON_CANCEL_CLICK -> { ON_CANCEL_CLICK -> {
LogUtil.d(TAG, "ON CLICK CANCEL") LogUtil.d(TAG, "ON CLICK CANCEL")
_pinStatus.value = PinPadStatus.ON_CANCEL if (!isTerminalStateReached) {
_pinStatus.value = PinPadStatus.ON_CANCEL
}
} }
ON_ERROR_PIN_PAD -> { ON_ERROR_PIN_PAD -> {
LogUtil.d(TAG, "ON ERROR CODE: ${msg.arg1}") LogUtil.d(TAG, "ON ERROR CODE: ${msg.arg1}")
_errorCode.value = msg.arg1 _errorCode.value = msg.arg1
isTerminalStateReached = true
_pinStatus.value = PinPadStatus.ON_ERROR _pinStatus.value = PinPadStatus.ON_ERROR
} }
@ -420,11 +428,13 @@ class PinPadViewModel @Inject constructor(
} }
ON_TIMEOUT_PIN_PAD -> { ON_TIMEOUT_PIN_PAD -> {
isTerminalStateReached = true
_pinStatus.value = PinPadStatus.ON_TIMEOUT _pinStatus.value = PinPadStatus.ON_TIMEOUT
} }
ON_ERROR_DUKPT -> { ON_ERROR_DUKPT -> {
_alertMsg.value = "Try Again!" _alertMsg.value = "Try Again!"
isTerminalStateReached = true
_pinStatus.value = PinPadStatus.ON_ERROR_DUKPT _pinStatus.value = PinPadStatus.ON_ERROR_DUKPT
} }
} }
@ -466,6 +476,7 @@ class PinPadViewModel @Inject constructor(
payDetail?.cardType == -9 payDetail?.cardType == -9
if (!isCardValid) { if (!isCardValid) {
isTerminalStateReached = true
_pinStatus.value = PinPadStatus.ON_CARD_REMOVED _pinStatus.value = PinPadStatus.ON_CARD_REMOVED
return return
} }
@ -481,6 +492,7 @@ class PinPadViewModel @Inject constructor(
transType.value == TransactionsType.PRE_AUTH_VOID || transType.value == TransactionsType.PRE_AUTH_VOID ||
transType.value == TransactionsType.REFUND transType.value == TransactionsType.REFUND
) { ) {
isTerminalStateReached = true
_pinStatus.value = PinPadStatus.ON_NEXT_SCREEN _pinStatus.value = PinPadStatus.ON_NEXT_SCREEN
} else { } else {
handler.obtainMessage( handler.obtainMessage(
@ -490,9 +502,11 @@ class PinPadViewModel @Inject constructor(
} }
override fun onCancel() { override fun onCancel() {
handler.obtainMessage( if (!isTerminalStateReached) {
ON_CANCEL_CLICK handler.obtainMessage(
).sendToTarget() ON_CANCEL_CLICK
).sendToTarget()
}
} }
override fun onError(code: Int) { override fun onError(code: Int) {

View File

@ -1,4 +1,4 @@
package com.mob.utsmyanmar.ui.void_trace package com.mob.utsmyanmar.ui.sale_void
import android.util.Log import android.util.Log
import androidx.compose.foundation.background import androidx.compose.foundation.background
@ -40,26 +40,29 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.mob.utsmyanmar.ui.components.appbar.AppBar import com.mob.utsmyanmar.ui.components.appbar.AppBar
import com.mob.utsmyanmar.ui.theme.Color import com.mob.utsmyanmar.ui.theme.Color
import com.mob.utsmyanmar.viewmodel.SharedViewModel
import com.utsmyanmar.paylibs.model.PayDetail import com.utsmyanmar.paylibs.model.PayDetail
import com.utsmyanmar.paylibs.utils.POSUtil import com.utsmyanmar.paylibs.utils.POSUtil
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
@Composable @Composable
fun VoidTraceScreen( fun VoidTraceScreen(
sharedViewModel: SharedViewModel, voidViewModel: VoidViewModel,
onBack: () -> Unit = {} onBack: () -> Unit = {}
) { ) {
val tag = "VoidTraceScreen" val tag = "VoidTraceScreen"
var traceNumber by remember { mutableStateOf("") } var traceNumber by remember { mutableStateOf("") }
var searchedTrace by remember { mutableStateOf("") } var searchedTrace by remember { mutableStateOf("") }
val recentTransactions by sharedViewModel.getLastThreeTransactions().observeAsState(emptyList()) val recentTransactions by voidViewModel.getLastThreeTransactions().observeAsState(emptyList())
val transactionSource: LiveData<PayDetail?> = remember(searchedTrace) { val transactionSource: LiveData<PayDetail?> = remember(searchedTrace) {
if (searchedTrace.isBlank()) { if (searchedTrace.isBlank()) {
MutableLiveData(null) MutableLiveData<PayDetail?>(null)
} else { } else {
MutableLiveData(null) @Suppress("UNCHECKED_CAST")
voidViewModel.getVoidTrans(
TransactionsType.SALE.value,
searchedTrace
) as LiveData<PayDetail?>
} }
} }
val transaction by transactionSource.observeAsState() val transaction by transactionSource.observeAsState()
@ -74,8 +77,9 @@ fun VoidTraceScreen(
} else { } else {
Color.Black Color.Black
} }
LaunchedEffect(recentTransactions) { LaunchedEffect(searchedTrace, transaction) {
Log.d( Log.d(
tag, tag,
"Recent DB traces: ${ "Recent DB traces: ${
@ -84,15 +88,13 @@ fun VoidTraceScreen(
} }
}" }"
) )
}
LaunchedEffect(searchedTrace, transaction) {
if (searchedTrace.isNotBlank()) { if (searchedTrace.isNotBlank()) {
Log.d( Log.d(
tag, tag,
"Search trace=$searchedTrace result=${transaction?.voucherNo ?: "NOT_FOUND"}" "Search trace=$searchedTrace result=${transaction?.voucherNo ?: "NOT_FOUND"}"
) )
} }
} }
Scaffold( Scaffold(

View File

@ -0,0 +1,53 @@
package com.mob.utsmyanmar.ui.sale_void
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModel
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 javax.inject.Inject
@HiltViewModel
class VoidViewModel @Inject constructor(
private val repository: Repository
) : ViewModel() {
val inputTrace = SingleLiveEvent<String>()
val lists = SingleLiveEvent<List<PayDetail>>()
fun getVoidTransactions(transType: Int): LiveData<List<PayDetail>> {
return repository.getVoidableTransactions(transType)
}
fun getGenericVoidTransactions(
transType: Int,
voucherNo: String,
isEmv: Boolean
): LiveData<PayDetail> {
return repository.getGenericVoidTransaction(transType, voucherNo, isEmv)
}
fun getVoidTrans(transType: Int, voucherNo: String): LiveData<PayDetail> {
return repository.getVoidTransaction(transType, voucherNo)
}
fun observeVoidTrans(transType: Int) {
getVoidTransactions(transType).observeForever(object : Observer<List<PayDetail>> {
override fun onChanged(payDetails: List<PayDetail>) {
if (lists.value == null) {
lists.postValue(payDetails)
}
}
})
}
fun searchTransaction(voucherNo: String): LiveData<PayDetail> {
return repository.searchTransaction(voucherNo)
}
fun getLastThreeTransactions(): LiveData<List<PayDetail>> {
return repository.getLastThreeTransactions()
}
}

View File

@ -2,15 +2,18 @@ package com.mob.utsmyanmar.ui.sending_to_host
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import com.mob.utsmyanmar.viewmodel.SharedViewModel
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
private const val MOCK_HOST_DELAY_MS = 2000L private const val MOCK_HOST_DELAY_MS = 2000L
@Composable @Composable
fun SendingToHostRoute( fun SendingToHostRoute(
sharedViewModel: SharedViewModel,
onNavigateTransactionResult: () -> Unit onNavigateTransactionResult: () -> Unit
) { ) {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
sharedViewModel.saveMockApprovedSaleForVoidTesting()
delay(MOCK_HOST_DELAY_MS) delay(MOCK_HOST_DELAY_MS)
onNavigateTransactionResult() onNavigateTransactionResult()
} }

View File

@ -14,10 +14,12 @@ import com.utsmyanmar.paylibs.model.PayDetail
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt import com.utsmyanmar.paylibs.print.printx.PrintXReceipt
import com.utsmyanmar.paylibs.print.printx.PrintXStatus import com.utsmyanmar.paylibs.print.printx.PrintXStatus
import com.utsmyanmar.paylibs.system.SingleLiveEvent import com.utsmyanmar.paylibs.system.SingleLiveEvent
import com.utsmyanmar.paylibs.system.SystemDateTime
import com.utsmyanmar.paylibs.utils.AccountType import com.utsmyanmar.paylibs.utils.AccountType
import com.utsmyanmar.paylibs.utils.PrintStatus import com.utsmyanmar.paylibs.utils.PrintStatus
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
import com.utsmyanmar.paylibs.utils.enums.HostType import com.utsmyanmar.paylibs.utils.enums.HostType
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionType
import com.utsmyanmar.paylibs.utils.enums.TransMenu import com.utsmyanmar.paylibs.utils.enums.TransMenu
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@ -441,6 +443,45 @@ class SharedViewModel @Inject constructor(
repository.insertPayDetail(payDetail) repository.insertPayDetail(payDetail)
} }
fun saveMockApprovedSaleForVoidTesting() {
val detail = payDetail.value ?: return
val systemParams = SystemParamsOperation.getInstance()
val mockTraceNo = systemParams.incrementSerialNum
val mockInvoiceNo = systemParams.incrementInvoiceNum
val mockApprovalCode = mockTraceNo.takeLast(6).padStart(6, '0')
val mockReferenceNo = buildString {
append(SystemDateTime.getYYMMDD())
append(SystemDateTime.getHHmmss())
}.takeLast(12)
detail.voucherNo = mockTraceNo
detail.invoiceNo = mockInvoiceNo
detail.referNo = mockReferenceNo
detail.approvalCode = mockApprovalCode
detail.authNo = mockApprovalCode
detail.tradeAnswerCode = "00"
detail.tradeResultDes = "MOCK APPROVED"
detail.transactionType = TransactionType.SALE
detail.transType = TransactionsType.SALE.name
detail.isCanceled = false
detail.isSettle = false
detail.isNeedReversal = false
detail.isReturnGood = false
detail.TradeDate = SystemDateTime.getMMDD()
detail.TradeTime = SystemDateTime.getHHmmss()
detail.tradeDateAndTime = SystemDateTime.getMMDDhhmmss()
detail.tradeDateTime = SystemDateTime.getYYMMDDhhmmss()
detail.transDate = SystemDateTime.getTodayDateFormat()
detail.transTime = SystemDateTime.getTodayTimeFormat()
repository.insertPayDetail(detail)
payDetail.value = detail
traceNo.value = mockTraceNo
rrNNo.value = mockReferenceNo
approvalCode.value = mockApprovalCode
}
fun enableCardStatusIcon( fun enableCardStatusIcon(
tapCard: Boolean, tapCard: Boolean,
tapDevice: Boolean, tapDevice: Boolean,