Compare commits
No commits in common. "752693c8f346212116154da8c8d6ddc0bd968ab5" and "5bb07df9e36fa2ac14af3e8e31eb88b64dfab873" have entirely different histories.
752693c8f3
...
5bb07df9e3
@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="temurin-21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|||||||
@ -11,9 +11,10 @@
|
|||||||
|
|
||||||
### version 3.4
|
### version 3.4
|
||||||
* disable display always on
|
* disable display always on
|
||||||
|
|
||||||
* auto-settlement
|
* auto-settlement
|
||||||
* show expiry date as "`**`/`**`"
|
* show expiry date as "`**`/`**`"
|
||||||
* align the customer name, in paper slip
|
* align the customer name, in paper slip
|
||||||
* settlement fixed in both UI and system
|
* settlement fixed in both UI and system
|
||||||
* amount, date, time fixed in Void Preview
|
* amount, date, time fixed in Void Preview
|
||||||
* show reversal status in trans records
|
* show reversal status in trans records
|
||||||
@ -19,10 +19,7 @@
|
|||||||
<uses-permission android:name="com.sunmi.perm.SECURITY" />
|
<uses-permission android:name="com.sunmi.perm.SECURITY" />
|
||||||
<uses-permission android:name="com.sunmi.perm.CONTACTLESS_CARD" />
|
<uses-permission android:name="com.sunmi.perm.CONTACTLESS_CARD" />
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
|
||||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
|
||||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
|
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
|
||||||
|
|||||||
@ -1,108 +1,41 @@
|
|||||||
package com.mob.utsmyanmar
|
package com.mob.utsmyanmar
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
import android.app.AlarmManager
|
|
||||||
import android.content.Intent
|
|
||||||
import android.content.pm.PackageManager
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.annotation.RequiresPermission
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
import androidx.core.view.WindowInsetsControllerCompat
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import com.mob.utsmyanmar.auto_settlement.SettlementScheduler
|
import com.mob.utsmyanmar.auto_settlement.SettlementScheduler
|
||||||
import com.mob.utsmyanmar.ui.navigation.AppNavGraph
|
import com.mob.utsmyanmar.ui.navigation.AppNavGraph
|
||||||
import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
|
import com.mob.utsmyanmar.ui.theme.MOBPOSTheme
|
||||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
private var autoSettlementRequested by mutableStateOf(false)
|
@RequiresPermission(Manifest.permission.SCHEDULE_EXACT_ALARM)
|
||||||
private var exactAlarmSettingsOpened = false
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
SettlementScheduler.schedule(this)
|
||||||
|
// installSplashScreen()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
autoSettlementRequested = intent?.getBooleanExtra("AUTO_SETTLEMENT", false) == true
|
|
||||||
requestNotificationPermission()
|
|
||||||
scheduleSettlementAlarm()
|
|
||||||
enableEdgeToEdge()
|
enableEdgeToEdge()
|
||||||
hideSystemBars()
|
hideSystemBars()
|
||||||
// window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
// window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||||
setContent {
|
setContent {
|
||||||
MOBPOSTheme {
|
MOBPOSTheme {
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
AppNavGraph(
|
AppNavGraph(navController = navController)
|
||||||
navController = navController,
|
|
||||||
autoSettlementRequested = autoSettlementRequested,
|
|
||||||
onAutoSettlementHandled = { autoSettlementRequested = false }
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNewIntent(intent: Intent) {
|
|
||||||
super.onNewIntent(intent)
|
|
||||||
setIntent(intent)
|
|
||||||
if (intent.getBooleanExtra("AUTO_SETTLEMENT", false)) {
|
|
||||||
autoSettlementRequested = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResume() {
|
|
||||||
super.onResume()
|
|
||||||
scheduleSettlementAlarm()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun requestNotificationPermission() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU &&
|
|
||||||
checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED
|
|
||||||
) {
|
|
||||||
requestPermissions(
|
|
||||||
arrayOf(Manifest.permission.POST_NOTIFICATIONS),
|
|
||||||
NOTIFICATION_PERMISSION_REQUEST_CODE
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun scheduleSettlementAlarm() {
|
|
||||||
if (!SystemParamsOperation.getInstance().isAutoSettlement()) {
|
|
||||||
SettlementScheduler.schedule(this)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
||||||
val alarmManager = getSystemService(AlarmManager::class.java)
|
|
||||||
if (!alarmManager.canScheduleExactAlarms()) {
|
|
||||||
if (!exactAlarmSettingsOpened) {
|
|
||||||
exactAlarmSettingsOpened = true
|
|
||||||
startActivity(
|
|
||||||
Intent(
|
|
||||||
Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM,
|
|
||||||
Uri.parse("package:$packageName")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
exactAlarmSettingsOpened = false
|
|
||||||
SettlementScheduler.schedule(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
const val NOTIFICATION_PERMISSION_REQUEST_CODE = 1003
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun hideSystemBars() {
|
private fun hideSystemBars() {
|
||||||
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
|
val windowInsetsController = WindowCompat.getInsetsController(window, window.decorView)
|
||||||
windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars())
|
windowInsetsController.hide(WindowInsetsCompat.Type.navigationBars())
|
||||||
|
|||||||
@ -4,32 +4,22 @@ import android.content.BroadcastReceiver
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import sunmi.sunmiui.utils.LogUtil
|
import sunmi.sunmiui.utils.LogUtil
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class AlarmReceiver : BroadcastReceiver() {
|
class AlarmReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
val appContext = context ?: return
|
val serviceIntent = Intent(context, AutoSettleService::class.java)
|
||||||
|
|
||||||
// Exact alarms are one-shot, so keep the next daily alarm alive before
|
|
||||||
// starting the foreground service.
|
|
||||||
if (!SettlementScheduler.schedule(appContext)) {
|
|
||||||
LogUtil.e(AlarmReceiver::class.java.simpleName, "Unable to reschedule settlement alarm")
|
|
||||||
}
|
|
||||||
|
|
||||||
val systemParams = SystemParamsOperation.getInstance()
|
|
||||||
if (!systemParams.isAutoSettlement() || !systemParams.settlementStatus) {
|
|
||||||
LogUtil.d(AlarmReceiver::class.java.simpleName, "Auto settlement is disabled")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val serviceIntent = Intent(appContext, AutoSettleService::class.java)
|
|
||||||
|
|
||||||
LogUtil.d(AlarmReceiver::class.java.simpleName, "Alert service")
|
LogUtil.d(AlarmReceiver::class.java.simpleName, "Alert service")
|
||||||
|
|
||||||
ContextCompat.startForegroundService(appContext, serviceIntent)
|
if (context != null) {
|
||||||
|
ContextCompat.startForegroundService(
|
||||||
|
context,
|
||||||
|
serviceIntent
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
LogUtil.d(AlarmReceiver::class.java.simpleName, "Foreground service")
|
LogUtil.d(AlarmReceiver::class.java.simpleName, "Foreground service")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,16 +3,13 @@ package com.mob.utsmyanmar.auto_settlement
|
|||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.media.AudioAttributes
|
import android.media.AudioAttributes
|
||||||
import android.media.Ringtone
|
|
||||||
import android.media.RingtoneManager
|
import android.media.RingtoneManager
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Handler
|
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.os.Looper
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import com.mob.utsmyanmar.MainActivity
|
import com.mob.utsmyanmar.MainActivity
|
||||||
import com.mob.utsmyanmar.R
|
import com.mob.utsmyanmar.R
|
||||||
@ -24,24 +21,8 @@ import sunmi.sunmiui.utils.LogUtil
|
|||||||
class AutoSettleService : Service() {
|
class AutoSettleService : Service() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val FOREGROUND_CHANNEL_ID = "auto_settlement_foreground_channel"
|
const val CHANNEL_ID = "auto_settlement_channel"
|
||||||
private const val ALERT_CHANNEL_ID = "auto_settlement_alert_channel"
|
const val NOTIFICATION_ID = 1001
|
||||||
private const val NOTIFICATION_ID = 1001
|
|
||||||
private const val ALERT_NOTIFICATION_ID = 1002
|
|
||||||
private const val ALERT_SOUND_DURATION_MS = 3_000L
|
|
||||||
}
|
|
||||||
|
|
||||||
private val mainHandler = Handler(Looper.getMainLooper())
|
|
||||||
private var alertRingtone: Ringtone? = null
|
|
||||||
private val stopServiceRunnable = Runnable {
|
|
||||||
alertRingtone?.stop()
|
|
||||||
alertRingtone = null
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
||||||
stopForeground(STOP_FOREGROUND_REMOVE)
|
|
||||||
} else {
|
|
||||||
stopForeground(true)
|
|
||||||
}
|
|
||||||
stopSelf()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreate() {
|
override fun onCreate() {
|
||||||
@ -50,129 +31,59 @@ class AutoSettleService : Service() {
|
|||||||
startForegroundNotification()
|
startForegroundNotification()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.N)
|
||||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||||
val systemParams = SystemParamsOperation.getInstance()
|
if (!SystemParamsOperation.getInstance().settlementStatus) {
|
||||||
if (!systemParams.isAutoSettlement() || !systemParams.settlementStatus) {
|
|
||||||
stopSelf()
|
stopSelf()
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
showSettlementAlert()
|
|
||||||
playAlertSound()
|
|
||||||
launchSettlement()
|
launchSettlement()
|
||||||
mainHandler.removeCallbacks(stopServiceRunnable)
|
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||||
mainHandler.postDelayed(stopServiceRunnable, ALERT_SOUND_DURATION_MS)
|
stopSelf()
|
||||||
|
|
||||||
return START_NOT_STICKY
|
return START_NOT_STICKY
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBind(intent: Intent?): IBinder? = null
|
override fun onBind(intent: Intent?): IBinder? = null
|
||||||
|
|
||||||
override fun onDestroy() {
|
|
||||||
mainHandler.removeCallbacks(stopServiceRunnable)
|
|
||||||
alertRingtone?.stop()
|
|
||||||
alertRingtone = null
|
|
||||||
super.onDestroy()
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ForegroundServiceType")
|
@SuppressLint("ForegroundServiceType")
|
||||||
private fun startForegroundNotification() {
|
private fun startForegroundNotification() {
|
||||||
LogUtil.d(AutoSettleService::class.java.simpleName, "foreground noti called")
|
LogUtil.d(AutoSettleService::class.java.simpleName, "foreground noti called")
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val channel = NotificationChannel(
|
val channel = NotificationChannel(
|
||||||
FOREGROUND_CHANNEL_ID,
|
CHANNEL_ID,
|
||||||
"AUTO SETTLEMENT",
|
"AUTO SETTLEMENT",
|
||||||
NotificationManager.IMPORTANCE_LOW
|
NotificationManager.IMPORTANCE_HIGH
|
||||||
|
)
|
||||||
|
channel.description = "Auto Settlement notification"
|
||||||
|
channel.enableVibration(true)
|
||||||
|
channel.setSound(
|
||||||
|
RingtoneManager.getDefaultUri(
|
||||||
|
RingtoneManager.TYPE_NOTIFICATION
|
||||||
|
), AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION).build()
|
||||||
)
|
)
|
||||||
channel.description = "Auto Settlement service status"
|
|
||||||
val manager = getSystemService(NotificationManager::class.java)
|
val manager = getSystemService(NotificationManager::class.java)
|
||||||
manager?.createNotificationChannel(channel)
|
manager?.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
val notification = NotificationCompat.Builder(this, FOREGROUND_CHANNEL_ID)
|
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
|
||||||
.setSmallIcon(R.drawable.logo_mob)
|
.setSmallIcon(R.drawable.logo_mob)
|
||||||
.setContentTitle("Auto Settlement")
|
.setContentTitle("Auto Settlement")
|
||||||
.setContentText("Preparing settlement reminder...")
|
.setContentText("Processing...")
|
||||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
||||||
.setOngoing(true)
|
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
startForeground(NOTIFICATION_ID, notification)
|
startForeground(NOTIFICATION_ID, notification)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSettlementAlert() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
||||||
val channel = NotificationChannel(
|
|
||||||
ALERT_CHANNEL_ID,
|
|
||||||
"AUTO SETTLEMENT ALERT",
|
|
||||||
NotificationManager.IMPORTANCE_HIGH
|
|
||||||
).apply {
|
|
||||||
description = "Daily settlement reminder"
|
|
||||||
enableVibration(true)
|
|
||||||
setSound(
|
|
||||||
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
|
|
||||||
AudioAttributes.Builder()
|
|
||||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
getSystemService(NotificationManager::class.java)?.createNotificationChannel(channel)
|
|
||||||
}
|
|
||||||
|
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
|
||||||
this,
|
|
||||||
ALERT_NOTIFICATION_ID,
|
|
||||||
settlementIntent(),
|
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
|
||||||
)
|
|
||||||
|
|
||||||
val notification = NotificationCompat.Builder(this, ALERT_CHANNEL_ID)
|
|
||||||
.setSmallIcon(R.drawable.logo_mob)
|
|
||||||
.setContentTitle("Settlement Reminder")
|
|
||||||
.setContentText("Daily settlement is due. Tap to open settlement.")
|
|
||||||
.setPriority(NotificationCompat.PRIORITY_HIGH)
|
|
||||||
.setCategory(NotificationCompat.CATEGORY_REMINDER)
|
|
||||||
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
|
|
||||||
.setVibrate(longArrayOf(0, 250, 150, 250))
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
getSystemService(NotificationManager::class.java)
|
|
||||||
?.notify(ALERT_NOTIFICATION_ID, notification)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun playAlertSound() {
|
|
||||||
alertRingtone?.stop()
|
|
||||||
alertRingtone = RingtoneManager.getRingtone(
|
|
||||||
this,
|
|
||||||
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
|
|
||||||
)?.apply {
|
|
||||||
audioAttributes = AudioAttributes.Builder()
|
|
||||||
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
|
||||||
.build()
|
|
||||||
play()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun launchSettlement() {
|
private fun launchSettlement() {
|
||||||
runCatching {
|
val intent = Intent(this, MainActivity::class.java).apply {
|
||||||
startActivity(settlementIntent())
|
addFlags(
|
||||||
}.onFailure {
|
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
LogUtil.e(
|
|
||||||
AutoSettleService::class.java.simpleName,
|
|
||||||
"Unable to open settlement screen: ${it.message}"
|
|
||||||
)
|
)
|
||||||
|
putExtra("AUTO_SETTLEMENT", true)
|
||||||
}
|
}
|
||||||
}
|
startActivity(intent)
|
||||||
|
|
||||||
private fun settlementIntent(): Intent = Intent(this, MainActivity::class.java).apply {
|
|
||||||
addFlags(
|
|
||||||
Intent.FLAG_ACTIVITY_NEW_TASK or
|
|
||||||
Intent.FLAG_ACTIVITY_SINGLE_TOP or
|
|
||||||
Intent.FLAG_ACTIVITY_CLEAR_TOP
|
|
||||||
)
|
|
||||||
putExtra("AUTO_SETTLEMENT", true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,42 +1,26 @@
|
|||||||
package com.mob.utsmyanmar.auto_settlement
|
package com.mob.utsmyanmar.auto_settlement
|
||||||
|
|
||||||
|
import android.Manifest
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.AlarmManager
|
import android.app.AlarmManager
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Build
|
import androidx.annotation.RequiresPermission
|
||||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
||||||
object SettlementScheduler {
|
object SettlementScheduler {
|
||||||
private const val FALLBACK_ALERT_TIME = "01:10:00"
|
|
||||||
|
|
||||||
fun schedule(context: Context): Boolean {
|
@RequiresPermission(Manifest.permission.SCHEDULE_EXACT_ALARM)
|
||||||
if (!SystemParamsOperation.getInstance().isAutoSettlement()) {
|
fun schedule(context: Context) {
|
||||||
cancel(context)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val alarmManager =
|
|
||||||
context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
|
|
||||||
!alarmManager.canScheduleExactAlarms()
|
|
||||||
) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
val configuredTime = parseTime(
|
|
||||||
// SystemParamsOperation.getInstance().clearBatchTime
|
|
||||||
"23:05:00"
|
|
||||||
) ?: parseTime(FALLBACK_ALERT_TIME)!!
|
|
||||||
|
|
||||||
val calendar = Calendar.getInstance().apply {
|
val calendar = Calendar.getInstance().apply {
|
||||||
set(Calendar.HOUR_OF_DAY, configuredTime.first)
|
|
||||||
set(Calendar.MINUTE, configuredTime.second)
|
// Auto settlement time
|
||||||
set(Calendar.SECOND, configuredTime.third)
|
set(Calendar.HOUR_OF_DAY, 1)
|
||||||
set(Calendar.MILLISECOND, 0)
|
set(Calendar.MINUTE, 10)
|
||||||
|
set(Calendar.SECOND, 0)
|
||||||
|
|
||||||
|
|
||||||
if (before(Calendar.getInstance())) {
|
if (before(Calendar.getInstance())) {
|
||||||
add(Calendar.DAY_OF_MONTH, 1)
|
add(Calendar.DAY_OF_MONTH, 1)
|
||||||
@ -44,6 +28,11 @@ object SettlementScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
val alarmManager =
|
||||||
|
context.getSystemService(Context.ALARM_SERVICE)
|
||||||
|
as AlarmManager
|
||||||
|
|
||||||
|
|
||||||
val intent = Intent(
|
val intent = Intent(
|
||||||
context,
|
context,
|
||||||
AlarmReceiver::class.java
|
AlarmReceiver::class.java
|
||||||
@ -64,20 +53,6 @@ object SettlementScheduler {
|
|||||||
calendar.timeInMillis,
|
calendar.timeInMillis,
|
||||||
pendingIntent
|
pendingIntent
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseTime(value: String): Triple<Int, Int, Int>? {
|
|
||||||
val parts = value.trim().split(":")
|
|
||||||
if (parts.size !in 2..3) return null
|
|
||||||
|
|
||||||
val hour = parts[0].toIntOrNull() ?: return null
|
|
||||||
val minute = parts[1].toIntOrNull() ?: return null
|
|
||||||
val second = if (parts.size == 3) parts[2].toIntOrNull() ?: return null else 0
|
|
||||||
|
|
||||||
if (hour !in 0..23 || minute !in 0..59 || second !in 0..59) return null
|
|
||||||
return Triple(hour, minute, second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,6 @@ import androidx.navigation.NavHostController
|
|||||||
import androidx.navigation.NavType
|
import androidx.navigation.NavType
|
||||||
import androidx.navigation.compose.NavHost
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.navigation.compose.composable
|
import androidx.navigation.compose.composable
|
||||||
import androidx.navigation.compose.currentBackStackEntryAsState
|
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen
|
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen
|
||||||
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel
|
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel
|
||||||
@ -66,31 +65,9 @@ import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
|||||||
@SuppressLint("ContextCastToActivity")
|
@SuppressLint("ContextCastToActivity")
|
||||||
@Composable
|
@Composable
|
||||||
fun AppNavGraph(
|
fun AppNavGraph(
|
||||||
navController: NavHostController,
|
navController: NavHostController
|
||||||
autoSettlementRequested: Boolean = false,
|
|
||||||
onAutoSettlementHandled: () -> Unit = {}
|
|
||||||
) {
|
) {
|
||||||
val activity = LocalContext.current as ComponentActivity
|
val activity = LocalContext.current as ComponentActivity
|
||||||
val currentBackStackEntry by navController.currentBackStackEntryAsState()
|
|
||||||
val currentRoute = currentBackStackEntry?.destination?.route
|
|
||||||
|
|
||||||
LaunchedEffect(autoSettlementRequested, currentRoute) {
|
|
||||||
if (!autoSettlementRequested ||
|
|
||||||
currentRoute == null ||
|
|
||||||
currentRoute == Routes.TmsSetup.route
|
|
||||||
) return@LaunchedEffect
|
|
||||||
if (currentRoute == Routes.Settlement.route) {
|
|
||||||
return@LaunchedEffect
|
|
||||||
}
|
|
||||||
if (currentRoute == Routes.Password.route) {
|
|
||||||
onAutoSettlementHandled()
|
|
||||||
return@LaunchedEffect
|
|
||||||
}
|
|
||||||
|
|
||||||
navController.navigate(Routes.Settlement.route) {
|
|
||||||
launchSingleTop = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NavHost(
|
NavHost(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
@ -101,9 +78,7 @@ fun AppNavGraph(
|
|||||||
TmsSetupRoute(
|
TmsSetupRoute(
|
||||||
viewModel = tmsSetupViewModel,
|
viewModel = tmsSetupViewModel,
|
||||||
onNavigateDashboard = {
|
onNavigateDashboard = {
|
||||||
navController.navigate(
|
navController.navigate(Routes.Dashboard.route) {
|
||||||
if (autoSettlementRequested) Routes.Settlement.route else Routes.Dashboard.route
|
|
||||||
) {
|
|
||||||
popUpTo(Routes.TmsSetup.route) {
|
popUpTo(Routes.TmsSetup.route) {
|
||||||
inclusive = true
|
inclusive = true
|
||||||
}
|
}
|
||||||
@ -437,7 +412,6 @@ fun AppNavGraph(
|
|||||||
sharedViewModel = sharedViewModel,
|
sharedViewModel = sharedViewModel,
|
||||||
settlementViewMode = settlementViewMode,
|
settlementViewMode = settlementViewMode,
|
||||||
onBack = { navController.popBackStack(Routes.Dashboard.route,false) },
|
onBack = { navController.popBackStack(Routes.Dashboard.route,false) },
|
||||||
autoStartSettlement = autoSettlementRequested,
|
|
||||||
onStartSettlement = {
|
onStartSettlement = {
|
||||||
sharedViewModel.transactionsType.value = TransactionsType.SETTLEMENT
|
sharedViewModel.transactionsType.value = TransactionsType.SETTLEMENT
|
||||||
navController.navigate(Routes.Processing.route) {
|
navController.navigate(Routes.Processing.route) {
|
||||||
@ -446,9 +420,6 @@ fun AppNavGraph(
|
|||||||
}
|
}
|
||||||
launchSingleTop = true
|
launchSingleTop = true
|
||||||
}
|
}
|
||||||
if (autoSettlementRequested) {
|
|
||||||
onAutoSettlementHandled()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -746,15 +717,10 @@ fun AppNavGraph(
|
|||||||
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
|
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
|
||||||
val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity)
|
val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity)
|
||||||
val settlementViewModel: SettlementViewModel = hiltViewModel(activity)
|
val settlementViewModel: SettlementViewModel = hiltViewModel(activity)
|
||||||
val tmsSetupViewModel: TmsSetupViewModel = hiltViewModel(activity)
|
|
||||||
val dashboardViewModel: DashboardViewModel = hiltViewModel(activity)
|
|
||||||
ProcessingRoute(
|
ProcessingRoute(
|
||||||
sharedViewModel = sharedViewModel,
|
sharedViewModel = sharedViewModel,
|
||||||
transProcessViewModel = transProcessViewModel,
|
transProcessViewModel = transProcessViewModel,
|
||||||
settlementViewModel = settlementViewModel,
|
settlementViewModel = settlementViewModel,
|
||||||
onTransactionFinished = {
|
|
||||||
tmsSetupViewModel.downloadConfigs(dashboardViewModel::refreshLastSyncTime)
|
|
||||||
},
|
|
||||||
onNavigateTransactionResult = {
|
onNavigateTransactionResult = {
|
||||||
navController.navigate(Routes.TransactionResult.route) {
|
navController.navigate(Routes.TransactionResult.route) {
|
||||||
popUpTo(Routes.Processing.route) {
|
popUpTo(Routes.Processing.route) {
|
||||||
@ -813,10 +779,14 @@ fun AppNavGraph(
|
|||||||
composable(Routes.TransactionResult.route) {
|
composable(Routes.TransactionResult.route) {
|
||||||
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
|
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
|
||||||
val transResultViewModel: TransactionResultViewModel = hiltViewModel(activity)
|
val transResultViewModel: TransactionResultViewModel = hiltViewModel(activity)
|
||||||
|
val tmsSetupViewModel: TmsSetupViewModel = hiltViewModel(activity)
|
||||||
|
val dashboardViewModel: DashboardViewModel = hiltViewModel(activity)
|
||||||
|
|
||||||
TransactionResultRoute(
|
TransactionResultRoute(
|
||||||
viewModel = transResultViewModel,
|
viewModel = transResultViewModel,
|
||||||
sharedViewModel = sharedViewModel,
|
sharedViewModel = sharedViewModel,
|
||||||
|
tmsSetupViewModel = tmsSetupViewModel,
|
||||||
|
dashboardViewModel = dashboardViewModel,
|
||||||
onNavigateMain = {
|
onNavigateMain = {
|
||||||
navController.navigate(Routes.Dashboard.route) {
|
navController.navigate(Routes.Dashboard.route) {
|
||||||
popUpTo(Routes.Dashboard.route) {
|
popUpTo(Routes.Dashboard.route) {
|
||||||
|
|||||||
@ -21,8 +21,7 @@ fun ProcessingRoute(
|
|||||||
settlementViewModel: SettlementViewModel,
|
settlementViewModel: SettlementViewModel,
|
||||||
onNavigateTransactionResult: () -> Unit,
|
onNavigateTransactionResult: () -> Unit,
|
||||||
onNavigateSignature: () -> Unit,
|
onNavigateSignature: () -> Unit,
|
||||||
onNavigateError: (Boolean, String) -> Unit,
|
onNavigateError: (Boolean, String) -> Unit
|
||||||
onTransactionFinished: () -> Unit
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val transStatus by transProcessViewModel.transResultStatus.collectAsStateWithLifecycle()
|
val transStatus by transProcessViewModel.transResultStatus.collectAsStateWithLifecycle()
|
||||||
@ -40,7 +39,6 @@ fun ProcessingRoute(
|
|||||||
when(settlementStatus.status) {
|
when(settlementStatus.status) {
|
||||||
TransactionStatus.ON_ERROR,
|
TransactionStatus.ON_ERROR,
|
||||||
TransactionStatus.ON_SUCCESS -> {
|
TransactionStatus.ON_SUCCESS -> {
|
||||||
onTransactionFinished()
|
|
||||||
sharedViewModel.payDetail.value = settlementViewModel.getPayDetail()
|
sharedViewModel.payDetail.value = settlementViewModel.getPayDetail()
|
||||||
onNavigateTransactionResult()
|
onNavigateTransactionResult()
|
||||||
}
|
}
|
||||||
@ -56,7 +54,6 @@ fun ProcessingRoute(
|
|||||||
LaunchedEffect(transStatus) {
|
LaunchedEffect(transStatus) {
|
||||||
when(transStatus) {
|
when(transStatus) {
|
||||||
TransResultStatus.SUCCESS -> {
|
TransResultStatus.SUCCESS -> {
|
||||||
onTransactionFinished()
|
|
||||||
sharedViewModel.payDetail.value = transProcessViewModel.payDetailResult.value
|
sharedViewModel.payDetail.value = transProcessViewModel.payDetailResult.value
|
||||||
if (requiresSignature(sharedViewModel.transactionsType.value, sharedViewModel.payDetail.value)) {
|
if (requiresSignature(sharedViewModel.transactionsType.value, sharedViewModel.payDetail.value)) {
|
||||||
onNavigateSignature()
|
onNavigateSignature()
|
||||||
@ -66,22 +63,18 @@ fun ProcessingRoute(
|
|||||||
}
|
}
|
||||||
|
|
||||||
TransResultStatus.FAIL -> {
|
TransResultStatus.FAIL -> {
|
||||||
onTransactionFinished()
|
|
||||||
sharedViewModel.payDetail.value = transProcessViewModel.payDetailResult.value
|
sharedViewModel.payDetail.value = transProcessViewModel.payDetailResult.value
|
||||||
onNavigateTransactionResult()
|
onNavigateTransactionResult()
|
||||||
}
|
}
|
||||||
TransResultStatus.REVERSAL_SUCCESS -> {
|
TransResultStatus.REVERSAL_SUCCESS -> {
|
||||||
onTransactionFinished()
|
|
||||||
onNavigateError(true,"Reversal success")
|
onNavigateError(true,"Reversal success")
|
||||||
}
|
}
|
||||||
|
|
||||||
TransResultStatus.REVERSAL_FAIL -> {
|
TransResultStatus.REVERSAL_FAIL -> {
|
||||||
onTransactionFinished()
|
|
||||||
onNavigateError(false,"Reversal failed")
|
onNavigateError(false,"Reversal failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
TransResultStatus.ERROR -> {
|
TransResultStatus.ERROR -> {
|
||||||
onTransactionFinished()
|
|
||||||
onNavigateError(false,
|
onNavigateError(false,
|
||||||
transProcessViewModel.errorMessage.value?.takeIf { it.isNotBlank() }
|
transProcessViewModel.errorMessage.value?.takeIf { it.isNotBlank() }
|
||||||
?: "Something went wrong. Please try again."
|
?: "Something went wrong. Please try again."
|
||||||
|
|||||||
@ -38,17 +38,11 @@ fun SettlementScreen(
|
|||||||
sharedViewModel: SharedViewModel,
|
sharedViewModel: SharedViewModel,
|
||||||
settlementViewMode: SettlementViewModel,
|
settlementViewMode: SettlementViewModel,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onStartSettlement: () -> Unit,
|
onStartSettlement: () -> Unit
|
||||||
autoStartSettlement: Boolean = false
|
|
||||||
) {
|
) {
|
||||||
val records by settlementViewMode.getSettlementPOS().observeAsState(emptyList())
|
val records by settlementViewMode.getSettlementPOS().observeAsState(emptyList())
|
||||||
val totalAmount = records.sumOf { it.amount }
|
val totalAmount = records.sumOf { it.amount }
|
||||||
|
|
||||||
LaunchedEffect(autoStartSettlement, records) {
|
|
||||||
if (autoStartSettlement && records.isNotEmpty()) {
|
|
||||||
onStartSettlement()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Scaffold(
|
Scaffold(
|
||||||
containerColor = Color.IvoryBeige,
|
containerColor = Color.IvoryBeige,
|
||||||
|
|||||||
@ -74,7 +74,7 @@ class TmsSetupViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun downloadConfigs(onSuccess: () -> Unit = {}) {
|
fun downloadConfigs() {
|
||||||
_uiState.update {
|
_uiState.update {
|
||||||
it.copy(isLoading = true, isError = false, statusText = "Connecting to TMS server...")
|
it.copy(isLoading = true, isError = false, statusText = "Connecting to TMS server...")
|
||||||
}
|
}
|
||||||
@ -99,7 +99,7 @@ class TmsSetupViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
|
|
||||||
tmsSetups.initParams(appResponse, TMSUpdate.UPDATE, emvParamOperation)
|
tmsSetups.initParams(appResponse, TMSUpdate.UPDATE, emvParamOperation)
|
||||||
onConfigApplied(onSuccess)
|
onConfigApplied()
|
||||||
},
|
},
|
||||||
{ error ->
|
{ error ->
|
||||||
val errorMessage = if (error is retrofit2.HttpException) {
|
val errorMessage = if (error is retrofit2.HttpException) {
|
||||||
@ -141,7 +141,7 @@ class TmsSetupViewModel @Inject constructor(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onConfigApplied(onSuccess: () -> Unit) {
|
private fun onConfigApplied() {
|
||||||
val ops = SystemParamsOperation.getInstance()
|
val ops = SystemParamsOperation.getInstance()
|
||||||
|
|
||||||
if (!ops.isActive) {
|
if (!ops.isActive) {
|
||||||
@ -166,7 +166,6 @@ class TmsSetupViewModel @Inject constructor(
|
|||||||
.edit {
|
.edit {
|
||||||
putLong("last_sync_time", System.currentTimeMillis())
|
putLong("last_sync_time", System.currentTimeMillis())
|
||||||
}
|
}
|
||||||
onSuccess()
|
|
||||||
_uiState.update { it.copy(isLoading = false, statusText = "Ready.") }
|
_uiState.update { it.copy(isLoading = false, statusText = "Ready.") }
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_onSyncCompleted.emit(Unit)
|
_onSyncCompleted.emit(Unit)
|
||||||
|
|||||||
@ -5,5 +5,4 @@ sealed interface TransactionResultEvent {
|
|||||||
data object BackClick: TransactionResultEvent
|
data object BackClick: TransactionResultEvent
|
||||||
data object RetryPrint: TransactionResultEvent
|
data object RetryPrint: TransactionResultEvent
|
||||||
data object PrintLater: TransactionResultEvent
|
data object PrintLater: TransactionResultEvent
|
||||||
data object Continue: TransactionResultEvent
|
|
||||||
}
|
}
|
||||||
@ -5,6 +5,8 @@ import androidx.compose.runtime.Composable
|
|||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||||
|
import com.mob.utsmyanmar.ui.dashboard.DashboardViewModel
|
||||||
|
import com.mob.utsmyanmar.ui.tms_setup.TmsSetupViewModel
|
||||||
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||||
|
|
||||||
@ -16,7 +18,9 @@ fun TransactionResultRoute(
|
|||||||
onNavigatePrintReceipt: () -> Unit,
|
onNavigatePrintReceipt: () -> Unit,
|
||||||
onShowError: (String) -> Unit,
|
onShowError: (String) -> Unit,
|
||||||
onShowSuccess: (String) -> Unit,
|
onShowSuccess: (String) -> Unit,
|
||||||
onShowPrinterDialog: (String) -> Unit
|
onShowPrinterDialog: (String) -> Unit,
|
||||||
|
tmsSetupViewModel: TmsSetupViewModel,
|
||||||
|
dashboardViewModel: DashboardViewModel,
|
||||||
) {
|
) {
|
||||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||||
val canGoBack = sharedViewModel.transactionsType.value != TransactionsType.SALE
|
val canGoBack = sharedViewModel.transactionsType.value != TransactionsType.SALE
|
||||||
@ -26,6 +30,8 @@ fun TransactionResultRoute(
|
|||||||
TransactionResultEvent.Start,
|
TransactionResultEvent.Start,
|
||||||
sharedViewModel
|
sharedViewModel
|
||||||
)
|
)
|
||||||
|
dashboardViewModel.refreshLastSyncTime()
|
||||||
|
tmsSetupViewModel.downloadConfigs()
|
||||||
}
|
}
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@ -45,9 +51,6 @@ fun TransactionResultRoute(
|
|||||||
canGoBack = canGoBack,
|
canGoBack = canGoBack,
|
||||||
onEvent = {
|
onEvent = {
|
||||||
viewModel.onEvent(it, sharedViewModel)
|
viewModel.onEvent(it, sharedViewModel)
|
||||||
},
|
|
||||||
onContinue = {
|
|
||||||
viewModel.onEvent(TransactionResultEvent.Continue, sharedViewModel)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,7 +36,6 @@ fun TransactionResultScreen(
|
|||||||
state: TransactionResultState,
|
state: TransactionResultState,
|
||||||
canGoBack: Boolean,
|
canGoBack: Boolean,
|
||||||
onEvent: (TransactionResultEvent) -> Unit,
|
onEvent: (TransactionResultEvent) -> Unit,
|
||||||
onContinue: () -> Unit,
|
|
||||||
) {
|
) {
|
||||||
BackHandler(enabled = canGoBack) {
|
BackHandler(enabled = canGoBack) {
|
||||||
onEvent(TransactionResultEvent.BackClick)
|
onEvent(TransactionResultEvent.BackClick)
|
||||||
@ -71,8 +70,11 @@ fun TransactionResultScreen(
|
|||||||
|
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
Spacer(modifier = Modifier.height(6.dp))
|
||||||
|
|
||||||
ReasonCard(
|
Text(
|
||||||
reason = state.message.ifBlank { "Your payment has been processed successfully." }
|
text = state.message.ifBlank { "Your payment has been processed successfully." },
|
||||||
|
color = Color.Gray,
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(28.dp))
|
Spacer(modifier = Modifier.height(28.dp))
|
||||||
@ -87,50 +89,6 @@ fun TransactionResultScreen(
|
|||||||
transactionId = state.payDetail?.referNo.toString()
|
transactionId = state.payDetail?.referNo.toString()
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(24.dp))
|
|
||||||
|
|
||||||
Button(
|
|
||||||
onClick = onContinue,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.height(56.dp),
|
|
||||||
colors = ButtonDefaults.buttonColors(
|
|
||||||
containerColor = Color.LegacyRed,
|
|
||||||
contentColor = Color.White
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
Text("Continue")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun ReasonCard(reason: String) {
|
|
||||||
Card(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
shape = RoundedCornerShape(16.dp),
|
|
||||||
colors = CardDefaults.cardColors(containerColor = Color.White)
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 18.dp, vertical = 14.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "Reason",
|
|
||||||
color = Color.Gray,
|
|
||||||
style = MaterialTheme.typography.labelLarge
|
|
||||||
)
|
|
||||||
Spacer(modifier = Modifier.height(6.dp))
|
|
||||||
Text(
|
|
||||||
text = reason,
|
|
||||||
color = Color.Black,
|
|
||||||
style = MaterialTheme.typography.titleMedium,
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,6 +323,5 @@ fun PreviewTransactionResultScreen() {
|
|||||||
),
|
),
|
||||||
canGoBack = true,
|
canGoBack = true,
|
||||||
onEvent = {},
|
onEvent = {},
|
||||||
onContinue = {},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,6 @@ import com.utsmyanmar.paylibs.model.PayDetail
|
|||||||
import com.utsmyanmar.paylibs.print.PaperRollStatusCallback
|
import com.utsmyanmar.paylibs.print.PaperRollStatusCallback
|
||||||
import com.utsmyanmar.paylibs.print.PrintHelper
|
import com.utsmyanmar.paylibs.print.PrintHelper
|
||||||
import com.utsmyanmar.paylibs.utils.PrintStatus
|
import com.utsmyanmar.paylibs.utils.PrintStatus
|
||||||
import com.utsmyanmar.paylibs.utils.POSUtil
|
|
||||||
import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil
|
import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil
|
||||||
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
|
||||||
@ -25,7 +24,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
import kotlinx.coroutines.flow.receiveAsFlow
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.Job
|
|
||||||
import sunmi.sunmiui.utils.LogUtil
|
import sunmi.sunmiui.utils.LogUtil
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -46,7 +44,6 @@ class TransactionResultViewModel @Inject constructor(
|
|||||||
val uiEvent = _uiEvent.receiveAsFlow()
|
val uiEvent = _uiEvent.receiveAsFlow()
|
||||||
|
|
||||||
private var started = false
|
private var started = false
|
||||||
private var resultTimeoutJob: Job? = null
|
|
||||||
|
|
||||||
fun onEvent(
|
fun onEvent(
|
||||||
event: TransactionResultEvent,
|
event: TransactionResultEvent,
|
||||||
@ -55,16 +52,11 @@ class TransactionResultViewModel @Inject constructor(
|
|||||||
when (event) {
|
when (event) {
|
||||||
TransactionResultEvent.Start -> {
|
TransactionResultEvent.Start -> {
|
||||||
started = false
|
started = false
|
||||||
resultTimeoutJob?.cancel()
|
|
||||||
start(sharedViewModel)
|
start(sharedViewModel)
|
||||||
}
|
}
|
||||||
TransactionResultEvent.BackClick -> isCardInside()
|
TransactionResultEvent.BackClick -> isCardInside()
|
||||||
TransactionResultEvent.RetryPrint -> startPrintProcess(sharedViewModel, false)
|
TransactionResultEvent.RetryPrint -> startPrintProcess(sharedViewModel, false)
|
||||||
TransactionResultEvent.PrintLater -> isCardInside()
|
TransactionResultEvent.PrintLater -> isCardInside()
|
||||||
TransactionResultEvent.Continue -> {
|
|
||||||
resultTimeoutJob?.cancel()
|
|
||||||
navigateMain()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,7 +99,7 @@ class TransactionResultViewModel @Inject constructor(
|
|||||||
|
|
||||||
val message = when {
|
val message = when {
|
||||||
isSuccess -> "Transaction approved"
|
isSuccess -> "Transaction approved"
|
||||||
payDetail != null -> failureReason(payDetail)
|
payDetail?.tradeAnswerCode?.isNotBlank() == true -> payDetail.tradeAnswerCode
|
||||||
else -> "Transaction failed"
|
else -> "Transaction failed"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,20 +109,8 @@ class TransactionResultViewModel @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun failureReason(payDetail: PayDetail): String {
|
|
||||||
val responseCode = payDetail.tradeAnswerCode.orEmpty().trim()
|
|
||||||
val resultDescription = payDetail.tradeResultDes.orEmpty().trim()
|
|
||||||
|
|
||||||
if (resultDescription.isNotBlank() && !resultDescription.equals(responseCode, ignoreCase = true)) {
|
|
||||||
return resultDescription
|
|
||||||
}
|
|
||||||
if (responseCode.isBlank()) return "Transaction failed"
|
|
||||||
|
|
||||||
return POSUtil.getInstance().getResponse(responseCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startResultTimeout(sharedViewModel: SharedViewModel) {
|
private fun startResultTimeout(sharedViewModel: SharedViewModel) {
|
||||||
resultTimeoutJob = viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
delay(RESULT_TIMEOUT)
|
delay(RESULT_TIMEOUT)
|
||||||
|
|
||||||
val payDetail = sharedViewModel.payDetail.value
|
val payDetail = sharedViewModel.payDetail.value
|
||||||
@ -148,6 +128,7 @@ class TransactionResultViewModel @Inject constructor(
|
|||||||
if (SystemParamsOperation.getInstance().isPrintErrorSlip) {
|
if (SystemParamsOperation.getInstance().isPrintErrorSlip) {
|
||||||
startPrintProcess(sharedViewModel, false)
|
startPrintProcess(sharedViewModel, false)
|
||||||
}
|
}
|
||||||
|
isCardInside()
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionType == TransactionsType.SETTLEMENT -> {
|
transactionType == TransactionsType.SETTLEMENT -> {
|
||||||
@ -157,10 +138,12 @@ class TransactionResultViewModel @Inject constructor(
|
|||||||
"Configs are updated"
|
"Configs are updated"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
navigateMain()
|
||||||
}
|
}
|
||||||
|
|
||||||
isWavePayNonSuccessTransaction(transactionType, payDetail) -> {
|
isWavePayNonSuccessTransaction(transactionType, payDetail) -> {
|
||||||
startPrintProcess(sharedViewModel, false)
|
startPrintProcess(sharedViewModel, false)
|
||||||
|
navigateMain()
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package com.mob.utsmyanmar.utils.tms
|
|||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
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.auto_settlement.SettlementScheduler
|
|
||||||
import com.utsmyanmar.baselib.BaseApplication
|
import com.utsmyanmar.baselib.BaseApplication
|
||||||
import com.utsmyanmar.baselib.emv.EmvParamOperation
|
import com.utsmyanmar.baselib.emv.EmvParamOperation
|
||||||
import com.utsmyanmar.baselib.network.model.sirius.SiriusHost
|
import com.utsmyanmar.baselib.network.model.sirius.SiriusHost
|
||||||
@ -158,10 +157,9 @@ class TMSSetupsImpl : TMSSetups {
|
|||||||
"pre_auth_enable" -> ops.preAuthStatus = parseBoolean(data)
|
"pre_auth_enable" -> ops.preAuthStatus = parseBoolean(data)
|
||||||
"void_enable" -> ops.voidStatus = parseBoolean(data)
|
"void_enable" -> ops.voidStatus = parseBoolean(data)
|
||||||
"cash_advance_enable" -> ops.cashAdvanceStatus = parseBoolean(data)
|
"cash_advance_enable" -> ops.cashAdvanceStatus = parseBoolean(data)
|
||||||
"refund_enable" -> ops.refundStatus = parseBoolean(data)
|
"refund_enable" -> ops.refundStatus = parseBoolean(data)
|
||||||
"settlement_enable" -> ops.settlementStatus = parseBoolean(data)
|
"settlement_enable" -> ops.settlementStatus = parseBoolean(data)
|
||||||
"auto_settlement" -> ops.setAutoSettlement(parseBoolean(data))
|
"system_password" -> ops.systemPassword = data.take(6).ifEmpty { data }
|
||||||
"system_password" -> ops.systemPassword = data.take(6).ifEmpty { data }
|
|
||||||
"settlement_password" -> ops.settlementPassword = data.take(6).ifEmpty { data }
|
"settlement_password" -> ops.settlementPassword = data.take(6).ifEmpty { data }
|
||||||
"setting_password" -> ops.settingPassword = data.take(6).ifEmpty { data }
|
"setting_password" -> ops.settingPassword = data.take(6).ifEmpty { data }
|
||||||
"terminal_enable" -> ops.isActive = parseBoolean(data)
|
"terminal_enable" -> ops.isActive = parseBoolean(data)
|
||||||
@ -228,7 +226,6 @@ class TMSSetupsImpl : TMSSetups {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ops.carouselUrls = imgUrls.joinToString(",")
|
ops.carouselUrls = imgUrls.joinToString(",")
|
||||||
SettlementScheduler.schedule(BaseApplication.getInstance().applicationContext)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun initParams(json: String) {
|
override fun initParams(json: String) {
|
||||||
|
|||||||
@ -409,17 +409,6 @@ public class SystemParamsOperation {
|
|||||||
return params.getSettlementStatus();
|
return params.getSettlementStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAutoSettlement() {
|
|
||||||
SystemParamsSettings params = getSystemParamsSettings();
|
|
||||||
return params.isAutoSettlement();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setAutoSettlement(boolean enabled) {
|
|
||||||
SystemParamsSettings params = getSystemParamsSettings();
|
|
||||||
params.setAutoSettlement(enabled);
|
|
||||||
saveSystemParamsSettings(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCarouselUrls() {
|
public String getCarouselUrls() {
|
||||||
SystemParamsSettings params = getSystemParamsSettings();
|
SystemParamsSettings params = getSystemParamsSettings();
|
||||||
return params.getCarouselUrls();
|
return params.getCarouselUrls();
|
||||||
|
|||||||
@ -220,8 +220,6 @@ public class SystemParamsSettings implements Serializable {
|
|||||||
|
|
||||||
private boolean settlementStatus = true;
|
private boolean settlementStatus = true;
|
||||||
|
|
||||||
private boolean autoSettlement = false;
|
|
||||||
|
|
||||||
private boolean isNeedSettlement = false;
|
private boolean isNeedSettlement = false;
|
||||||
|
|
||||||
private boolean manualEntryStatus = true;
|
private boolean manualEntryStatus = true;
|
||||||
@ -568,8 +566,6 @@ public class SystemParamsSettings implements Serializable {
|
|||||||
protected boolean getSettlementStatus() { return settlementStatus; }
|
protected boolean getSettlementStatus() { return settlementStatus; }
|
||||||
|
|
||||||
protected void setSettlementStatus(boolean status) { this.settlementStatus = status; }
|
protected void setSettlementStatus(boolean status) { this.settlementStatus = status; }
|
||||||
protected boolean isAutoSettlement() { return autoSettlement; }
|
|
||||||
protected void setAutoSettlement(boolean enabled) { this.autoSettlement = enabled; }
|
|
||||||
protected void setUserRole(int role){ this.user_role = role;}
|
protected void setUserRole(int role){ this.user_role = role;}
|
||||||
|
|
||||||
protected int getUserRole(){ return user_role;}
|
protected int getUserRole(){ return user_role;}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user