Compare commits
9 Commits
8223b4877f
...
2323562270
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2323562270 | ||
|
|
c45c8adf65 | ||
|
|
2ca1b5eee0 | ||
|
|
bb9db73182 | ||
|
|
59153170bf | ||
|
|
726310a779 | ||
|
|
209279b847 | ||
|
|
7ccf393793 | ||
|
|
81920acc8c |
@ -40,8 +40,8 @@ android {
|
|||||||
dimension = "env"
|
dimension = "env"
|
||||||
applicationIdSuffix = ".uat"
|
applicationIdSuffix = ".uat"
|
||||||
versionNameSuffix = "-UAT"
|
versionNameSuffix = "-UAT"
|
||||||
versionCode = 15
|
versionCode = 17
|
||||||
versionName = "3.3"
|
versionName = "3.5"
|
||||||
buildConfigField("String", "ENV", "\"UAT\"")
|
buildConfigField("String", "ENV", "\"UAT\"")
|
||||||
resValue("string", "app_name", "MOB-UAT")
|
resValue("string", "app_name", "MOB-UAT")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,3 +38,6 @@ Mark intentional simplifications with a ponytail: comment. If the shortcut has a
|
|||||||
Not lazy about: understanding the problem (read it fully and trace the real flow before picking a rung, a small diff you don't understand is just laziness dressed up as efficiency), input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs (the platform is never the spec ideal, a clock drifts, a sensor reads off), anything explicitly requested. Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test.
|
Not lazy about: understanding the problem (read it fully and trace the real flow before picking a rung, a small diff you don't understand is just laziness dressed up as efficiency), input validation at trust boundaries, error handling that prevents data loss, security, accessibility, the calibration real hardware needs (the platform is never the spec ideal, a clock drifts, a sensor reads off), anything explicitly requested. Lazy code without its check is unfinished: non-trivial logic leaves ONE runnable check behind, the smallest thing that fails if the logic breaks (an assert-based demo/self-check or one small test file; no frameworks, no fixtures). Trivial one-liners need no test.
|
||||||
|
|
||||||
(Yes, this file also applies to agents working on the ponytail repo itself. Especially to them.)
|
(Yes, this file also applies to agents working on the ponytail repo itself. Especially to them.)
|
||||||
|
|
||||||
|
### Don't Do This
|
||||||
|
- don't run ./grdlew
|
||||||
@ -29,7 +29,7 @@ object SettlementScheduler {
|
|||||||
|
|
||||||
val configuredTime = parseTime(
|
val configuredTime = parseTime(
|
||||||
// SystemParamsOperation.getInstance().clearBatchTime
|
// SystemParamsOperation.getInstance().clearBatchTime
|
||||||
"10:50:00"
|
"21:35:00"
|
||||||
) ?: parseTime(FALLBACK_ALERT_TIME)!!
|
) ?: parseTime(FALLBACK_ALERT_TIME)!!
|
||||||
|
|
||||||
val calendar = Calendar.getInstance().apply {
|
val calendar = Calendar.getInstance().apply {
|
||||||
|
|||||||
@ -389,6 +389,10 @@ private fun CardLogoRow() {
|
|||||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
CardLogo(
|
||||||
|
icon = painterResource(R.drawable.logo_mpu),
|
||||||
|
name = "master",
|
||||||
|
)
|
||||||
CardLogo(
|
CardLogo(
|
||||||
icon = painterResource(R.drawable.logo_visa),
|
icon = painterResource(R.drawable.logo_visa),
|
||||||
name = "visa",
|
name = "visa",
|
||||||
@ -398,12 +402,12 @@ private fun CardLogoRow() {
|
|||||||
name = "master",
|
name = "master",
|
||||||
)
|
)
|
||||||
CardLogo(
|
CardLogo(
|
||||||
icon = painterResource(R.drawable.logo_mpu),
|
icon = painterResource(R.drawable.logo_union_pay),
|
||||||
name = "master",
|
name = "union",
|
||||||
)
|
)
|
||||||
CardLogo(
|
CardLogo(
|
||||||
icon = painterResource(R.drawable.logo_union_pay),
|
icon = painterResource(R.drawable.logo_jcb),
|
||||||
name = "master",
|
name = "jcb",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,10 +61,8 @@ class CardWaitingViewModel(
|
|||||||
retryCounter = 0
|
retryCounter = 0
|
||||||
fallbackCounter = SystemParamsOperation.getInstance().fallbackCounter
|
fallbackCounter = SystemParamsOperation.getInstance().fallbackCounter
|
||||||
fallbackEnabled = SystemParamsOperation.getInstance().fallbackEnabled
|
fallbackEnabled = SystemParamsOperation.getInstance().fallbackEnabled
|
||||||
val isSaleTransaction = sharedViewModel.transactionsType.value == TransactionsType.SALE
|
|
||||||
|
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(canGoBack = !isSaleTransaction)
|
it.copy(canGoBack = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sharedViewModel.transactionsType.value == TransactionsType.REFUND) {
|
if (sharedViewModel.transactionsType.value == TransactionsType.REFUND) {
|
||||||
|
|||||||
@ -23,8 +23,8 @@ import androidx.compose.ui.Alignment
|
|||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.mob.utsmyanmar.ui.theme.Color
|
import com.mob.utsmyanmar.ui.theme.Color
|
||||||
|
import com.mob.utsmyanmar.utils.convertDateString
|
||||||
import com.utsmyanmar.paylibs.model.PayDetail
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
import com.utsmyanmar.paylibs.utils.POSUtil
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun HistoryTransactionCard(
|
internal fun HistoryTransactionCard(
|
||||||
@ -54,7 +54,7 @@ internal fun HistoryTransactionCard(
|
|||||||
style = MaterialTheme.typography.titleSmall
|
style = MaterialTheme.typography.titleSmall
|
||||||
)
|
)
|
||||||
Text(
|
Text(
|
||||||
text = POSUtil.getInstance().formatAmount(payDetail.amount),
|
text = displayAmountWithSign(payDetail),
|
||||||
style = MaterialTheme.typography.titleSmall
|
style = MaterialTheme.typography.titleSmall
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -62,7 +62,7 @@ internal fun HistoryTransactionCard(
|
|||||||
Text("Trace ${payDetail.voucherNo.ifBlank { "-" }}", style = MaterialTheme.typography.bodySmall)
|
Text("Trace ${payDetail.voucherNo.ifBlank { "-" }}", style = MaterialTheme.typography.bodySmall)
|
||||||
Text("RRN ${payDetail.referNo.ifBlank { "-" }}", style = MaterialTheme.typography.bodySmall, color = Color.Gray)
|
Text("RRN ${payDetail.referNo.ifBlank { "-" }}", style = MaterialTheme.typography.bodySmall, color = Color.Gray)
|
||||||
Text(
|
Text(
|
||||||
"${payDetail.transDate} ${payDetail.transTime}",
|
"${convertDateString(payDetail.transDate)} ${payDetail.transTime}",
|
||||||
style = MaterialTheme.typography.bodySmall,
|
style = MaterialTheme.typography.bodySmall,
|
||||||
color = Color.Gray
|
color = Color.Gray
|
||||||
)
|
)
|
||||||
@ -85,13 +85,13 @@ internal fun HistoryTransactionDetailCard(payDetail: PayDetail) {
|
|||||||
color = Color.LegacyRed,
|
color = Color.LegacyRed,
|
||||||
style = MaterialTheme.typography.titleMedium
|
style = MaterialTheme.typography.titleMedium
|
||||||
)
|
)
|
||||||
SummaryLine("Trace", payDetail.voucherNo)
|
|
||||||
SummaryLine("Amount", POSUtil.getInstance().formatAmount(payDetail.amount))
|
|
||||||
SummaryLine("Card No", payDetail.cardNo)
|
|
||||||
SummaryLine("Reference", payDetail.referNo)
|
|
||||||
SummaryLine("Approval", payDetail.approvalCode.orEmpty())
|
|
||||||
SummaryLine("Date", payDetail.tradeDate)
|
SummaryLine("Date", payDetail.tradeDate)
|
||||||
SummaryLine("Time", payDetail.tradeTime)
|
SummaryLine("Time", payDetail.tradeTime)
|
||||||
|
SummaryLine("Amount", displayAmountWithSign(payDetail))
|
||||||
|
SummaryLine("Trace No", payDetail.voucherNo)
|
||||||
|
// SummaryLine("Card No", payDetail.cardNo)
|
||||||
|
SummaryLine("Reference No", payDetail.referNo)
|
||||||
|
SummaryLine("Approval Code", payDetail.approvalCode.orEmpty())
|
||||||
SummaryLine("Status", displayTransactionStatus(payDetail))
|
SummaryLine("Status", displayTransactionStatus(payDetail))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,6 +46,7 @@ internal fun displayTransactionTitle(payDetail: PayDetail): String {
|
|||||||
|
|
||||||
internal fun isValidForReprint(payDetail: PayDetail): Boolean {
|
internal fun isValidForReprint(payDetail: PayDetail): Boolean {
|
||||||
if (payDetail.transactionType == TransactionsType.SETTLEMENT.value) return false
|
if (payDetail.transactionType == TransactionsType.SETTLEMENT.value) return false
|
||||||
|
if (payDetail.transactionType == TransactionsType.REVERSAL.value) return false
|
||||||
if (payDetail.transactionType == TransactionsType.WAVEPAY.value && payDetail.qrTransStatus != 1) {
|
if (payDetail.transactionType == TransactionsType.WAVEPAY.value && payDetail.qrTransStatus != 1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -59,14 +60,8 @@ internal fun filterReprintAnyTransactions(
|
|||||||
transactions: List<PayDetail>,
|
transactions: List<PayDetail>,
|
||||||
hostType: HostType
|
hostType: HostType
|
||||||
): List<PayDetail> {
|
): List<PayDetail> {
|
||||||
val yesterday = POSUtil.getInstance().yesterdayDate
|
|
||||||
val dateFormat = SimpleDateFormat("dd/MM/yy", Locale.getDefault())
|
|
||||||
|
|
||||||
return transactions.filter { pay ->
|
return transactions.filter { pay ->
|
||||||
val transDate = parseTransDate(pay.transDate, dateFormat) ?: return@filter false
|
if (!isValidForReprint(pay)) return@filter false
|
||||||
if (yesterday.compareTo(transDate) > 0) return@filter false
|
|
||||||
if (pay.transactionType == TransactionsType.SETTLEMENT.value) return@filter false
|
|
||||||
if (pay.transactionType == TransactionsType.REVERSAL.value) return@filter false
|
|
||||||
|
|
||||||
when (hostType) {
|
when (hostType) {
|
||||||
HostType.MPU ->
|
HostType.MPU ->
|
||||||
@ -91,10 +86,7 @@ internal fun filterDetailReportTransactions(
|
|||||||
transactions: List<PayDetail>,
|
transactions: List<PayDetail>,
|
||||||
hostType: HostType
|
hostType: HostType
|
||||||
): List<PayDetail> {
|
): List<PayDetail> {
|
||||||
val yesterday = POSUtil.getInstance().yesterdayDate
|
|
||||||
|
|
||||||
return transactions.filter { pay ->
|
return transactions.filter { pay ->
|
||||||
if (POSUtil.getInstance().getDateByString(pay.transDate).before(yesterday)) return@filter false
|
|
||||||
if (pay.transactionType == TransactionsType.REVERSAL.value) return@filter false
|
if (pay.transactionType == TransactionsType.REVERSAL.value) return@filter false
|
||||||
if (pay.transactionType == TransactionsType.SETTLEMENT.value) return@filter false
|
if (pay.transactionType == TransactionsType.SETTLEMENT.value) return@filter false
|
||||||
|
|
||||||
@ -117,10 +109,20 @@ internal fun filterDetailReportTransactions(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun displayAmountWithSign(payDetail: PayDetail): String {
|
||||||
|
val prefix = if (payDetail.transactionType == TransactionsType.VOID.value ||
|
||||||
|
payDetail.transactionType == TransactionsType.REFUND.value ||
|
||||||
|
payDetail.transactionType == TransactionsType.WAVEPAY_REFUND.value ||
|
||||||
|
payDetail.transactionType == TransactionsType.CASH_OUT.value
|
||||||
|
) "-" else ""
|
||||||
|
return prefix + POSUtil.getInstance().formatAmount(payDetail.amount)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun detailReportSignedAmount(payDetail: PayDetail): Long {
|
internal fun detailReportSignedAmount(payDetail: PayDetail): Long {
|
||||||
val isNegative = payDetail.transactionType == TransactionsType.VOID.value ||
|
val isNegative = payDetail.transactionType == TransactionsType.VOID.value ||
|
||||||
payDetail.transactionType == TransactionsType.REFUND.value ||
|
payDetail.transactionType == TransactionsType.REFUND.value ||
|
||||||
payDetail.transactionType == TransactionsType.WAVEPAY_REFUND.value
|
payDetail.transactionType == TransactionsType.WAVEPAY_REFUND.value ||
|
||||||
|
payDetail.transactionType == TransactionsType.CASH_OUT.value
|
||||||
return if (isNegative) -payDetail.amount else payDetail.amount
|
return if (isNegative) -payDetail.amount else payDetail.amount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package com.mob.utsmyanmar.ui.history_functions
|
|||||||
|
|
||||||
import com.utsmyanmar.paylibs.model.PayDetail
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
import com.utsmyanmar.paylibs.model.SettleData
|
import com.utsmyanmar.paylibs.model.SettleData
|
||||||
import com.utsmyanmar.paylibs.utils.POSUtil
|
|
||||||
import com.utsmyanmar.paylibs.utils.enums.HostType
|
import com.utsmyanmar.paylibs.utils.enums.HostType
|
||||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
@ -31,9 +30,7 @@ internal fun buildSummarySettleData(
|
|||||||
start: Date,
|
start: Date,
|
||||||
end: Date,
|
end: Date,
|
||||||
): SettleData {
|
): SettleData {
|
||||||
val dateFormat = SimpleDateFormat("dd/MM/yy", Locale.getDefault())
|
|
||||||
val dateTimeFormat = SimpleDateFormat("dd/MM/yy HH:mm", Locale.getDefault())
|
val dateTimeFormat = SimpleDateFormat("dd/MM/yy HH:mm", Locale.getDefault())
|
||||||
val yesterday = POSUtil.getInstance().yesterdayDate
|
|
||||||
|
|
||||||
val wave = SummaryCounter()
|
val wave = SummaryCounter()
|
||||||
val waveRefund = SummaryCounter()
|
val waveRefund = SummaryCounter()
|
||||||
@ -47,14 +44,6 @@ internal fun buildSummarySettleData(
|
|||||||
val refund = SummaryCounter()
|
val refund = SummaryCounter()
|
||||||
|
|
||||||
for (pay in transactions) {
|
for (pay in transactions) {
|
||||||
val transDate = try {
|
|
||||||
dateFormat.parse(pay.transDate)
|
|
||||||
} catch (_: ParseException) {
|
|
||||||
continue
|
|
||||||
} ?: continue
|
|
||||||
|
|
||||||
if (yesterday.after(transDate)) continue
|
|
||||||
|
|
||||||
val currentDate = try {
|
val currentDate = try {
|
||||||
dateTimeFormat.parse("${pay.transDate} ${pay.transTime}")
|
dateTimeFormat.parse("${pay.transDate} ${pay.transTime}")
|
||||||
} catch (_: ParseException) {
|
} catch (_: ParseException) {
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
package com.mob.utsmyanmar.ui.history_functions
|
package com.mob.utsmyanmar.ui.history_functions
|
||||||
|
|
||||||
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.slideInVertically
|
||||||
|
import androidx.compose.animation.slideOutVertically
|
||||||
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
@ -10,11 +15,20 @@ import androidx.compose.foundation.layout.height
|
|||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material.icons.automirrored.rounded.Backspace
|
||||||
|
import androidx.compose.material3.Card
|
||||||
|
import androidx.compose.material3.CardDefaults
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
@ -23,12 +37,27 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.draw.shadow
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.mob.utsmyanmar.ui.components.appbar.AppBar
|
import androidx.compose.ui.unit.sp
|
||||||
|
import com.mob.utsmyanmar.ui.components.NumericKeypad
|
||||||
|
import com.mob.utsmyanmar.ui.preview.P2Preview
|
||||||
|
import com.mob.utsmyanmar.ui.preview.P3Preview
|
||||||
import com.mob.utsmyanmar.ui.theme.Color
|
import com.mob.utsmyanmar.ui.theme.Color
|
||||||
|
import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
|
||||||
import com.utsmyanmar.paylibs.model.PayDetail
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
import com.utsmyanmar.paylibs.utils.enums.HostType
|
import com.utsmyanmar.paylibs.utils.enums.HostType
|
||||||
|
|
||||||
|
private val searchKeys = listOf(
|
||||||
|
listOf("1", "2", "3"),
|
||||||
|
listOf("4", "5", "6"),
|
||||||
|
listOf("7", "8", "9"),
|
||||||
|
listOf("C", "0", "\u232B")
|
||||||
|
)
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ReprintAnyTransactionScreen(
|
fun ReprintAnyTransactionScreen(
|
||||||
viewModel: HistoryViewModel,
|
viewModel: HistoryViewModel,
|
||||||
@ -38,6 +67,7 @@ fun ReprintAnyTransactionScreen(
|
|||||||
) {
|
) {
|
||||||
val allTransactions by viewModel.getTransactionHistory().observeAsState(emptyList())
|
val allTransactions by viewModel.getTransactionHistory().observeAsState(emptyList())
|
||||||
var searchQuery by remember { mutableStateOf("") }
|
var searchQuery by remember { mutableStateOf("") }
|
||||||
|
var isFocused by remember { mutableStateOf(false) }
|
||||||
|
|
||||||
val filtered = remember(allTransactions, hostType, searchQuery) {
|
val filtered = remember(allTransactions, hostType, searchQuery) {
|
||||||
val base = filterReprintAnyTransactions(allTransactions, hostType)
|
val base = filterReprintAnyTransactions(allTransactions, hostType)
|
||||||
@ -47,10 +77,32 @@ fun ReprintAnyTransactionScreen(
|
|||||||
Scaffold(
|
Scaffold(
|
||||||
containerColor = Color.IvoryBeige,
|
containerColor = Color.IvoryBeige,
|
||||||
topBar = {
|
topBar = {
|
||||||
AppBar(
|
TopAppBar(
|
||||||
title = "Transactions",
|
title = {
|
||||||
icon = Icons.AutoMirrored.Filled.ArrowBack,
|
Column {
|
||||||
onIconClick = onBack
|
Text(
|
||||||
|
text = "Reprint Transaction",
|
||||||
|
style = MaterialTheme.typography.titleMedium
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = hostTypeLabel(hostType),
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
color = Color.Gray
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = onBack) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
|
||||||
|
contentDescription = "Back",
|
||||||
|
tint = Color.LegacyRed
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
colors = TopAppBarDefaults.topAppBarColors(
|
||||||
|
containerColor = Color.IvoryBeige
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) { paddingValues ->
|
) { paddingValues ->
|
||||||
@ -58,37 +110,154 @@ fun ReprintAnyTransactionScreen(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(paddingValues)
|
.padding(paddingValues)
|
||||||
.padding(16.dp)
|
.padding(horizontal = 16.dp)
|
||||||
) {
|
) {
|
||||||
OutlinedTextField(
|
SearchInputBox(
|
||||||
value = searchQuery,
|
query = searchQuery,
|
||||||
onValueChange = { searchQuery = it },
|
isFocused = isFocused,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
onFocus = { isFocused = true }
|
||||||
label = { Text("Trace (6) or RRN (12)") },
|
|
||||||
singleLine = true
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = "${filtered.size} transaction(s) found",
|
||||||
|
style = MaterialTheme.typography.labelSmall,
|
||||||
|
color = Color.Gray,
|
||||||
|
modifier = Modifier.padding(horizontal = 4.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
|
||||||
if (filtered.isEmpty()) {
|
if (filtered.isEmpty()) {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.weight(1f),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text("No transactions found.", color = Color.Gray)
|
Text(
|
||||||
|
text = if (allTransactions.isEmpty()) "No transactions available" else "No matching transactions",
|
||||||
|
color = Color.Gray,
|
||||||
|
style = MaterialTheme.typography.bodyMedium
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.weight(1f),
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
) {
|
) {
|
||||||
items(filtered, key = { "${it.voucherNo}_${it.referNo}_${it.PID}" }) { payDetail ->
|
items(filtered, key = { "${it.voucherNo}_${it.referNo}_${it.PID}" }) { payDetail ->
|
||||||
HistoryTransactionCard(payDetail) {
|
HistoryTransactionCard(payDetail) {
|
||||||
|
isFocused = false
|
||||||
onReprintTransaction(prepareReprintPayDetail(payDetail))
|
onReprintTransaction(prepareReprintPayDetail(payDetail))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = isFocused,
|
||||||
|
enter = slideInVertically(initialOffsetY = { it }),
|
||||||
|
exit = slideOutVertically(targetOffsetY = { it })
|
||||||
|
) {
|
||||||
|
NumericKeypad(
|
||||||
|
keys = searchKeys,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.height(280.dp)
|
||||||
|
.padding(top = 8.dp),
|
||||||
|
onKeyClick = { key ->
|
||||||
|
when (key) {
|
||||||
|
"C" -> searchQuery = ""
|
||||||
|
"\u232B" -> searchQuery = searchQuery.dropLast(1)
|
||||||
|
else -> if (searchQuery.length < 12) searchQuery += key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun SearchInputBox(
|
||||||
|
query: String,
|
||||||
|
isFocused: Boolean,
|
||||||
|
onFocus: () -> Unit,
|
||||||
|
) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clickable(onClick = onFocus),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = Color.White),
|
||||||
|
shape = RoundedCornerShape(12.dp),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = if (isFocused) 6.dp else 2.dp)
|
||||||
|
) {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp, vertical = 14.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
|
Text(
|
||||||
|
text = if (isFocused) "Trace or RRN" else "Tap to search by Trace or RRN",
|
||||||
|
style = MaterialTheme.typography.bodySmall,
|
||||||
|
color = if (isFocused) Color.LegacyRed else Color.Gray
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text(
|
||||||
|
text = query.ifEmpty { "_" },
|
||||||
|
color = Color.LegacyRed,
|
||||||
|
style = MaterialTheme.typography.headlineSmall.copy(
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
letterSpacing = 2.sp
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.isNotEmpty()) {
|
||||||
|
Card(
|
||||||
|
shape = RoundedCornerShape(18.dp),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = Color.White),
|
||||||
|
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp),
|
||||||
|
modifier = Modifier
|
||||||
|
.shadow(2.dp, RoundedCornerShape(18.dp))
|
||||||
|
.clickable { }
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.AutoMirrored.Rounded.Backspace,
|
||||||
|
contentDescription = "Delete",
|
||||||
|
tint = Color.LegacyRed,
|
||||||
|
modifier = Modifier.padding(horizontal = 14.dp, vertical = 12.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@P2Preview
|
||||||
|
@P3Preview
|
||||||
|
@Composable
|
||||||
|
private fun ReprintAnyTransactionScreenPreview() {
|
||||||
|
MOBPOSTheme {
|
||||||
|
Box(modifier = Modifier.height(600.dp)) {
|
||||||
|
Card(
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
colors = CardDefaults.cardColors(containerColor = Color.White)
|
||||||
|
) {
|
||||||
|
Column(modifier = Modifier.padding(16.dp)) {
|
||||||
|
Text(
|
||||||
|
text = "SALE",
|
||||||
|
color = Color.LegacyRed,
|
||||||
|
style = MaterialTheme.typography.titleSmall
|
||||||
|
)
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
Text("Trace 000001", style = MaterialTheme.typography.bodySmall)
|
||||||
|
Text("RRN 123456789012", style = MaterialTheme.typography.bodySmall, color = Color.Gray)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -171,16 +171,16 @@ fun InputAmount(
|
|||||||
Text("Cancel")
|
Text("Cancel")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val isAmountValid = amount.toDoubleOrNull()?.let { it > 0.0 } == true
|
||||||
|
|
||||||
Button(
|
Button(
|
||||||
onClick = {
|
onClick = {
|
||||||
if (amount.isNotEmpty()) {
|
onChargeClick(amount)
|
||||||
onChargeClick(amount)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.height(56.dp),
|
.height(56.dp),
|
||||||
enabled = amount.isNotEmpty(),
|
enabled = isAmountValid,
|
||||||
shape = RoundedCornerShape(8.dp),
|
shape = RoundedCornerShape(8.dp),
|
||||||
colors = ButtonDefaults.buttonColors(
|
colors = ButtonDefaults.buttonColors(
|
||||||
containerColor = Color.LegacyRed,
|
containerColor = Color.LegacyRed,
|
||||||
|
|||||||
@ -3,6 +3,7 @@ package com.mob.utsmyanmar.ui.print_receipt
|
|||||||
import androidx.compose.animation.core.Animatable
|
import androidx.compose.animation.core.Animatable
|
||||||
import androidx.compose.animation.core.FastOutSlowInEasing
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
|
import androidx.compose.foundation.Canvas
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.border
|
import androidx.compose.foundation.border
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
@ -32,20 +33,26 @@ import androidx.compose.runtime.setValue
|
|||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.geometry.Offset
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.graphics.graphicsLayer
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.platform.LocalInspectionMode
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
import com.mob.utsmyanmar.ui.components.appbar.AppBar
|
import com.mob.utsmyanmar.ui.components.appbar.AppBar
|
||||||
import com.mob.utsmyanmar.ui.history_functions.displayTransactionStatus
|
import com.mob.utsmyanmar.ui.history_functions.displayTransactionStatus
|
||||||
import com.mob.utsmyanmar.ui.history_functions.displayTransactionTitle
|
import com.mob.utsmyanmar.ui.history_functions.displayTransactionTitle
|
||||||
|
import com.mob.utsmyanmar.ui.preview.P2Preview
|
||||||
|
import com.mob.utsmyanmar.ui.preview.P3Preview
|
||||||
import com.mob.utsmyanmar.ui.theme.Color
|
import com.mob.utsmyanmar.ui.theme.Color
|
||||||
|
import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
|
||||||
import com.mob.utsmyanmar.ui.transaction_result.TransactionResultState
|
import com.mob.utsmyanmar.ui.transaction_result.TransactionResultState
|
||||||
import com.mob.utsmyanmar.ui.transaction_result.TransactionResultViewModel
|
import com.mob.utsmyanmar.ui.transaction_result.TransactionResultViewModel
|
||||||
|
import com.mob.utsmyanmar.utils.convertDateString
|
||||||
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||||
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
import com.utsmyanmar.paylibs.utils.POSUtil
|
import com.utsmyanmar.paylibs.utils.POSUtil
|
||||||
import com.utsmyanmar.paylibs.utils.PrintStatus
|
import com.utsmyanmar.paylibs.utils.PrintStatus
|
||||||
|
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
private enum class ReceiptCopy(val label: String) {
|
private enum class ReceiptCopy(val label: String) {
|
||||||
@ -59,9 +66,32 @@ fun PrintReceiptScreen(
|
|||||||
sharedViewModel: SharedViewModel,
|
sharedViewModel: SharedViewModel,
|
||||||
onPrint: () -> Unit,
|
onPrint: () -> Unit,
|
||||||
onDone: () -> Unit,
|
onDone: () -> Unit,
|
||||||
onPrintFinished : () -> Unit,
|
onPrintFinished: () -> Unit,
|
||||||
) {
|
) {
|
||||||
val state by transactionResultViewModel.state.collectAsStateWithLifecycle()
|
val state by transactionResultViewModel.state.collectAsStateWithLifecycle()
|
||||||
|
val isReprint = sharedViewModel.isReprint.value ?: false
|
||||||
|
|
||||||
|
PrintReceiptContent(
|
||||||
|
state = state,
|
||||||
|
isReprint = isReprint,
|
||||||
|
onPrint = onPrint,
|
||||||
|
onDone = onDone,
|
||||||
|
onPrintFinished = onPrintFinished,
|
||||||
|
onSetPrintStatus = { sharedViewModel.setPrintStatus(it) },
|
||||||
|
onResetReprint = { sharedViewModel.isReprint.value = false },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PrintReceiptContent(
|
||||||
|
state: TransactionResultState,
|
||||||
|
isReprint: Boolean,
|
||||||
|
onPrint: () -> Unit,
|
||||||
|
onDone: () -> Unit,
|
||||||
|
onPrintFinished: () -> Unit,
|
||||||
|
onSetPrintStatus: (PrintStatus) -> Unit,
|
||||||
|
onResetReprint: () -> Unit
|
||||||
|
) {
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val receiptOffsetY = remember { Animatable(0f) }
|
val receiptOffsetY = remember { Animatable(0f) }
|
||||||
val merchant_copy_autoprint = true
|
val merchant_copy_autoprint = true
|
||||||
@ -82,14 +112,11 @@ fun PrintReceiptScreen(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isReprintMode() = sharedViewModel.isReprint.value == true
|
|
||||||
|
|
||||||
fun doPrint(copy: ReceiptCopy, onFinished: (printFinished: ReceiptCopy) -> Unit) {
|
fun doPrint(copy: ReceiptCopy, onFinished: (printFinished: ReceiptCopy) -> Unit) {
|
||||||
val reprint = isReprintMode()
|
val actualCopy = if (isReprint && copy == ReceiptCopy.MERCHANT) ReceiptCopy.CUSTOMER else copy
|
||||||
val actualCopy = if (reprint && copy == ReceiptCopy.MERCHANT) ReceiptCopy.CUSTOMER else copy
|
|
||||||
currentCopy = actualCopy
|
currentCopy = actualCopy
|
||||||
|
|
||||||
sharedViewModel.setPrintStatus(
|
onSetPrintStatus(
|
||||||
if (actualCopy == ReceiptCopy.MERCHANT)
|
if (actualCopy == ReceiptCopy.MERCHANT)
|
||||||
PrintStatus.FIRST_PRINT
|
PrintStatus.FIRST_PRINT
|
||||||
else
|
else
|
||||||
@ -100,7 +127,7 @@ fun PrintReceiptScreen(
|
|||||||
isPrinting = true
|
isPrinting = true
|
||||||
animatePrint()
|
animatePrint()
|
||||||
isPrinting = false
|
isPrinting = false
|
||||||
val upcomingCopy = if (reprint) ReceiptCopy.CUSTOMER
|
val upcomingCopy = if (isReprint) ReceiptCopy.CUSTOMER
|
||||||
else if (actualCopy == ReceiptCopy.MERCHANT) ReceiptCopy.CUSTOMER
|
else if (actualCopy == ReceiptCopy.MERCHANT) ReceiptCopy.CUSTOMER
|
||||||
else ReceiptCopy.CUSTOMER
|
else ReceiptCopy.CUSTOMER
|
||||||
|
|
||||||
@ -112,14 +139,13 @@ fun PrintReceiptScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
val reprint = isReprintMode()
|
if (isReprint) {
|
||||||
if (reprint) {
|
|
||||||
currentCopy = ReceiptCopy.CUSTOMER
|
currentCopy = ReceiptCopy.CUSTOMER
|
||||||
nextCopy = ReceiptCopy.CUSTOMER
|
nextCopy = ReceiptCopy.CUSTOMER
|
||||||
}
|
}
|
||||||
sharedViewModel.isReprint.value = false
|
onResetReprint()
|
||||||
when {
|
when {
|
||||||
merchant_copy_autoprint && !reprint -> doPrint(ReceiptCopy.MERCHANT) { }
|
merchant_copy_autoprint && !isReprint -> doPrint(ReceiptCopy.MERCHANT) { }
|
||||||
customer_copy_autoprint -> doPrint(ReceiptCopy.CUSTOMER) { }
|
customer_copy_autoprint -> doPrint(ReceiptCopy.CUSTOMER) { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -209,6 +235,7 @@ fun ReceiptPreview(
|
|||||||
copyLabel: String,
|
copyLabel: String,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val isPreview = LocalInspectionMode.current
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
@ -239,17 +266,21 @@ fun ReceiptPreview(
|
|||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
ReceiptDivider()
|
ReceiptDivider()
|
||||||
ReceiptRow("Merchant", state.payDetail?.merchantName.toString() )
|
ReceiptRow("Date", convertDateString(state.payDetail?.transDate.toString()))
|
||||||
ReceiptRow("Terminal ID", state.payDetail?.terminalNo.toString() )
|
ReceiptRow("Time", state.payDetail?.transTime.toString())
|
||||||
ReceiptRow("Trace No", state.payDetail?.voucherNo.toString() )
|
ReceiptRow("Merchant Name", state.payDetail?.merchantName.toString())
|
||||||
ReceiptRow("Transaction", state.payDetail?.let(::displayTransactionTitle).orEmpty())
|
ReceiptRow("TID", state.payDetail?.terminalNo.toString())
|
||||||
ReceiptRow("Amount", POSUtil.getInstance().getDecimalAmountSeparatorFormat(state.payDetail?.amount?:0))
|
ReceiptRow("Trace No", state.payDetail?.voucherNo.toString())
|
||||||
|
ReceiptRow("Ref No", state.payDetail?.referNo.toString())
|
||||||
|
ReceiptRow("Approval Code", state.payDetail?.approvalCode.toString())
|
||||||
|
ReceiptRow("Transaction Type", state.payDetail?.let(::displayTransactionTitle).orEmpty())
|
||||||
|
ReceiptRow("Amount", POSUtil.getInstance().getDecimalAmountSeparatorFormat(state.payDetail?.amount?:0).let { amt ->
|
||||||
|
val prefix = POSUtil.getInstance().checkMinusSign(state.payDetail?.transactionType ?: 0)
|
||||||
|
if (prefix.isEmpty() && (state.payDetail?.transactionType ?: 0) == TransactionsType.CASH_OUT.value) "-$amt" else "$prefix$amt"
|
||||||
|
})
|
||||||
ReceiptRow("Card Type", state.payDetail?.accountType.toString())
|
ReceiptRow("Card Type", state.payDetail?.accountType.toString())
|
||||||
ReceiptRow("Card No", state.payDetail?.cardNo.toString())
|
ReceiptRow("Card No", state.payDetail?.cardNo.toString())
|
||||||
ReceiptRow("Status", state.payDetail?.let(::displayTransactionStatus).orEmpty())
|
ReceiptRow("Status", if (isPreview) "SUCCESS" else state.payDetail?.let(::displayTransactionStatus).orEmpty())
|
||||||
ReceiptRow("Date", state.payDetail?.transDate.toString() )
|
|
||||||
ReceiptRow("Time", state.payDetail?.transTime.toString())
|
|
||||||
ReceiptRow("Ref No", state.payDetail?.referNo.toString())
|
|
||||||
ReceiptDivider()
|
ReceiptDivider()
|
||||||
Spacer(modifier = Modifier.height(8.dp))
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
Text(
|
Text(
|
||||||
@ -292,25 +323,63 @@ fun ReceiptRow(
|
|||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ReceiptDivider() {
|
fun ReceiptDivider() {
|
||||||
Text(
|
Canvas(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(vertical = 10.dp),
|
.padding(vertical = 10.dp)
|
||||||
text = "--------------------------------",
|
.height(2.dp)
|
||||||
color = Color.Gray
|
) {
|
||||||
)
|
// Convert dp to pixels so it scales perfectly on all screen sizes
|
||||||
|
val dotRadius = 1.5.dp.toPx()
|
||||||
|
val dotSpacing = 6.dp.toPx()
|
||||||
|
|
||||||
|
val totalWidth = size.width
|
||||||
|
var currentX = 0f
|
||||||
|
|
||||||
|
// Loop across the width of the screen and draw individual circles
|
||||||
|
while (currentX < totalWidth) {
|
||||||
|
drawCircle(
|
||||||
|
color = Color.Gray,
|
||||||
|
radius = dotRadius,
|
||||||
|
center = Offset(x = currentX, y = size.height / 2)
|
||||||
|
)
|
||||||
|
// Move X forward by the size of the dot + the space we want
|
||||||
|
currentX += (dotRadius * 2) + dotSpacing
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(showBackground = true, showSystemUi = true)
|
@P2Preview
|
||||||
|
@P3Preview
|
||||||
@Composable
|
@Composable
|
||||||
fun PreviewPrintReceiptScreen() {
|
private fun PrintReceiptScreenPreview() {
|
||||||
MaterialTheme {
|
val samplePayDetail = PayDetail().apply {
|
||||||
PrintReceiptScreen(
|
merchantName = "Sample Merchant"
|
||||||
sharedViewModel = hiltViewModel(),
|
terminalNo = "12345678"
|
||||||
transactionResultViewModel = hiltViewModel(),
|
voucherNo = "000001"
|
||||||
|
amount = 100000
|
||||||
|
cardNo = "1234********5678"
|
||||||
|
transDate = "25-08-26"
|
||||||
|
transTime = "10:30:00"
|
||||||
|
referNo = "123456789012"
|
||||||
|
transType = "SALE"
|
||||||
|
tradeAnswerCode = "00"
|
||||||
|
approvalCode = "123456"
|
||||||
|
}
|
||||||
|
|
||||||
|
val sampleState = TransactionResultState(
|
||||||
|
payDetail = samplePayDetail
|
||||||
|
)
|
||||||
|
|
||||||
|
MOBPOSTheme {
|
||||||
|
PrintReceiptContent(
|
||||||
|
state = sampleState,
|
||||||
|
isReprint = false,
|
||||||
onPrint = {},
|
onPrint = {},
|
||||||
onDone = {},
|
onDone = {},
|
||||||
onPrintFinished = {}
|
onPrintFinished = {},
|
||||||
|
onSetPrintStatus = {},
|
||||||
|
onResetReprint = {}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,7 @@ import androidx.compose.ui.unit.dp
|
|||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
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.utils.convertDateString
|
||||||
import com.utsmyanmar.paylibs.model.PayDetail
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
import com.utsmyanmar.paylibs.utils.POSUtil
|
import com.utsmyanmar.paylibs.utils.POSUtil
|
||||||
|
|
||||||
@ -126,19 +127,18 @@ private fun TransactionDetailsCard(transaction: PayDetail) {
|
|||||||
verticalArrangement = Arrangement.spacedBy(10.dp)
|
verticalArrangement = Arrangement.spacedBy(10.dp)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Previous Sale",
|
text = "Void Sale",
|
||||||
color = Color.LegacyRed,
|
color = Color.LegacyRed,
|
||||||
fontWeight = FontWeight.Bold,
|
fontWeight = FontWeight.Bold,
|
||||||
fontSize = 16.sp
|
fontSize = 16.sp
|
||||||
)
|
)
|
||||||
|
DetailRow("Date", convertDateString(transaction.transDate))
|
||||||
DetailRow("Trace", transaction.voucherNo)
|
|
||||||
DetailRow("Amount", POSUtil.getInstance().formatAmount(transaction.amount))
|
|
||||||
DetailRow("Card No", transaction.cardNo)
|
|
||||||
DetailRow("Reference", transaction.referNo)
|
|
||||||
DetailRow("Approval", transaction.approvalCode.orEmpty())
|
|
||||||
DetailRow("Date", transaction.transDate)
|
|
||||||
DetailRow("Time", transaction.transTime)
|
DetailRow("Time", transaction.transTime)
|
||||||
|
DetailRow("Amount", POSUtil.getInstance().formatAmount(transaction.amount))
|
||||||
|
DetailRow("Trace No", transaction.voucherNo)
|
||||||
|
DetailRow("Reference No", transaction.referNo)
|
||||||
|
DetailRow("Approval Code", transaction.approvalCode.orEmpty())
|
||||||
|
// DetailRow("Card No", transaction.cardNo)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,7 +24,7 @@ import androidx.compose.ui.text.style.TextAlign
|
|||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.mob.utsmyanmar.ui.preview.P2Preview
|
import com.mob.utsmyanmar.ui.preview.P2Preview
|
||||||
import com.mob.utsmyanmar.ui.theme.Color
|
import com.mob.utsmyanmar.ui.theme.Color
|
||||||
import com.mob.utsmyanmar.utils.toFormattedDate
|
import com.mob.utsmyanmar.utils.convertDateString
|
||||||
import com.mob.utsmyanmar.utils.toFormattedTime
|
import com.mob.utsmyanmar.utils.toFormattedTime
|
||||||
import com.utsmyanmar.paylibs.model.PayDetail
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
import com.utsmyanmar.paylibs.print.PrintReceipt
|
import com.utsmyanmar.paylibs.print.PrintReceipt
|
||||||
@ -82,7 +82,7 @@ fun TransactionResultScreen(
|
|||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
InfoCard(
|
InfoCard(
|
||||||
date = "${state.payDetail?.transDate?.toFormattedDate()}",
|
date = convertDateString(state.payDetail?.transDate.toString()),
|
||||||
time = "${state.payDetail?.transTime?.toFormattedTime()}",
|
time = "${state.payDetail?.transTime?.toFormattedTime()}",
|
||||||
transactionId = state.payDetail?.referNo.toString()
|
transactionId = state.payDetail?.referNo.toString()
|
||||||
)
|
)
|
||||||
|
|||||||
@ -2,6 +2,7 @@ package com.mob.utsmyanmar.utils
|
|||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("DefaultLocale")
|
@SuppressLint("DefaultLocale")
|
||||||
fun Long?.formatAmount(): String {
|
fun Long?.formatAmount(): String {
|
||||||
val amount = (this ?: 0L) / 100.0
|
val amount = (this ?: 0L) / 100.0
|
||||||
@ -18,3 +19,7 @@ fun String?.maskCardNumber(): String {
|
|||||||
}
|
}
|
||||||
return maskedPan.toString()
|
return maskedPan.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun convertDateString(dateStr: String): String {
|
||||||
|
return dateStr.replace(Regex("/(\\d{2})$"), "/20$1")
|
||||||
|
}
|
||||||
BIN
app/src/main/res/drawable/logo_jcb.png
Normal file
BIN
app/src/main/res/drawable/logo_jcb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
BIN
app/src/main/res/drawable/logo_mob_always_with_you.png
Normal file
BIN
app/src/main/res/drawable/logo_mob_always_with_you.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 169 KiB |
@ -575,7 +575,7 @@ public class PrintReceipt {
|
|||||||
|
|
||||||
String receiptFooter = SystemParamsOperation.getInstance().getReceiptFooter();
|
String receiptFooter = SystemParamsOperation.getInstance().getReceiptFooter();
|
||||||
|
|
||||||
String finalVersion = SystemParamsOperation.getInstance().getFinalVersion();
|
// String finalVersion = SystemParamsOperation.getInstance().getFinalVersion();
|
||||||
|
|
||||||
sunmiPrinterService.sendRAWData(boldOn(), null);
|
sunmiPrinterService.sendRAWData(boldOn(), null);
|
||||||
sunmiPrinterService.setAlignment(1, null);
|
sunmiPrinterService.setAlignment(1, null);
|
||||||
@ -596,7 +596,7 @@ public class PrintReceipt {
|
|||||||
} else {
|
} else {
|
||||||
sunmiPrinterService.printText("***** CUSTOMER COPY *****" + "\n", null);
|
sunmiPrinterService.printText("***** CUSTOMER COPY *****" + "\n", null);
|
||||||
}
|
}
|
||||||
sunmiPrinterService.printText(finalVersion + "\n", null);
|
// sunmiPrinterService.printText(finalVersion + "\n", null);
|
||||||
sunmiPrinterService.printText(receiptFooter + "\n", null);
|
sunmiPrinterService.printText(receiptFooter + "\n", null);
|
||||||
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
|
|||||||
@ -155,6 +155,11 @@ public class PrintUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String toFullYearDate(String dateStr) {
|
||||||
|
if (TextUtils.isEmpty(dateStr)) return dateStr;
|
||||||
|
return dateStr.replaceFirst("/(\\d{2})$", "/20$1");
|
||||||
|
}
|
||||||
|
|
||||||
public String getFormatTransactionTime(String transTime) {
|
public String getFormatTransactionTime(String transTime) {
|
||||||
if (!TextUtils.equals("", transTime)) {
|
if (!TextUtils.equals("", transTime)) {
|
||||||
return transTime.substring(0, 2) + ":" + transTime.substring(2, 4) + ":" + transTime.substring(4, 6);
|
return transTime.substring(0, 2) + ":" + transTime.substring(2, 4) + ":" + transTime.substring(4, 6);
|
||||||
|
|||||||
@ -202,11 +202,11 @@ public abstract class BaseXPrint {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
String receiptFooter = SystemParamsOperation.getInstance().getReceiptFooter();
|
String receiptFooter = SystemParamsOperation.getInstance().getReceiptFooter();
|
||||||
String finalVersion = SystemParamsOperation.getInstance().getFinalVersion();
|
// String finalVersion = SystemParamsOperation.getInstance().getFinalVersion();
|
||||||
|
|
||||||
sunmiPrinterService.setFontSize(textSize, innerResultCallback);
|
sunmiPrinterService.setFontSize(textSize, innerResultCallback);
|
||||||
// sunmiPrinterService.printText("***** MERCHANT COPY *****" + "\n", innerResultCallback);
|
// sunmiPrinterService.printText("***** MERCHANT COPY *****" + "\n", innerResultCallback);
|
||||||
sunmiPrinterService.printText(finalVersion + "\n", innerResultCallback);
|
// sunmiPrinterService.printText(finalVersion + "\n", innerResultCallback);
|
||||||
sunmiPrinterService.printText(receiptFooter + "\n", innerResultCallback);
|
sunmiPrinterService.printText(receiptFooter + "\n", innerResultCallback);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -267,6 +267,7 @@ public abstract class BaseXPrint {
|
|||||||
}
|
}
|
||||||
sunmiPrinterService.printText("REF NUM : " + payDetail.getReferNo() + "\n", innerResultCallback);
|
sunmiPrinterService.printText("REF NUM : " + payDetail.getReferNo() + "\n", innerResultCallback);
|
||||||
sunmiPrinterService.printText("TRACE NO : " + payDetail.getVoucherNo() + "\n", innerResultCallback);
|
sunmiPrinterService.printText("TRACE NO : " + payDetail.getVoucherNo() + "\n", innerResultCallback);
|
||||||
|
sunmiPrinterService.printText("APR CODE : " + payDetail.getApprovalCode() + "\n", innerResultCallback);
|
||||||
// sunmiPrinterService.printColumnsString(new String[]{"REF NUM", ":" + payDetail.getReferNo()}, new int[]{1, 2}, new int[]{0, 0}, innerResultCallback);
|
// sunmiPrinterService.printColumnsString(new String[]{"REF NUM", ":" + payDetail.getReferNo()}, new int[]{1, 2}, new int[]{0, 0}, innerResultCallback);
|
||||||
// sunmiPrinterService.printColumnsString(new String[]{"TRACE No", ":" + payDetail.getVoucherNo()}, new int[]{1, 2}, new int[]{0, 0}, innerResultCallback);
|
// sunmiPrinterService.printColumnsString(new String[]{"TRACE No", ":" + payDetail.getVoucherNo()}, new int[]{1, 2}, new int[]{0, 0}, innerResultCallback);
|
||||||
|
|
||||||
@ -375,7 +376,7 @@ public abstract class BaseXPrint {
|
|||||||
try {
|
try {
|
||||||
sunmiPrinterService.setFontSize(20, innerResultCallback);
|
sunmiPrinterService.setFontSize(20, innerResultCallback);
|
||||||
sunmiPrinterService.setAlignment(0, innerResultCallback);
|
sunmiPrinterService.setAlignment(0, innerResultCallback);
|
||||||
sunmiPrinterService.printColumnsString(new String[]{"DATE :" + payDetail.getTransDate(), "TIME: " + payDetail.getTransTime()}, new int[]{2, 2}, new int[]{0, 2}, innerResultCallback);
|
sunmiPrinterService.printColumnsString(new String[]{"DATE :" + PrintUtils.getInstance().toFullYearDate(payDetail.getTransDate()), "TIME: " + payDetail.getTransTime()}, new int[]{2, 2}, new int[]{0, 2}, innerResultCallback);
|
||||||
if(Objects.equals(payDetail.getAccountType(), CardScheme.MPU_CTLS.name) || Objects.equals(payDetail.getAccountType(), CardScheme.UPI.name) ) {
|
if(Objects.equals(payDetail.getAccountType(), CardScheme.MPU_CTLS.name) || Objects.equals(payDetail.getAccountType(), CardScheme.UPI.name) ) {
|
||||||
hostName = HOST_NAME_MPU;
|
hostName = HOST_NAME_MPU;
|
||||||
} else {
|
} else {
|
||||||
@ -636,7 +637,7 @@ public abstract class BaseXPrint {
|
|||||||
|
|
||||||
for (PayDetail pay: lists) {
|
for (PayDetail pay: lists) {
|
||||||
|
|
||||||
boolean isNeedMinusSign = pay.getTransactionType() == TransactionsType.VOID.value || pay.getTransactionType() == TransactionsType.REFUND.value || pay.getTransactionType() == TransactionsType.WAVEPAY_REFUND.value || pay.getTransactionType() == TransactionsType.PRE_AUTH_COMPLETE_VOID.value;
|
boolean isNeedMinusSign = pay.getTransactionType() == TransactionsType.VOID.value || pay.getTransactionType() == TransactionsType.REFUND.value || pay.getTransactionType() == TransactionsType.WAVEPAY_REFUND.value || pay.getTransactionType() == TransactionsType.PRE_AUTH_COMPLETE_VOID.value || pay.getTransactionType() == TransactionsType.CASH_OUT.value;
|
||||||
|
|
||||||
if(hostType == HostType.MPU || hostType == HostType.VISA_MASTER) {
|
if(hostType == HostType.MPU || hostType == HostType.VISA_MASTER) {
|
||||||
sunmiPrinterService.printColumnsString(new String[]{pay.getAccountType() , PrintUtils.getInstance().maskCardNumberPciDss(pay.getCardNo())}, new int[]{2, 2}, new int[]{0, 2}, innerResultCallback);
|
sunmiPrinterService.printColumnsString(new String[]{pay.getAccountType() , PrintUtils.getInstance().maskCardNumberPciDss(pay.getCardNo())}, new int[]{2, 2}, new int[]{0, 2}, innerResultCallback);
|
||||||
@ -718,7 +719,7 @@ public abstract class BaseXPrint {
|
|||||||
|
|
||||||
String receiptFooter = SystemParamsOperation.getInstance().getReceiptFooter();
|
String receiptFooter = SystemParamsOperation.getInstance().getReceiptFooter();
|
||||||
|
|
||||||
String finalVersion = SystemParamsOperation.getInstance().getFinalVersion();
|
// String finalVersion = SystemParamsOperation.getInstance().getFinalVersion();
|
||||||
|
|
||||||
sunmiPrinterService.sendRAWData(boldOn(), innerResultCallback);
|
sunmiPrinterService.sendRAWData(boldOn(), innerResultCallback);
|
||||||
sunmiPrinterService.setAlignment(1, innerResultCallback);
|
sunmiPrinterService.setAlignment(1, innerResultCallback);
|
||||||
@ -761,7 +762,7 @@ public abstract class BaseXPrint {
|
|||||||
} else {
|
} else {
|
||||||
sunmiPrinterService.printText("***** CUSTOMER COPY *****" + "\n", innerResultCallback);
|
sunmiPrinterService.printText("***** CUSTOMER COPY *****" + "\n", innerResultCallback);
|
||||||
}
|
}
|
||||||
sunmiPrinterService.printText(finalVersion + "\n", innerResultCallback);
|
// sunmiPrinterService.printText(finalVersion + "\n", innerResultCallback);
|
||||||
sunmiPrinterService.printText(receiptFooter + "\n", innerResultCallback);
|
sunmiPrinterService.printText(receiptFooter + "\n", innerResultCallback);
|
||||||
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
@ -894,7 +895,7 @@ public abstract class BaseXPrint {
|
|||||||
try {
|
try {
|
||||||
sunmiPrinterService.setFontSize(18, innerResultCallback);
|
sunmiPrinterService.setFontSize(18, innerResultCallback);
|
||||||
sunmiPrinterService.setAlignment(0, innerResultCallback);
|
sunmiPrinterService.setAlignment(0, innerResultCallback);
|
||||||
sunmiPrinterService.printColumnsString(new String[]{"DATE :" + payDetail.getTransDate(), "TIME: " + payDetail.getTransTime()}, new int[]{2, 2}, new int[]{0, 2}, innerResultCallback);
|
sunmiPrinterService.printColumnsString(new String[]{"DATE :" + PrintUtils.getInstance().toFullYearDate(payDetail.getTransDate()), "TIME: " + payDetail.getTransTime()}, new int[]{2, 2}, new int[]{0, 2}, innerResultCallback);
|
||||||
if (payDetail.getTransactionType() == TransactionsType.WAVEPAY.value && payDetail.getQrTransStatus() == 1) {
|
if (payDetail.getTransactionType() == TransactionsType.WAVEPAY.value && payDetail.getQrTransStatus() == 1) {
|
||||||
sunmiPrinterService.printColumnsString(new String[]{"TRACE NO :" + traceNum, "INV NO: " + invoiceNo}, new int[]{2, 2}, new int[]{0, 2}, innerResultCallback);
|
sunmiPrinterService.printColumnsString(new String[]{"TRACE NO :" + traceNum, "INV NO: " + invoiceNo}, new int[]{2, 2}, new int[]{0, 2}, innerResultCallback);
|
||||||
} else if (!payDetail.getTransType().equals(SETTLEMENT) && !payDetail.getTransType().equals(SUMMARY) && payDetail.getTransactionType() != TransactionsType.WAVEPAY_REFUND.value && payDetail.getTransactionType() != TransactionsType.WAVEPAY.value) {
|
} else if (!payDetail.getTransType().equals(SETTLEMENT) && !payDetail.getTransType().equals(SUMMARY) && payDetail.getTransactionType() != TransactionsType.WAVEPAY_REFUND.value && payDetail.getTransactionType() != TransactionsType.WAVEPAY.value) {
|
||||||
|
|||||||
@ -48,14 +48,14 @@ public class PrintXImpl extends BaseXPrint implements PrintX {
|
|||||||
opts.inJustDecodeBounds = true;
|
opts.inJustDecodeBounds = true;
|
||||||
|
|
||||||
// Step 1: Only read dimensions first
|
// Step 1: Only read dimensions first
|
||||||
BitmapFactory.decodeResource(resources, R.drawable.mob_print_logo, opts);
|
BitmapFactory.decodeResource(resources, R.drawable.logo_mob_receipt, opts);
|
||||||
|
|
||||||
// Step 2: Calculate sample size so width <= 384px
|
// Step 2: Calculate sample size so width <= 384px
|
||||||
opts.inSampleSize = calculateInSampleSize(opts, 384, 384);
|
opts.inSampleSize = calculateInSampleSize(opts, 384, 384);
|
||||||
opts.inJustDecodeBounds = false;
|
opts.inJustDecodeBounds = false;
|
||||||
|
|
||||||
// Step 3: Decode scaled-down bitmap
|
// Step 3: Decode scaled-down bitmap
|
||||||
bitmap = BitmapFactory.decodeResource(resources, R.drawable.mob_print_logo, opts);
|
bitmap = BitmapFactory.decodeResource(resources, R.drawable.logo_mob_receipt, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -172,6 +172,7 @@ public class PrintXImpl extends BaseXPrint implements PrintX {
|
|||||||
try {
|
try {
|
||||||
setHeight(0x12);
|
setHeight(0x12);
|
||||||
printLogo();
|
printLogo();
|
||||||
|
sunmiPrinterService.lineWrap(1, innerResultCallback);
|
||||||
printMerchantHeader();
|
printMerchantHeader();
|
||||||
printTransHeader(payDetail);
|
printTransHeader(payDetail);
|
||||||
printTransDetailWave(payDetail);
|
printTransDetailWave(payDetail);
|
||||||
|
|||||||
BIN
paylibs/src/main/res/drawable/logo_mob_receipt.jpg
Normal file
BIN
paylibs/src/main/res/drawable/logo_mob_receipt.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 104 KiB |
Loading…
Reference in New Issue
Block a user