Compare commits
2 Commits
2937a747c8
...
af9a5487b1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af9a5487b1 | ||
|
|
46ef4521cc |
@ -449,7 +449,9 @@ fun DashboardScreen2(
|
|||||||
Spacer(Modifier.height(12.dp))
|
Spacer(Modifier.height(12.dp))
|
||||||
SummaryCard(
|
SummaryCard(
|
||||||
onClickLastSync = onClickLastSync,
|
onClickLastSync = onClickLastSync,
|
||||||
lastSyncTime = dashboardUiState.lastSyncTime
|
lastSyncTime = dashboardUiState.lastSyncTime,
|
||||||
|
totalSaleCount = dashboardUiState.totalSaleCount,
|
||||||
|
totalSaleAmount = dashboardUiState.totalSaleAmount
|
||||||
)
|
)
|
||||||
Spacer(Modifier.height(12.dp))
|
Spacer(Modifier.height(12.dp))
|
||||||
}
|
}
|
||||||
@ -527,7 +529,9 @@ private fun formatRelativeTime(timestamp: Long?, now: Long): String {
|
|||||||
@Composable
|
@Composable
|
||||||
private fun SummaryCard(
|
private fun SummaryCard(
|
||||||
onClickLastSync: () -> Unit,
|
onClickLastSync: () -> Unit,
|
||||||
lastSyncTime: Long?
|
lastSyncTime: Long?,
|
||||||
|
totalSaleCount: Int,
|
||||||
|
totalSaleAmount: Long
|
||||||
) {
|
) {
|
||||||
var now by remember { mutableLongStateOf(System.currentTimeMillis()) }
|
var now by remember { mutableLongStateOf(System.currentTimeMillis()) }
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@ -554,9 +558,9 @@ private fun SummaryCard(
|
|||||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||||
Column(modifier = Modifier.weight(1f)) {
|
Column(modifier = Modifier.weight(1f)) {
|
||||||
SummaryItem(
|
SummaryItem(
|
||||||
title = "Sales Today",
|
title = "Total Sale",
|
||||||
value = "MMK 2,000,000",
|
value = "MMK ${formatAmount(totalSaleAmount)}",
|
||||||
subtitle = "47 Transactions",
|
subtitle = "$totalSaleCount Transactions",
|
||||||
icon = Icons.Default.BarChart,
|
icon = Icons.Default.BarChart,
|
||||||
iconBg = Color.CrimsonRed
|
iconBg = Color.CrimsonRed
|
||||||
)
|
)
|
||||||
|
|||||||
@ -13,5 +13,7 @@ data class TrnxRecord(
|
|||||||
data class DashboardUiState(
|
data class DashboardUiState(
|
||||||
val recentTransactions: List<TrnxRecord> = emptyList(),
|
val recentTransactions: List<TrnxRecord> = emptyList(),
|
||||||
val lastSyncTime: Long? = null,
|
val lastSyncTime: Long? = null,
|
||||||
val carouselUrls: List<String> = emptyList()
|
val carouselUrls: List<String> = emptyList(),
|
||||||
|
val totalSaleCount: Int = 0,
|
||||||
|
val totalSaleAmount: Long = 0L
|
||||||
)
|
)
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.utsmyanmar.baselib.repo.Repository
|
import com.utsmyanmar.baselib.repo.Repository
|
||||||
import com.utsmyanmar.paylibs.model.PayDetail
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
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.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
@ -29,14 +30,16 @@ class DashboardViewModel @Inject constructor(
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
repository.getLastTenTransactions().asFlow().collect { payDetails ->
|
repository.getLastTenTransactions().asFlow().collect { payDetails ->
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
recentTransactions = payDetails.map { pd -> pd.toRecord() }
|
recentTransactions = payDetails.map { pd -> pd.toRecord() },
|
||||||
)
|
totalSaleCount = payDetails.totalSaleCount(),
|
||||||
}
|
totalSaleAmount = payDetails.totalSaleAmount()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
refreshLastSyncTime()
|
refreshLastSyncTime()
|
||||||
loadCarouselUrls()
|
loadCarouselUrls()
|
||||||
}
|
}
|
||||||
@ -58,36 +61,48 @@ class DashboardViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun PayDetail.toRecord(): TrnxRecord {
|
private fun PayDetail.toRecord(): TrnxRecord {
|
||||||
val type = transType?.takeIf { it.isNotBlank() }?.let { formatTypeLabel(it) } ?: "Transaction"
|
val baseType = transType?.takeIf { it.isNotBlank() }?.let { formatTypeLabel(it) } ?: "Transaction"
|
||||||
val amount = "MMK ${formatAmount(amount)}"
|
val type = if (isCanceled) "Void" else baseType
|
||||||
val card = CardNo?.takeIf { it.length >= 4 }?.let { "**** ${it.takeLast(4)}" } ?: "----"
|
val amountText = "MMK ${formatAmount(amount)}"
|
||||||
val dt = buildDateTime(TradeDate, TradeTime)
|
val card = CardNo?.takeIf { it.length >= 4 }?.let { "**** ${it.takeLast(4)}" } ?: "----"
|
||||||
|
val dt = buildDateTime(TradeDate, TradeTime)
|
||||||
val approved = tradeAnswerCode == "00" || approvalCode?.isNotBlank() == true
|
val approved = tradeAnswerCode == "00" || approvalCode?.isNotBlank() == true
|
||||||
|
|
||||||
return TrnxRecord(
|
return TrnxRecord(
|
||||||
pid = PID ?: 0L,
|
pid = PID ?: 0L,
|
||||||
typeLabel = type,
|
typeLabel = type,
|
||||||
amountDisplay= amount,
|
amountDisplay = amountText,
|
||||||
maskedCard = card,
|
maskedCard = card,
|
||||||
dateTime = dt,
|
dateTime = dt,
|
||||||
isVoided = isCanceled,
|
isVoided = isCanceled,
|
||||||
isApproved = approved
|
isApproved = approved
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun formatAmount(amount: Long): String {
|
fun formatAmount(amount: Long): String {
|
||||||
val scaled = BigDecimal(amount).movePointLeft(2)
|
val scaled = BigDecimal(amount).movePointLeft(2)
|
||||||
return DecimalFormat("#,###.00").format(scaled)
|
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 {
|
private fun formatTypeLabel(raw: String): String = when {
|
||||||
raw.contains("SALE", ignoreCase = true) -> "Sale"
|
raw.contains("SALE", ignoreCase = true) -> "Sale"
|
||||||
raw.contains("VOID", ignoreCase = true) -> "Void"
|
raw.contains("VOID", ignoreCase = true) -> "Void"
|
||||||
raw.contains("REFUND", ignoreCase = true) -> "Refund"
|
raw.contains("REFUND", ignoreCase = true) -> "Refund"
|
||||||
raw.contains("SETTLEMENT", ignoreCase = true) -> "Settlement"
|
raw.contains("SETTLEMENT", ignoreCase = true) -> "Settlement"
|
||||||
raw.contains("PRE", ignoreCase = true) -> "Pre-Auth"
|
raw.contains("PRE", ignoreCase = true) -> "Pre-Auth"
|
||||||
raw.contains("CASH", ignoreCase = true) -> "Cash Out"
|
raw.contains("CASH", ignoreCase = true) -> "Cash Out"
|
||||||
raw.contains("WAVE", ignoreCase = true) -> "Wave Pay"
|
raw.contains("WAVE", ignoreCase = true) -> "Wave Pay"
|
||||||
else -> raw.lowercase().replaceFirstChar { it.uppercaseChar() }
|
else -> raw.lowercase().replaceFirstChar { it.uppercaseChar() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
package com.mob.utsmyanmar.ui.navigation
|
package com.mob.utsmyanmar.ui.navigation
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
|
import android.os.Build
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
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.model.TradeData
|
||||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
@SuppressLint("ContextCastToActivity")
|
@SuppressLint("ContextCastToActivity")
|
||||||
@Composable
|
@Composable
|
||||||
fun AppNavGraph(
|
fun AppNavGraph(
|
||||||
@ -82,10 +86,27 @@ fun AppNavGraph(
|
|||||||
val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity)
|
val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity)
|
||||||
val dashboardViewModel: DashboardViewModel = hiltViewModel(activity)
|
val dashboardViewModel: DashboardViewModel = hiltViewModel(activity)
|
||||||
val dashboardUiState = dashboardViewModel.uiState.collectAsStateWithLifecycle().value
|
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()
|
transProcessViewModel.resetTransactionStatus()
|
||||||
DashboardScreen2(
|
DashboardScreen2(
|
||||||
dashboardUiState = dashboardUiState,
|
dashboardUiState = dashboardUiState,
|
||||||
|
deviceInfo = deviceInfoUiState,
|
||||||
|
onClickLastSync = {
|
||||||
|
tmsSetupViewModel.downloadConfigs()
|
||||||
|
},
|
||||||
onNavigateAmount = { action ->
|
onNavigateAmount = { action ->
|
||||||
when (action) {
|
when (action) {
|
||||||
"Sale" -> {
|
"Sale" -> {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import com.mob.utsmyanmar.model.sirius.SiriusResponse
|
import com.mob.utsmyanmar.model.sirius.SiriusResponse
|
||||||
import com.mob.utsmyanmar.model.sirius.TMSUpdate
|
import com.mob.utsmyanmar.model.sirius.TMSUpdate
|
||||||
import com.mob.utsmyanmar.model.sirius.ValidityStatus
|
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.TMSSetupsImpl
|
||||||
import com.mob.utsmyanmar.utils.tms.TMSUtil
|
import com.mob.utsmyanmar.utils.tms.TMSUtil
|
||||||
import com.utsmyanmar.baselib.BaseApplication
|
import com.utsmyanmar.baselib.BaseApplication
|
||||||
@ -49,6 +50,7 @@ class TmsSetupViewModel @Inject constructor(
|
|||||||
) : ViewModel() {
|
) : ViewModel() {
|
||||||
|
|
||||||
private val _uiState = MutableStateFlow(TmsSetupUiState())
|
private val _uiState = MutableStateFlow(TmsSetupUiState())
|
||||||
|
private val _dashboardUiState = MutableStateFlow(DashboardUiState())
|
||||||
val uiState: StateFlow<TmsSetupUiState> = _uiState.asStateFlow()
|
val uiState: StateFlow<TmsSetupUiState> = _uiState.asStateFlow()
|
||||||
|
|
||||||
private val _navigateToDashboard = MutableSharedFlow<Unit>()
|
private val _navigateToDashboard = MutableSharedFlow<Unit>()
|
||||||
@ -76,14 +78,15 @@ class TmsSetupViewModel @Inject constructor(
|
|||||||
it.copy(isLoading = true, isError = false, statusText = "Connecting to TMS server...")
|
it.copy(isLoading = true, isError = false, statusText = "Connecting to TMS server...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val disposable = repository.getParams(buildRequest())
|
val disposable = repository.getParams(buildRequest())
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(
|
.subscribe(
|
||||||
{ response ->
|
{ response ->
|
||||||
_uiState.update { it.copy(statusText = "Applying configuration...") }
|
_uiState.update { it.copy(
|
||||||
|
statusText = "Applying configuration...")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val appResponse = SiriusResponse(
|
val appResponse = SiriusResponse(
|
||||||
serial = response.serial.orEmpty(),
|
serial = response.serial.orEmpty(),
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.mob.utsmyanmar.viewmodel
|
package com.mob.utsmyanmar.viewmodel
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import com.mob.utsmyanmar.model.TransResultStatus
|
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.core_utils.SystemParamsOperation
|
||||||
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
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class TransProcessViewModel @Inject constructor(
|
class TransProcessViewModel @Inject constructor(
|
||||||
private val repository: Repository
|
private val repository: Repository,
|
||||||
|
@ApplicationContext private val context: Context
|
||||||
) : ViewModel(), ProcessingTransaction {
|
) : ViewModel(), ProcessingTransaction {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -184,6 +187,8 @@ class TransProcessViewModel @Inject constructor(
|
|||||||
_payDetailResult.value =
|
_payDetailResult.value =
|
||||||
payDetailRes
|
payDetailRes
|
||||||
|
|
||||||
|
stampLastSyncTime()
|
||||||
|
|
||||||
_transResultStatus.value =
|
_transResultStatus.value =
|
||||||
TransResultStatus.SUCCESS
|
TransResultStatus.SUCCESS
|
||||||
|
|
||||||
@ -252,6 +257,7 @@ class TransProcessViewModel @Inject constructor(
|
|||||||
repository.insertPayDetail(
|
repository.insertPayDetail(
|
||||||
updateCurrentDateAndTime(payResult)
|
updateCurrentDateAndTime(payResult)
|
||||||
)
|
)
|
||||||
|
stampLastSyncTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processRefundDB(payResult: PayDetail) {
|
override fun processRefundDB(payResult: PayDetail) {
|
||||||
@ -266,6 +272,7 @@ class TransProcessViewModel @Inject constructor(
|
|||||||
repository.insertPayDetail(
|
repository.insertPayDetail(
|
||||||
updateCurrentDateAndTime(payResult)
|
updateCurrentDateAndTime(payResult)
|
||||||
)
|
)
|
||||||
|
stampLastSyncTime()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun processPreVoidDb(payResult: PayDetail) {
|
override fun processPreVoidDb(payResult: PayDetail) {
|
||||||
@ -276,6 +283,7 @@ class TransProcessViewModel @Inject constructor(
|
|||||||
|
|
||||||
|
|
||||||
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
|
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
|
||||||
|
stampLastSyncTime()
|
||||||
}
|
}
|
||||||
override fun processPreCompDb(payResult: PayDetail) {
|
override fun processPreCompDb(payResult: PayDetail) {
|
||||||
if (oldTransPayDetail?.getAmount() == payResult.getAmount()) {
|
if (oldTransPayDetail?.getAmount() == payResult.getAmount()) {
|
||||||
@ -290,6 +298,7 @@ class TransProcessViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
|
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
|
||||||
|
stampLastSyncTime()
|
||||||
}
|
}
|
||||||
override fun processPreCompVoidDb(payResult: PayDetail) {
|
override fun processPreCompVoidDb(payResult: PayDetail) {
|
||||||
payDetail?.apply {
|
payDetail?.apply {
|
||||||
@ -297,6 +306,7 @@ class TransProcessViewModel @Inject constructor(
|
|||||||
repository.updatePayDetail(this)
|
repository.updatePayDetail(this)
|
||||||
}
|
}
|
||||||
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
|
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
|
* Utils
|
||||||
*/
|
*/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user