Compare commits

...

2 Commits

Author SHA1 Message Date
moon
af9a5487b1 Update AppNavGraph.kt 2026-06-29 01:10:19 +06:30
moon
46ef4521cc show total sales 2026-06-29 01:03:15 +06:30
7 changed files with 98 additions and 36 deletions

View File

@ -449,7 +449,9 @@ fun DashboardScreen2(
Spacer(Modifier.height(12.dp))
SummaryCard(
onClickLastSync = onClickLastSync,
lastSyncTime = dashboardUiState.lastSyncTime
lastSyncTime = dashboardUiState.lastSyncTime,
totalSaleCount = dashboardUiState.totalSaleCount,
totalSaleAmount = dashboardUiState.totalSaleAmount
)
Spacer(Modifier.height(12.dp))
}
@ -527,7 +529,9 @@ private fun formatRelativeTime(timestamp: Long?, now: Long): String {
@Composable
private fun SummaryCard(
onClickLastSync: () -> Unit,
lastSyncTime: Long?
lastSyncTime: Long?,
totalSaleCount: Int,
totalSaleAmount: Long
) {
var now by remember { mutableLongStateOf(System.currentTimeMillis()) }
LaunchedEffect(Unit) {
@ -554,9 +558,9 @@ private fun SummaryCard(
Row(verticalAlignment = Alignment.CenterVertically) {
Column(modifier = Modifier.weight(1f)) {
SummaryItem(
title = "Sales Today",
value = "MMK 2,000,000",
subtitle = "47 Transactions",
title = "Total Sale",
value = "MMK ${formatAmount(totalSaleAmount)}",
subtitle = "$totalSaleCount Transactions",
icon = Icons.Default.BarChart,
iconBg = Color.CrimsonRed
)

View File

@ -13,5 +13,7 @@ data class TrnxRecord(
data class DashboardUiState(
val recentTransactions: List<TrnxRecord> = emptyList(),
val lastSyncTime: Long? = null,
val carouselUrls: List<String> = emptyList()
val carouselUrls: List<String> = emptyList(),
val totalSaleCount: Int = 0,
val totalSaleAmount: Long = 0L
)

View File

@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
import com.utsmyanmar.baselib.repo.Repository
import com.utsmyanmar.paylibs.model.PayDetail
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow
@ -32,7 +33,9 @@ class DashboardViewModel @Inject constructor(
repository.getLastTenTransactions().asFlow().collect { payDetails ->
_uiState.update {
it.copy(
recentTransactions = payDetails.map { pd -> pd.toRecord() }
recentTransactions = payDetails.map { pd -> pd.toRecord() },
totalSaleCount = payDetails.totalSaleCount(),
totalSaleAmount = payDetails.totalSaleAmount()
)
}
}
@ -58,8 +61,9 @@ class DashboardViewModel @Inject constructor(
}
private fun PayDetail.toRecord(): TrnxRecord {
val type = transType?.takeIf { it.isNotBlank() }?.let { formatTypeLabel(it) } ?: "Transaction"
val amount = "MMK ${formatAmount(amount)}"
val baseType = transType?.takeIf { it.isNotBlank() }?.let { formatTypeLabel(it) } ?: "Transaction"
val type = if (isCanceled) "Void" else baseType
val amountText = "MMK ${formatAmount(amount)}"
val card = CardNo?.takeIf { it.length >= 4 }?.let { "**** ${it.takeLast(4)}" } ?: "----"
val dt = buildDateTime(TradeDate, TradeTime)
val approved = tradeAnswerCode == "00" || approvalCode?.isNotBlank() == true
@ -67,7 +71,7 @@ private fun PayDetail.toRecord(): TrnxRecord {
return TrnxRecord(
pid = PID ?: 0L,
typeLabel = type,
amountDisplay= amount,
amountDisplay = amountText,
maskedCard = card,
dateTime = dt,
isVoided = isCanceled,
@ -75,11 +79,22 @@ private fun PayDetail.toRecord(): TrnxRecord {
)
}
fun formatAmount(amount: Long): String {
val scaled = BigDecimal(amount).movePointLeft(2)
return DecimalFormat("#,###.00").format(scaled)
}
private fun List<PayDetail>.totalSaleCount(): Int = count { it.isSaleTransaction() }
private fun List<PayDetail>.totalSaleAmount(): Long = sumOf {
if (it.isSaleTransaction()) it.amount else 0L
}
private fun PayDetail.isSaleTransaction(): Boolean {
return transactionType == TransactionsType.SALE.value ||
(transactionType == TransactionsType.WAVEPAY.value && qrTransStatus == 1)
}
private fun formatTypeLabel(raw: String): String = when {
raw.contains("SALE", ignoreCase = true) -> "Sale"
raw.contains("VOID", ignoreCase = true) -> "Void"

View File

@ -1,8 +1,11 @@
package com.mob.utsmyanmar.ui.navigation
import android.annotation.SuppressLint
import android.os.Build
import androidx.activity.ComponentActivity
import androidx.annotation.RequiresApi
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.platform.LocalContext
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
@ -50,6 +53,7 @@ import com.mob.utsmyanmar.viewmodel.TransProcessViewModel
import com.utsmyanmar.paylibs.model.TradeData
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
@RequiresApi(Build.VERSION_CODES.N)
@SuppressLint("ContextCastToActivity")
@Composable
fun AppNavGraph(
@ -82,10 +86,27 @@ fun AppNavGraph(
val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity)
val dashboardViewModel: DashboardViewModel = hiltViewModel(activity)
val dashboardUiState = dashboardViewModel.uiState.collectAsStateWithLifecycle().value
val deviceInfoViewModel: DeviceInfoViewModel = hiltViewModel(activity)
val deviceInfoUiState = deviceInfoViewModel.uiState.collectAsStateWithLifecycle().value
val tmsSetupViewModel: TmsSetupViewModel = hiltViewModel();
LaunchedEffect(deviceInfoViewModel) {
deviceInfoViewModel.loadDeviceInfo()
}
LaunchedEffect(tmsSetupViewModel) {
tmsSetupViewModel.onSyncCompleted.collect {
dashboardViewModel.refreshLastSyncTime()
}
}
transProcessViewModel.resetTransactionStatus()
DashboardScreen2(
dashboardUiState = dashboardUiState,
deviceInfo = deviceInfoUiState,
onClickLastSync = {
tmsSetupViewModel.downloadConfigs()
},
onNavigateAmount = { action ->
when (action) {
"Sale" -> {

View File

@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
import com.mob.utsmyanmar.model.sirius.SiriusResponse
import com.mob.utsmyanmar.model.sirius.TMSUpdate
import com.mob.utsmyanmar.model.sirius.ValidityStatus
import com.mob.utsmyanmar.ui.dashboard.DashboardUiState
import com.mob.utsmyanmar.utils.tms.TMSSetupsImpl
import com.mob.utsmyanmar.utils.tms.TMSUtil
import com.utsmyanmar.baselib.BaseApplication
@ -49,6 +50,7 @@ class TmsSetupViewModel @Inject constructor(
) : ViewModel() {
private val _uiState = MutableStateFlow(TmsSetupUiState())
private val _dashboardUiState = MutableStateFlow(DashboardUiState())
val uiState: StateFlow<TmsSetupUiState> = _uiState.asStateFlow()
private val _navigateToDashboard = MutableSharedFlow<Unit>()
@ -76,14 +78,15 @@ 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())
.subscribe(
{ response ->
_uiState.update { it.copy(statusText = "Applying configuration...") }
_uiState.update { it.copy(
statusText = "Applying configuration...")
}
val appResponse = SiriusResponse(
serial = response.serial.orEmpty(),

View File

@ -1,5 +1,6 @@
package com.mob.utsmyanmar.viewmodel
import android.content.Context
import android.text.TextUtils
import androidx.lifecycle.ViewModel
import com.mob.utsmyanmar.model.TransResultStatus
@ -17,13 +18,15 @@ import com.utsmyanmar.paylibs.utils.PrintStatus
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import javax.inject.Inject
@HiltViewModel
class TransProcessViewModel @Inject constructor(
private val repository: Repository
private val repository: Repository,
@ApplicationContext private val context: Context
) : ViewModel(), ProcessingTransaction {
companion object {
@ -184,6 +187,8 @@ class TransProcessViewModel @Inject constructor(
_payDetailResult.value =
payDetailRes
stampLastSyncTime()
_transResultStatus.value =
TransResultStatus.SUCCESS
@ -252,6 +257,7 @@ class TransProcessViewModel @Inject constructor(
repository.insertPayDetail(
updateCurrentDateAndTime(payResult)
)
stampLastSyncTime()
}
override fun processRefundDB(payResult: PayDetail) {
@ -266,6 +272,7 @@ class TransProcessViewModel @Inject constructor(
repository.insertPayDetail(
updateCurrentDateAndTime(payResult)
)
stampLastSyncTime()
}
override fun processPreVoidDb(payResult: PayDetail) {
@ -276,6 +283,7 @@ class TransProcessViewModel @Inject constructor(
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
stampLastSyncTime()
}
override fun processPreCompDb(payResult: PayDetail) {
if (oldTransPayDetail?.getAmount() == payResult.getAmount()) {
@ -290,6 +298,7 @@ class TransProcessViewModel @Inject constructor(
}
}
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
stampLastSyncTime()
}
override fun processPreCompVoidDb(payResult: PayDetail) {
payDetail?.apply {
@ -297,6 +306,7 @@ class TransProcessViewModel @Inject constructor(
repository.updatePayDetail(this)
}
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
stampLastSyncTime()
}
/*
@ -371,6 +381,13 @@ class TransProcessViewModel @Inject constructor(
})
}
private fun stampLastSyncTime() {
context.getSharedPreferences("mobpos_prefs", Context.MODE_PRIVATE)
.edit()
.putLong("last_sync_time", System.currentTimeMillis())
.apply()
}
/*
* Utils
*/