card reader setup
This commit is contained in:
parent
32c4bf8fb7
commit
d3a6ddbc37
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?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">
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
plugins {
|
plugins {
|
||||||
alias(libs.plugins.android.application)
|
alias(libs.plugins.android.application)
|
||||||
alias(libs.plugins.kotlin.compose)
|
alias(libs.plugins.kotlin.compose)
|
||||||
|
id("com.google.devtools.ksp")
|
||||||
|
id("com.google.dagger.hilt.android")
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -44,10 +46,12 @@ dependencies {
|
|||||||
implementation(libs.androidx.activity.compose)
|
implementation(libs.androidx.activity.compose)
|
||||||
implementation(libs.androidx.compose.foundation)
|
implementation(libs.androidx.compose.foundation)
|
||||||
implementation(libs.androidx.compose.material3)
|
implementation(libs.androidx.compose.material3)
|
||||||
|
implementation(libs.androidx.compose.runtime)
|
||||||
implementation(libs.androidx.compose.ui)
|
implementation(libs.androidx.compose.ui)
|
||||||
implementation(libs.androidx.compose.ui.graphics)
|
implementation(libs.androidx.compose.ui.graphics)
|
||||||
implementation(libs.androidx.compose.ui.tooling.preview)
|
implementation(libs.androidx.compose.ui.tooling.preview)
|
||||||
implementation(libs.androidx.core.ktx)
|
implementation(libs.androidx.core.ktx)
|
||||||
|
implementation(libs.androidx.hilt.navigation.compose)
|
||||||
implementation(libs.androidx.lifecycle.runtime.ktx)
|
implementation(libs.androidx.lifecycle.runtime.ktx)
|
||||||
implementation(libs.androidx.navigation.compose)
|
implementation(libs.androidx.navigation.compose)
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
@ -57,4 +61,18 @@ dependencies {
|
|||||||
androidTestImplementation(libs.androidx.junit)
|
androidTestImplementation(libs.androidx.junit)
|
||||||
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
debugImplementation(libs.androidx.compose.ui.test.manifest)
|
||||||
debugImplementation(libs.androidx.compose.ui.tooling)
|
debugImplementation(libs.androidx.compose.ui.tooling)
|
||||||
}
|
implementation("com.google.dagger:hilt-android:2.59.2")
|
||||||
|
ksp(libs.hilt.android.compiler)
|
||||||
|
implementation(libs.rxjava)
|
||||||
|
implementation(libs.rxandroid)
|
||||||
|
// local libs
|
||||||
|
implementation(project(":baselib"))
|
||||||
|
implementation(project(":mpulib"))
|
||||||
|
implementation(project(":paylibs"))
|
||||||
|
implementation(project(":paysdk-lib"))
|
||||||
|
implementation(project(":qrgen-lib"))
|
||||||
|
implementation(project(":sunmiui-lib"))
|
||||||
|
implementation(project(":ecr"))
|
||||||
|
implementation(project(":xpay"))
|
||||||
|
implementation(project(":cmhl"))
|
||||||
|
}
|
||||||
|
|||||||
@ -2,7 +2,32 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.telephony"
|
||||||
|
android:required="false" />
|
||||||
|
<uses-feature
|
||||||
|
android:name="android.hardware.camera"
|
||||||
|
android:required="false" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
<uses-permission android:name="com.sunmi.perm.LED" />
|
||||||
|
<uses-permission android:name="com.sunmi.perm.MSR" />
|
||||||
|
<uses-permission android:name="com.sunmi.perm.ICC" />
|
||||||
|
<uses-permission android:name="com.sunmi.perm.PINPAD" />
|
||||||
|
<uses-permission android:name="com.sunmi.perm.SECURITY" />
|
||||||
|
<uses-permission android:name="com.sunmi.perm.CONTACTLESS_CARD" />
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"
|
||||||
|
tools:ignore="ProtectedPermissions" />
|
||||||
|
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
android:name="com.mob.utsmyanmar.MyApplication"
|
||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||||
android:fullBackupContent="@xml/backup_rules"
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
@ -12,7 +37,7 @@
|
|||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/Theme.MOBPOS">
|
android:theme="@style/Theme.MOBPOS">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name="com.mob.utsmyanmar.MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/Theme.MOBPOS">
|
android:theme="@style/Theme.MOBPOS">
|
||||||
@ -24,4 +49,4 @@
|
|||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@ -7,7 +7,9 @@ import androidx.activity.enableEdgeToEdge
|
|||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
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 dagger.hilt.android.AndroidEntryPoint
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
|
|||||||
13
app/src/main/java/com/mob/utsmyanmar/MyApplication.kt
Normal file
13
app/src/main/java/com/mob/utsmyanmar/MyApplication.kt
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package com.mob.utsmyanmar
|
||||||
|
|
||||||
|
import com.mob.utsmyanmar.utils.AppContextHolder
|
||||||
|
import com.utsmyanmar.baselib.BaseApplication
|
||||||
|
import dagger.hilt.android.HiltAndroidApp
|
||||||
|
|
||||||
|
@HiltAndroidApp
|
||||||
|
class MyApplication : BaseApplication() {
|
||||||
|
override fun onCreate() {
|
||||||
|
super.onCreate()
|
||||||
|
AppContextHolder.init(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,5 @@
|
|||||||
|
package com.mob.utsmyanmar.model
|
||||||
|
|
||||||
|
enum class CardTransactionType {
|
||||||
|
MPU, EMV, MAG, FALLBACK
|
||||||
|
}
|
||||||
39
app/src/main/java/com/mob/utsmyanmar/model/ProcessCode.kt
Normal file
39
app/src/main/java/com/mob/utsmyanmar/model/ProcessCode.kt
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package com.mob.utsmyanmar.model
|
||||||
|
|
||||||
|
object ProcessCode {
|
||||||
|
const val BALANCE_INQUIRY = "31"
|
||||||
|
|
||||||
|
const val SALE_PURCHASE = "00"
|
||||||
|
|
||||||
|
const val SALE_VOID = "02"
|
||||||
|
|
||||||
|
const val PRE_AUTH_SALE = "30"
|
||||||
|
|
||||||
|
const val PRE_AUTH_VOID = "30"
|
||||||
|
|
||||||
|
const val PRE_AUTH_COMPLETE = "30"
|
||||||
|
|
||||||
|
const val PRE_AUTH_COMPLETE_VOID = "30"
|
||||||
|
|
||||||
|
const val CASH_ADVANCE = "01" // 01-MPU 17-TTIP
|
||||||
|
|
||||||
|
const val FUND_TRANSFER = "61"
|
||||||
|
|
||||||
|
const val PIN_CHANGE = "70"
|
||||||
|
|
||||||
|
const val SETTLEMENT = "92"
|
||||||
|
|
||||||
|
const val SIGN_ON = "95"
|
||||||
|
|
||||||
|
const val CASH_DEPOSIT = "21"
|
||||||
|
|
||||||
|
const val REFUND = "20"
|
||||||
|
|
||||||
|
const val SMART = "00"
|
||||||
|
|
||||||
|
const val SAVING = "10"
|
||||||
|
|
||||||
|
const val CURRENT = "20"
|
||||||
|
|
||||||
|
const val TO_ACCOUNT = "00"
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
package com.mob.utsmyanmar.model
|
||||||
|
|
||||||
|
enum class SettlementType {
|
||||||
|
NORMAL,
|
||||||
|
CUT_OVER
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.mob.utsmyanmar.model
|
||||||
|
|
||||||
|
enum class TransResultStatus {
|
||||||
|
CLICK_CONFIRM,
|
||||||
|
SUCCESS,
|
||||||
|
FAIL,
|
||||||
|
OFFLINE_SUCCESS,
|
||||||
|
OFFLINE_FAILURE,
|
||||||
|
SECONDARY,
|
||||||
|
REVERSAL_PROCESS,
|
||||||
|
REVERSAL_PREPARE,
|
||||||
|
REVERSAL_SECONDARY,
|
||||||
|
REVERSAL_THIRD,
|
||||||
|
REVERSAL_FAIL,
|
||||||
|
REVERSAL_SUCCESS,
|
||||||
|
BEFORE_REVERSAL,
|
||||||
|
PIN_PAD_CANCEL,
|
||||||
|
PIN_PAD_CONFIRM,
|
||||||
|
PIN_PAD_ERROR,
|
||||||
|
PIN_MISMATCH,
|
||||||
|
PIN_MISMATCH_END,
|
||||||
|
REMOVED_CARD,
|
||||||
|
EMV_ERROR,
|
||||||
|
ERROR,
|
||||||
|
RETRY_AGAIN,
|
||||||
|
NEXT_SCREEN,
|
||||||
|
EMPTY_PIN,
|
||||||
|
NETWORK_ERROR
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package com.mob.utsmyanmar.model.ecr
|
||||||
|
|
||||||
|
enum class ECRResultStatus {
|
||||||
|
USER_CANCEL,
|
||||||
|
TIME_OUT,
|
||||||
|
RESPONSE_RECEIVED
|
||||||
|
}
|
||||||
@ -137,7 +137,7 @@ fun AmountScreen(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = "Next",
|
text = "Enter",
|
||||||
fontSize = 20.sp,
|
fontSize = 20.sp,
|
||||||
fontWeight = FontWeight.Bold
|
fontWeight = FontWeight.Bold
|
||||||
)
|
)
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
package com.mob.utsmyanmar.ui.cardwaiting
|
||||||
|
|
||||||
|
sealed interface CardWaitingEvent {
|
||||||
|
data object GoManualEntry : CardWaitingEvent
|
||||||
|
data object GoProcessingCard : CardWaitingEvent
|
||||||
|
data object GoTimeout : CardWaitingEvent
|
||||||
|
data object GoMain : CardWaitingEvent
|
||||||
|
data object GoBack : CardWaitingEvent
|
||||||
|
}
|
||||||
@ -0,0 +1,93 @@
|
|||||||
|
package com.mob.utsmyanmar.ui.cardwaiting
|
||||||
|
|
||||||
|
import androidx.activity.compose.BackHandler
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material3.Button
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.DisposableEffect
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
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.sp
|
||||||
|
import com.mob.utsmyanmar.ui.theme.White
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CardWaitingScreen(
|
||||||
|
viewModel: CardWaitingViewModel,
|
||||||
|
onManualEntry: () -> Unit,
|
||||||
|
onProcessingCard: () -> Unit,
|
||||||
|
onTimeout: () -> Unit,
|
||||||
|
onBack: () -> Unit,
|
||||||
|
onMain: () -> Unit
|
||||||
|
) {
|
||||||
|
val uiState by viewModel.uiState.collectAsState()
|
||||||
|
|
||||||
|
LaunchedEffect(viewModel) {
|
||||||
|
viewModel.events.collect { event ->
|
||||||
|
when (event) {
|
||||||
|
CardWaitingEvent.GoManualEntry -> onManualEntry()
|
||||||
|
CardWaitingEvent.GoProcessingCard -> onProcessingCard()
|
||||||
|
CardWaitingEvent.GoTimeout -> onTimeout()
|
||||||
|
CardWaitingEvent.GoMain -> onMain()
|
||||||
|
CardWaitingEvent.GoBack -> onBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LaunchedEffect(viewModel) {
|
||||||
|
viewModel.onScreenResume()
|
||||||
|
}
|
||||||
|
|
||||||
|
DisposableEffect(viewModel) {
|
||||||
|
onDispose {
|
||||||
|
viewModel.onScreenPause()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BackHandler {
|
||||||
|
viewModel.onBackPressed()
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.background(White)
|
||||||
|
.padding(24.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Card Capture",
|
||||||
|
fontSize = 22.sp,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(40.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = uiState.alertMessage,
|
||||||
|
fontSize = 20.sp,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
|
|
||||||
|
Button(
|
||||||
|
onClick = viewModel::onManualEntryClick,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Text("Manual Entry")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
package com.mob.utsmyanmar.ui.cardwaiting
|
||||||
|
|
||||||
|
data class CardWaitingUiState(
|
||||||
|
val alertMessage: String = "Please insert, tap, or swipe card",
|
||||||
|
val isLoading: Boolean = false,
|
||||||
|
val isFallback: Boolean = false
|
||||||
|
)
|
||||||
@ -0,0 +1,293 @@
|
|||||||
|
package com.mob.utsmyanmar.ui.cardwaiting
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.ViewModelProvider
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.mob.utsmyanmar.model.CardTransactionType
|
||||||
|
import com.mob.utsmyanmar.model.ecr.ECRResultStatus
|
||||||
|
import com.mob.utsmyanmar.utils.CoreUtils
|
||||||
|
import com.mob.utsmyanmar.viewmodel.CardReaderViewModel
|
||||||
|
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||||
|
import com.sunmi.pay.hardware.aidl.AidlConstants
|
||||||
|
import com.utsmyanmar.checkxread.checkcard.CheckCardResultX
|
||||||
|
import com.utsmyanmar.checkxread.util.CardTypeX
|
||||||
|
import com.utsmyanmar.ecr.ECRHelper
|
||||||
|
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
||||||
|
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
|
import kotlinx.coroutines.channels.Channel
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.flow.receiveAsFlow
|
||||||
|
import kotlinx.coroutines.flow.update
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class CardWaitingViewModel(
|
||||||
|
private val cardReadViewModel: CardReaderViewModel,
|
||||||
|
private val sharedViewModel: SharedViewModel
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun provideFactory(
|
||||||
|
cardReadViewModel: CardReaderViewModel,
|
||||||
|
sharedViewModel: SharedViewModel
|
||||||
|
): ViewModelProvider.Factory {
|
||||||
|
return object : ViewModelProvider.Factory {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||||
|
return CardWaitingViewModel(
|
||||||
|
cardReadViewModel = cardReadViewModel,
|
||||||
|
sharedViewModel = sharedViewModel
|
||||||
|
) as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val _uiState = MutableStateFlow(CardWaitingUiState())
|
||||||
|
val uiState = _uiState.asStateFlow()
|
||||||
|
|
||||||
|
private val _events = Channel<CardWaitingEvent>()
|
||||||
|
val events = _events.receiveAsFlow()
|
||||||
|
|
||||||
|
private var retryCounter = 0
|
||||||
|
private var fallbackCounter = 0
|
||||||
|
private var fallbackEnabled = false
|
||||||
|
private var readerInitJob: Job? = null
|
||||||
|
|
||||||
|
fun onScreenResume() {
|
||||||
|
retryCounter = 0
|
||||||
|
fallbackCounter = SystemParamsOperation.getInstance().fallbackCounter
|
||||||
|
fallbackEnabled = SystemParamsOperation.getInstance().fallbackEnabled
|
||||||
|
|
||||||
|
if (sharedViewModel.transactionsType.value == TransactionsType.REFUND) {
|
||||||
|
sharedViewModel.enableCardStatusIcon(false, false, false, false)
|
||||||
|
} else {
|
||||||
|
sharedViewModel.enableCardStatusIcon(true, true, true, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
val isFallback = sharedViewModel.getIsFallback().value == true
|
||||||
|
if (isFallback) {
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(
|
||||||
|
alertMessage = "Fallback!\nPlease stripe!",
|
||||||
|
isFallback = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startCardReadWhenReady(isFallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onScreenPause() {
|
||||||
|
readerInitJob?.cancel()
|
||||||
|
stopCardReading()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onBackPressed() {
|
||||||
|
if (sharedViewModel.isEcr.value == true) {
|
||||||
|
sharedViewModel.isEcr.postValue(false)
|
||||||
|
CoreUtils.getInstance(sharedViewModel).responseRejectMsg("Transaction cancelled")
|
||||||
|
sharedViewModel.isEcrFinished.postValue(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
stopCardReading()
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
_events.send(CardWaitingEvent.GoBack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun onManualEntryClick() {
|
||||||
|
viewModelScope.launch {
|
||||||
|
_events.send(CardWaitingEvent.GoManualEntry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startCardReadWhenReady(isFallback: Boolean) {
|
||||||
|
readerInitJob?.cancel()
|
||||||
|
readerInitJob = viewModelScope.launch {
|
||||||
|
if (cardReadViewModel.isReaderReady()) {
|
||||||
|
setupCardReadProcess(isFallback)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(
|
||||||
|
alertMessage = "Initializing card reader...",
|
||||||
|
isLoading = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
repeat(10) {
|
||||||
|
delay(300)
|
||||||
|
if (cardReadViewModel.isReaderReady()) {
|
||||||
|
_uiState.update { state ->
|
||||||
|
state.copy(
|
||||||
|
alertMessage = if (isFallback) {
|
||||||
|
"Fallback!\nPlease stripe!"
|
||||||
|
} else {
|
||||||
|
"Please insert, tap, or swipe card"
|
||||||
|
},
|
||||||
|
isLoading = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
setupCardReadProcess(isFallback)
|
||||||
|
return@launch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(
|
||||||
|
alertMessage = "Card reader unavailable.\nPlease wait and try again.",
|
||||||
|
isLoading = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setupCardReadProcess(isFallback: Boolean) {
|
||||||
|
initCheckCard(isFallback)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun initCheckCard(isFallback: Boolean) {
|
||||||
|
var allType =
|
||||||
|
AidlConstants.CardType.NFC.value or
|
||||||
|
AidlConstants.CardType.IC.value or
|
||||||
|
AidlConstants.CardType.MAGNETIC.value
|
||||||
|
|
||||||
|
if (isFallback) {
|
||||||
|
allType = AidlConstants.CardType.MAGNETIC.value
|
||||||
|
} else if (
|
||||||
|
SystemParamsOperation.getInstance().isMagStripeEnabled &&
|
||||||
|
!SystemParamsOperation.getInstance().isNfcEnabled
|
||||||
|
) {
|
||||||
|
allType =
|
||||||
|
AidlConstants.CardType.IC.value or
|
||||||
|
AidlConstants.CardType.MAGNETIC.value
|
||||||
|
}
|
||||||
|
|
||||||
|
cardReadViewModel.startCheckXProcess(
|
||||||
|
allType,
|
||||||
|
65,
|
||||||
|
object : CheckCardResultX {
|
||||||
|
override fun onSuccess(cardType: CardTypeX, isMPU: Boolean) {
|
||||||
|
when {
|
||||||
|
!isFallback && cardType == CardTypeX.MAG -> {
|
||||||
|
if (SystemParamsOperation.getInstance().isMagStripeEnabled) {
|
||||||
|
cardReadViewModel.setCardTransactionType(CardTransactionType.MAG)
|
||||||
|
} else {
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(alertMessage = "Mag stripe not allowed")
|
||||||
|
}
|
||||||
|
setupCardReadProcess(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isFallback && cardType == CardTypeX.MAG -> {
|
||||||
|
sharedViewModel.setEmvTrans(false)
|
||||||
|
cardReadViewModel.setCardTransactionType(CardTransactionType.FALLBACK)
|
||||||
|
}
|
||||||
|
|
||||||
|
cardType == CardTypeX.IC || cardType == CardTypeX.NFC -> {
|
||||||
|
if (isMPU) {
|
||||||
|
sharedViewModel.setEmvTrans(false)
|
||||||
|
cardReadViewModel.setCardTransactionType(CardTransactionType.MPU)
|
||||||
|
} else {
|
||||||
|
cardReadViewModel.setCardData(cardType.value)
|
||||||
|
cardReadViewModel.setCardTransactionType(CardTransactionType.EMV)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
_events.send(CardWaitingEvent.GoProcessingCard)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(code: Int, message: String) {
|
||||||
|
ecrActionCancel("Transaction cancelled")
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(
|
||||||
|
alertMessage = message,
|
||||||
|
isLoading = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_events.send(CardWaitingEvent.GoMain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCommError() {
|
||||||
|
if (fallbackEnabled && retryCounter < fallbackCounter) {
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(
|
||||||
|
alertMessage = "Card not detected!\nRemain Attempt - ${fallbackCounter - retryCounter}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
retryCounter++
|
||||||
|
setupCardReadProcess(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retryCounter == fallbackCounter) {
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(alertMessage = "Fallback!\nPlease stripe!")
|
||||||
|
}
|
||||||
|
setupCardReadProcess(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ecrActionCancel("Transaction cancelled")
|
||||||
|
|
||||||
|
viewModelScope.launch {
|
||||||
|
_uiState.update {
|
||||||
|
it.copy(
|
||||||
|
alertMessage = "Chip not detected!",
|
||||||
|
isLoading = false
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_events.send(CardWaitingEvent.GoMain)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ecrActionCancel(msg: String) {
|
||||||
|
if (sharedViewModel.isEcr.value != true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sharedViewModel.isEcr.postValue(false)
|
||||||
|
sharedViewModel.isEcrFinished.postValue(true)
|
||||||
|
|
||||||
|
if (SystemParamsOperation.getInstance().isCMHLEnabled) {
|
||||||
|
ECRHelper.send(
|
||||||
|
CoreUtils.getInstance(sharedViewModel)
|
||||||
|
.generateCMHLResponse(ECRResultStatus.USER_CANCEL)
|
||||||
|
)
|
||||||
|
|
||||||
|
CoreUtils.getInstance(sharedViewModel).responseACKCMHL()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun stopCardReading() {
|
||||||
|
sharedViewModel.setIsFallback(false)
|
||||||
|
cardReadViewModel.cancelCheckCard()
|
||||||
|
cardReadViewModel.resetOneTimeFlag()
|
||||||
|
cardReadViewModel.cancelCheckXProcess()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCleared() {
|
||||||
|
super.onCleared()
|
||||||
|
readerInitJob?.cancel()
|
||||||
|
stopCardReading()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,19 @@
|
|||||||
package com.mob.utsmyanmar.ui.navigation
|
package com.mob.utsmyanmar.ui.navigation
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.navigation.NavHostController
|
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.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.mob.utsmyanmar.ui.amount.AmountScreen
|
import com.mob.utsmyanmar.ui.amount.AmountScreen
|
||||||
|
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingScreen
|
||||||
|
import com.mob.utsmyanmar.ui.cardwaiting.CardWaitingViewModel
|
||||||
import com.mob.utsmyanmar.ui.dashboard.DashboardScreen
|
import com.mob.utsmyanmar.ui.dashboard.DashboardScreen
|
||||||
|
import com.mob.utsmyanmar.viewmodel.CardReaderViewModel
|
||||||
|
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppNavGraph(
|
fun AppNavGraph(
|
||||||
@ -42,7 +48,38 @@ fun AppNavGraph(
|
|||||||
) { backStackEntry ->
|
) { backStackEntry ->
|
||||||
AmountScreen(
|
AmountScreen(
|
||||||
action = backStackEntry.arguments?.getString("action").orEmpty(),
|
action = backStackEntry.arguments?.getString("action").orEmpty(),
|
||||||
onBackClick = { navController.popBackStack() }
|
onBackClick = { navController.popBackStack() },
|
||||||
|
onCancelClick = { navController.popBackStack() },
|
||||||
|
onNextClick = {
|
||||||
|
navController.navigate(Routes.CardWaiting.route)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
composable(Routes.CardWaiting.route) {
|
||||||
|
val sharedViewModel: SharedViewModel = hiltViewModel()
|
||||||
|
val cardReaderViewModel: CardReaderViewModel = hiltViewModel()
|
||||||
|
val cardWaitingViewModel: CardWaitingViewModel = viewModel(
|
||||||
|
factory = CardWaitingViewModel.provideFactory(
|
||||||
|
cardReadViewModel = cardReaderViewModel,
|
||||||
|
sharedViewModel = sharedViewModel
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
CardWaitingScreen(
|
||||||
|
viewModel = cardWaitingViewModel,
|
||||||
|
onManualEntry = {},
|
||||||
|
onProcessingCard = {},
|
||||||
|
onTimeout = { navController.popBackStack() },
|
||||||
|
onBack = { navController.popBackStack() },
|
||||||
|
onMain = {
|
||||||
|
navController.navigate(Routes.Dashboard.route) {
|
||||||
|
popUpTo(Routes.Dashboard.route) {
|
||||||
|
inclusive = false
|
||||||
|
}
|
||||||
|
launchSingleTop = true
|
||||||
|
}
|
||||||
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,4 +5,5 @@ sealed class Routes(val route: String) {
|
|||||||
data object Amount : Routes("amount/{action}") {
|
data object Amount : Routes("amount/{action}") {
|
||||||
fun createRoute(action: String): String = "amount/$action"
|
fun createRoute(action: String): String = "amount/$action"
|
||||||
}
|
}
|
||||||
|
data object CardWaiting : Routes("card_waiting")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,15 @@
|
|||||||
|
package com.mob.utsmyanmar.utils
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
|
||||||
|
object AppContextHolder {
|
||||||
|
private lateinit var appContext: Context
|
||||||
|
|
||||||
|
fun init(context: Context) {
|
||||||
|
appContext = context.applicationContext
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get(): Context {
|
||||||
|
return appContext
|
||||||
|
}
|
||||||
|
}
|
||||||
1037
app/src/main/java/com/mob/utsmyanmar/utils/CoreUtils.kt
Normal file
1037
app/src/main/java/com/mob/utsmyanmar/utils/CoreUtils.kt
Normal file
File diff suppressed because it is too large
Load Diff
17
app/src/main/java/com/mob/utsmyanmar/utils/ECRSetups.kt
Normal file
17
app/src/main/java/com/mob/utsmyanmar/utils/ECRSetups.kt
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
package com.mob.utsmyanmar.utils
|
||||||
|
|
||||||
|
import com.utsmyanmar.ecr.data.model.Transactions
|
||||||
|
|
||||||
|
interface ECRSetups {
|
||||||
|
fun setUpECREchoTest()
|
||||||
|
fun setUpECRSale(trans: Transactions): Boolean
|
||||||
|
fun setUpECRQR(trans: Transactions): Boolean
|
||||||
|
fun setUpECRVoid(trans: Transactions): Boolean
|
||||||
|
fun setUpECRCashAdvance(trans: Transactions): Boolean
|
||||||
|
fun setUpECRPreAuth(trans: Transactions): Boolean
|
||||||
|
fun setUpECRPreAuthVoid(trans: Transactions): Boolean
|
||||||
|
fun setUpECRPreAuthComplete(trans: Transactions): Boolean
|
||||||
|
fun setUpECRPreAuthCompleteVoid(trans: Transactions): Boolean
|
||||||
|
fun setUpECRSettlement()
|
||||||
|
fun setUpECRRefund(trans: Transactions): Boolean
|
||||||
|
}
|
||||||
24
app/src/main/java/com/mob/utsmyanmar/utils/ECRSetupsCMHL.kt
Normal file
24
app/src/main/java/com/mob/utsmyanmar/utils/ECRSetupsCMHL.kt
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package com.mob.utsmyanmar.utils
|
||||||
|
|
||||||
|
import com.kizzy.cmhl.models.PingRequest
|
||||||
|
import com.kizzy.cmhl.models.PreAuthCancellationRequest
|
||||||
|
import com.kizzy.cmhl.models.PreAuthCompletionRequest
|
||||||
|
import com.kizzy.cmhl.models.PreAuthRequest
|
||||||
|
import com.kizzy.cmhl.models.QrPaymentRequest
|
||||||
|
import com.kizzy.cmhl.models.SaleRequest
|
||||||
|
import com.kizzy.cmhl.models.SettlementRequest
|
||||||
|
import com.kizzy.cmhl.models.VoidQrPaymentRequest
|
||||||
|
import com.kizzy.cmhl.models.VoidRequest
|
||||||
|
|
||||||
|
interface ECRSetupsCMHL {
|
||||||
|
fun setUpECREchoTest()
|
||||||
|
fun setupPingRequest(trans: PingRequest)
|
||||||
|
fun setUpECRSale(trans: SaleRequest): Boolean
|
||||||
|
fun setUpECRQR(trans: QrPaymentRequest): Boolean
|
||||||
|
fun setUpECRQRVoid(trans: VoidQrPaymentRequest): Boolean
|
||||||
|
fun setUpECRVoid(trans: VoidRequest): Boolean
|
||||||
|
fun setUpECRPreAuth(trans: PreAuthRequest): Boolean
|
||||||
|
fun setUpECRPreAuthVoid(trans: PreAuthCancellationRequest): Boolean
|
||||||
|
fun setUpECRPreAuthComplete(trans: PreAuthCompletionRequest): Boolean
|
||||||
|
fun setUpECRSettlement(trans: SettlementRequest)
|
||||||
|
}
|
||||||
14
app/src/main/java/com/mob/utsmyanmar/utils/OldECRSetups.kt
Normal file
14
app/src/main/java/com/mob/utsmyanmar/utils/OldECRSetups.kt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package com.mob.utsmyanmar.utils
|
||||||
|
|
||||||
|
interface OldECRSetups {
|
||||||
|
fun setUpECRTest()
|
||||||
|
fun setUpECRSale(msg: String): Boolean
|
||||||
|
fun setUpECRVoid(msg: String): Boolean
|
||||||
|
fun setUpECRCashAdvance(msg: String): Boolean
|
||||||
|
fun setUpECRPreAuth(msg: String): Boolean
|
||||||
|
fun setUpECRPreAuthVoid(msg: String): Boolean
|
||||||
|
fun setUpECRPreAuthComplete(msg: String): Boolean
|
||||||
|
fun setUpECRPreAuthCompleteVoid(msg: String): Boolean
|
||||||
|
fun setUpECRSettlement()
|
||||||
|
fun setUpECRRefund(msg: String): Boolean
|
||||||
|
}
|
||||||
@ -0,0 +1,152 @@
|
|||||||
|
package com.mob.utsmyanmar.viewmodel
|
||||||
|
|
||||||
|
|
||||||
|
import android.os.Handler
|
||||||
|
import android.os.Looper
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.mob.utsmyanmar.model.CardTransactionType
|
||||||
|
import com.utsmyanmar.checkxread.CheckXRead
|
||||||
|
import com.utsmyanmar.checkxread.checkcard.CheckCardResultX
|
||||||
|
import com.utsmyanmar.checkxread.model.CardDataX
|
||||||
|
import com.utsmyanmar.checkxread.readcard.ReadCardResultX
|
||||||
|
import com.utsmyanmar.checkxread.readcard.ReadCardX
|
||||||
|
import com.utsmyanmar.checkxread.sdk.SunmiSDK
|
||||||
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class CardReaderViewModel @Inject constructor() : ViewModel() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val TAG = CardReaderViewModel::class.java.simpleName
|
||||||
|
}
|
||||||
|
|
||||||
|
private val mainThreadHandler = Handler(Looper.getMainLooper())
|
||||||
|
|
||||||
|
private var oneTimeFlag = false
|
||||||
|
|
||||||
|
private var cardTransactionType: CardTransactionType? = null
|
||||||
|
|
||||||
|
/*
|
||||||
|
* UI States
|
||||||
|
*/
|
||||||
|
|
||||||
|
private val _errorCode = MutableStateFlow("")
|
||||||
|
val errorCode = _errorCode.asStateFlow()
|
||||||
|
|
||||||
|
private val _cardData = MutableStateFlow<CardDataX?>(null)
|
||||||
|
val cardData = _cardData.asStateFlow()
|
||||||
|
|
||||||
|
private var _cardTypeData = MutableStateFlow<Int?>(null)
|
||||||
|
val cardTypeData = _cardTypeData.asStateFlow()
|
||||||
|
|
||||||
|
private val _payDetail = MutableStateFlow<PayDetail?>(null)
|
||||||
|
val payDetail = _payDetail.asStateFlow()
|
||||||
|
|
||||||
|
private val _checkCardAlertMsg =
|
||||||
|
MutableStateFlow<String?>(null)
|
||||||
|
val checkCardAlertMsg =
|
||||||
|
_checkCardAlertMsg.asStateFlow()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transaction Type
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun setCardTransactionType(
|
||||||
|
cardTransactionType: CardTransactionType
|
||||||
|
) {
|
||||||
|
this.cardTransactionType = cardTransactionType
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCardTransactionType(): CardTransactionType? {
|
||||||
|
return cardTransactionType
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check Card Process
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun startCheckXProcess(
|
||||||
|
allType: Int,
|
||||||
|
timeOut: Int,
|
||||||
|
cardResultX: CheckCardResultX
|
||||||
|
) {
|
||||||
|
CheckXRead.getInstance()
|
||||||
|
.startCheckXProcess(
|
||||||
|
allType,
|
||||||
|
timeOut,
|
||||||
|
cardResultX
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isReaderReady(): Boolean {
|
||||||
|
return SunmiSDK.getInstance().readCardOptV2 != null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun cancelCheckXProcess() {
|
||||||
|
CheckXRead.getInstance()
|
||||||
|
.cancelCheckXProcess()
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read Card Process
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun startReadXProcess(
|
||||||
|
readCardX: ReadCardX,
|
||||||
|
readCardResultX: ReadCardResultX
|
||||||
|
) {
|
||||||
|
CheckXRead.getInstance()
|
||||||
|
.startReadXProcess(
|
||||||
|
readCardX,
|
||||||
|
readCardResultX
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Alert Message
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun setCheckCardAlertMsg(
|
||||||
|
msg: String,
|
||||||
|
isAutoHide: Boolean
|
||||||
|
) {
|
||||||
|
_checkCardAlertMsg.value = msg
|
||||||
|
|
||||||
|
if (isAutoHide) {
|
||||||
|
Handler(Looper.getMainLooper()).postDelayed({
|
||||||
|
_checkCardAlertMsg.value = null
|
||||||
|
}, 5000)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetUI() {
|
||||||
|
_checkCardAlertMsg.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* One Time Flag
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun resetOneTimeFlag() {
|
||||||
|
oneTimeFlag = false
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cancel Card Checking
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun cancelCheckCard() {
|
||||||
|
if (isReaderReady()) {
|
||||||
|
SunmiSDK.getInstance()
|
||||||
|
.cancelCheckCard()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setCardData(value: Int){
|
||||||
|
_cardTypeData.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package com.mob.utsmyanmar.viewmodel
|
||||||
|
|
||||||
|
import com.mob.utsmyanmar.model.TransResultStatus
|
||||||
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
|
import com.utsmyanmar.paylibs.system.SingleLiveEvent
|
||||||
|
|
||||||
|
interface ProcessingTransaction {
|
||||||
|
fun resetTransactionStatus()
|
||||||
|
|
||||||
|
fun getTransStatus(): SingleLiveEvent<TransResultStatus>
|
||||||
|
|
||||||
|
fun startOnlineProcess()
|
||||||
|
|
||||||
|
fun insertDB(payResult: PayDetail)
|
||||||
|
|
||||||
|
fun processVoidDB(payResult: PayDetail)
|
||||||
|
|
||||||
|
fun processPreVoidDb(payResult: PayDetail)
|
||||||
|
|
||||||
|
fun processPreCompDb(payResult: PayDetail)
|
||||||
|
|
||||||
|
fun processPreCompVoidDb(payResult: PayDetail)
|
||||||
|
|
||||||
|
fun processRefundDB(payResult: PayDetail)
|
||||||
|
}
|
||||||
@ -0,0 +1,476 @@
|
|||||||
|
package com.mob.utsmyanmar.viewmodel
|
||||||
|
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import androidx.lifecycle.LiveData
|
||||||
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.mob.utsmyanmar.model.SettlementType
|
||||||
|
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest
|
||||||
|
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse
|
||||||
|
import com.utsmyanmar.baselib.repo.Repository
|
||||||
|
import com.utsmyanmar.ecr.data.TransType
|
||||||
|
import com.utsmyanmar.ecr.data.model.Transactions
|
||||||
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
|
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt
|
||||||
|
import com.utsmyanmar.paylibs.print.printx.PrintXStatus
|
||||||
|
import com.utsmyanmar.paylibs.system.SingleLiveEvent
|
||||||
|
import com.utsmyanmar.paylibs.utils.AccountType
|
||||||
|
import com.utsmyanmar.paylibs.utils.PrintStatus
|
||||||
|
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
||||||
|
import com.utsmyanmar.paylibs.utils.enums.HostType
|
||||||
|
import com.utsmyanmar.paylibs.utils.enums.TransMenu
|
||||||
|
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import io.reactivex.rxjava3.core.Observable
|
||||||
|
import sunmi.sunmiui.utils.LogUtil
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class SharedViewModel @Inject constructor(
|
||||||
|
private val repository: Repository
|
||||||
|
) : ViewModel() {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "SharedViewModel"
|
||||||
|
}
|
||||||
|
|
||||||
|
val transactionsType = SingleLiveEvent<TransactionsType>()
|
||||||
|
|
||||||
|
val settlementType = SingleLiveEvent<SettlementType>()
|
||||||
|
|
||||||
|
val accountType = SingleLiveEvent<AccountType>()
|
||||||
|
|
||||||
|
val amount = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val totalAmount = SingleLiveEvent<Long>()
|
||||||
|
|
||||||
|
val cardNo = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val processCode = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val payDetail = SingleLiveEvent<PayDetail>()
|
||||||
|
|
||||||
|
val printStatus = SingleLiveEvent<PrintStatus>()
|
||||||
|
|
||||||
|
val merchantName = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val transactionName = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val payDetailList = SingleLiveEvent<List<PayDetail>>()
|
||||||
|
|
||||||
|
val isEcr = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
val traceNo = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val rrNNo = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val approvalCode = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val isEcrFinished = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
val isEmv = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
private val settlementStatus = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
private val wavePayStatus = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val sendMsg = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val qrData = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val qrRefNum = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val ecrCMD = SingleLiveEvent<TransType>()
|
||||||
|
|
||||||
|
val _transMenu = SingleLiveEvent<TransMenu?>()
|
||||||
|
|
||||||
|
val twoBtnLayout = MutableLiveData(0)
|
||||||
|
|
||||||
|
val oneBtnLayout = MutableLiveData(8)
|
||||||
|
|
||||||
|
private val reprintBtnLayout = MutableLiveData(8)
|
||||||
|
|
||||||
|
val isReprint = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
var signBitmap: Bitmap? = null
|
||||||
|
|
||||||
|
val hostType = SingleLiveEvent<HostType>()
|
||||||
|
|
||||||
|
private val printReceiptButtons = MutableLiveData(0)
|
||||||
|
|
||||||
|
val printReceiptMsg = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val reprintTransTypeMsg = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val ecrTrans = SingleLiveEvent<Transactions>()
|
||||||
|
|
||||||
|
val _manualEntryStatus = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val fullVoidPreauthStatus = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val partialVoidPreauthStatus = MutableLiveData<Boolean>()
|
||||||
|
|
||||||
|
val printXStatus = SingleLiveEvent<PrintStatus>()
|
||||||
|
|
||||||
|
private val _errorFragmentMsg = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
private val _successFragmentMsg = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
private val _currencyText = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val tapCardStatus = MutableLiveData(1)
|
||||||
|
|
||||||
|
val tapDeviceStatus = MutableLiveData(1)
|
||||||
|
|
||||||
|
val insertCardStatus = MutableLiveData(1)
|
||||||
|
|
||||||
|
val swipeCardStatus = MutableLiveData(0)
|
||||||
|
|
||||||
|
val countDownTxt = MutableLiveData<String>()
|
||||||
|
|
||||||
|
val mmqrLoading = MutableLiveData<Int>()
|
||||||
|
|
||||||
|
val isMMPay = MutableLiveData<Int>()
|
||||||
|
|
||||||
|
val isWavePay = MutableLiveData<Int>()
|
||||||
|
|
||||||
|
val mockData = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
val qrPayVisibility = MutableLiveData<Int>()
|
||||||
|
|
||||||
|
val loadingView = MutableLiveData(8)
|
||||||
|
|
||||||
|
val loadingMsg = SingleLiveEvent<String>()
|
||||||
|
|
||||||
|
private val isFallback = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
private val _isCardDataExist = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
private val _isAmountExist = SingleLiveEvent<Boolean>()
|
||||||
|
|
||||||
|
private var mPayDetail = PayDetail()
|
||||||
|
|
||||||
|
init {
|
||||||
|
setPrintStatus(PrintStatus.FIRST_PRINT)
|
||||||
|
isReprint.value = false
|
||||||
|
cardNo.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setSettlementStatus(status: Boolean) {
|
||||||
|
settlementStatus.value = status
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSettlementStatus(): MutableLiveData<Boolean> {
|
||||||
|
return settlementStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setWavePayStatus(status: Boolean) {
|
||||||
|
wavePayStatus.value = status
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getWavePayStatus(): MutableLiveData<Boolean> {
|
||||||
|
return wavePayStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setEmvTrans(status: Boolean) {
|
||||||
|
isEmv.value = status
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isEmvTrans(): SingleLiveEvent<Boolean> {
|
||||||
|
return isEmv
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPayDetail(): PayDetail {
|
||||||
|
return mPayDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun cachePayDetail(payDetail: PayDetail) {
|
||||||
|
mPayDetail = payDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPrintReceiptButtons(visible: Boolean) {
|
||||||
|
printReceiptButtons.value = if (visible) 0 else 8
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postPrintReceiptButtons(visible: Boolean) {
|
||||||
|
printReceiptButtons.postValue(if (visible) 0 else 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPrintReceiptButtons(): MutableLiveData<Int> {
|
||||||
|
return printReceiptButtons
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getReprintBtnLayout(): MutableLiveData<Int> {
|
||||||
|
return reprintBtnLayout
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setReprintBtnLayout(visible: Boolean) {
|
||||||
|
reprintBtnLayout.value = if (visible) 0 else 8
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPrintReceiptMsg(msg: String) {
|
||||||
|
printReceiptMsg.value = msg
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postPrintReceiptMsg(msg: String) {
|
||||||
|
printReceiptMsg.postValue(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setPrintStatus(printStatus: PrintStatus) {
|
||||||
|
this.printStatus.value = printStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postPrintStatus(printStatus: PrintStatus) {
|
||||||
|
this.printStatus.postValue(printStatus)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPrintStatusEvent(): SingleLiveEvent<PrintStatus> {
|
||||||
|
return printStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setIsFallback(status: Boolean) {
|
||||||
|
isFallback.value = status
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getIsFallback(): SingleLiveEvent<Boolean> {
|
||||||
|
return isFallback
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setCardDataExist(exist: Boolean) {
|
||||||
|
_isCardDataExist.value = exist
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCardDataExist(): SingleLiveEvent<Boolean> {
|
||||||
|
return _isCardDataExist
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAmountExist(exist: Boolean) {
|
||||||
|
_isAmountExist.value = exist
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAmountExist(): SingleLiveEvent<Boolean> {
|
||||||
|
return _isAmountExist
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getManualEntryStatus(): MutableLiveData<Boolean> {
|
||||||
|
return _manualEntryStatus
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setManualEntryStatus(status: Boolean) {
|
||||||
|
_manualEntryStatus.value = status
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getErrorFragmentMsg(): SingleLiveEvent<String> {
|
||||||
|
return _errorFragmentMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set_errorFragmentMsg(msg: String) {
|
||||||
|
_errorFragmentMsg.value = msg
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSuccessFragmentMsg(): SingleLiveEvent<String> {
|
||||||
|
return _successFragmentMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set_currencyText(msg: String) {
|
||||||
|
_currencyText.value = msg
|
||||||
|
}
|
||||||
|
|
||||||
|
fun get_currencyText(): SingleLiveEvent<String> {
|
||||||
|
return _currencyText
|
||||||
|
}
|
||||||
|
|
||||||
|
fun set_successFragmentMsg(msg: String) {
|
||||||
|
_successFragmentMsg.value = msg
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTransMenu(): SingleLiveEvent<TransMenu?> {
|
||||||
|
return _transMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTransMenu(transMenu: TransMenu?) {
|
||||||
|
_transMenu.value = transMenu
|
||||||
|
}
|
||||||
|
|
||||||
|
fun loadingMsg(msg: String) {
|
||||||
|
loadingView.value = 0
|
||||||
|
loadingMsg.value = msg
|
||||||
|
}
|
||||||
|
|
||||||
|
fun dismissLoadingMsg() {
|
||||||
|
loadingView.value = 8
|
||||||
|
loadingMsg.value = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getParams(siriusRequest: SiriusRequest): Observable<SiriusResponse> {
|
||||||
|
return repository.getParams(siriusRequest)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun printReceipt(isMerchantCopy: Boolean) {
|
||||||
|
PrintXReceipt.getInstance()
|
||||||
|
.printSmileReceipt(payDetail.value, isMerchantCopy, object : PrintXStatus {
|
||||||
|
|
||||||
|
override fun onSuccess() {
|
||||||
|
|
||||||
|
if (isMerchantCopy) {
|
||||||
|
|
||||||
|
if (!SystemParamsOperation.getInstance().demoStatus) {
|
||||||
|
if (SystemParamsOperation.getInstance().printISOStatus) {
|
||||||
|
PrintXReceipt.getInstance()
|
||||||
|
.printSmileISoReceipt(payDetail.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postPrintStatus(PrintStatus.FIRST_PRINT_DONE)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
setPrintStatus(PrintStatus.SECOND_PRINT_DONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure() {
|
||||||
|
LogUtil.d(TAG, "Print Status Result Failure!")
|
||||||
|
printXStatus.postValue(PrintStatus.EMPTY_PAPER_ROLL)
|
||||||
|
postPrintReceiptButtons(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startPrintReceipt(isFirstPrint: Boolean) {
|
||||||
|
|
||||||
|
payDetail.value?.let {
|
||||||
|
cachePayDetail(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintXReceipt.getInstance()
|
||||||
|
.printSmileReceipt(getPayDetail(), isFirstPrint, object : PrintXStatus {
|
||||||
|
|
||||||
|
override fun onSuccess() {
|
||||||
|
|
||||||
|
if (isFirstPrint) {
|
||||||
|
|
||||||
|
if (!SystemParamsOperation.getInstance().demoStatus) {
|
||||||
|
if (SystemParamsOperation.getInstance().printISOStatus) {
|
||||||
|
PrintXReceipt.getInstance()
|
||||||
|
.printSmileISoReceipt(getPayDetail())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
postPrintStatus(PrintStatus.FIRST_PRINT_DONE)
|
||||||
|
|
||||||
|
if (isEcr.value == true &&
|
||||||
|
SystemParamsOperation.getInstance()
|
||||||
|
.isAutoPrintCustomerCopy
|
||||||
|
) {
|
||||||
|
printReceiptButtons.postValue(8)
|
||||||
|
} else {
|
||||||
|
printReceiptButtons.postValue(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
postPrintStatus(PrintStatus.SECOND_PRINT_DONE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure() {
|
||||||
|
LogUtil.d(TAG, "Print Status Result Failure!")
|
||||||
|
|
||||||
|
if (isFirstPrint) {
|
||||||
|
setPrintStatus(PrintStatus.EMPTY_PAPER_ROLL_FIRST)
|
||||||
|
} else {
|
||||||
|
setPrintStatus(PrintStatus.EMPTY_PAPER_ROLL_SECOND)
|
||||||
|
}
|
||||||
|
|
||||||
|
postPrintReceiptButtons(true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startPrintProcess() {
|
||||||
|
|
||||||
|
LogUtil.d(TAG, "Print status : ${getPrintStatusEvent().value}")
|
||||||
|
|
||||||
|
when (getPrintStatusEvent().value) {
|
||||||
|
|
||||||
|
PrintStatus.FIRST_PRINT -> {
|
||||||
|
printReceipt(true)
|
||||||
|
postPrintReceiptMsg("Printing Receipt for Merchant")
|
||||||
|
postPrintReceiptButtons(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintStatus.SECOND_PRINT -> {
|
||||||
|
printReceipt(false)
|
||||||
|
postPrintReceiptMsg("Printing Receipt for Customer")
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintStatus.NOT_PRINT -> {
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun startPrintProcessSettlement() {
|
||||||
|
|
||||||
|
val detail = payDetail.value ?: return
|
||||||
|
|
||||||
|
PrintXReceipt.getInstance()
|
||||||
|
.printSmileSettlementReport(detail, object : PrintXStatus {
|
||||||
|
|
||||||
|
override fun onSuccess() {
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure() {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLastThreeTransactions(): LiveData<List<PayDetail>> {
|
||||||
|
return repository.getLastThreeTransactions()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getReversalTransaction(voucherNo: String): LiveData<PayDetail> {
|
||||||
|
return repository.getReversalTransaction(voucherNo)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updatePayDetail(payDetail: PayDetail) {
|
||||||
|
repository.updatePayDetail(payDetail)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun insertPayDetail(payDetail: PayDetail) {
|
||||||
|
repository.insertPayDetail(payDetail)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun enableCardStatusIcon(
|
||||||
|
tapCard: Boolean,
|
||||||
|
tapDevice: Boolean,
|
||||||
|
insertCard: Boolean,
|
||||||
|
swipeCard: Boolean
|
||||||
|
) {
|
||||||
|
|
||||||
|
tapCardStatus.value = if (tapCard) 1 else 0
|
||||||
|
tapDeviceStatus.value = if (tapDevice) 1 else 0
|
||||||
|
insertCardStatus.value = if (insertCard) 1 else 0
|
||||||
|
swipeCardStatus.value = if (swipeCard) 1 else 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun resetParamsMain() {
|
||||||
|
|
||||||
|
isEcrFinished.postValue(true)
|
||||||
|
isEcr.postValue(false)
|
||||||
|
|
||||||
|
setAmountExist(false)
|
||||||
|
setCardDataExist(false)
|
||||||
|
setTransMenu(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateButtonStatus() {
|
||||||
|
setSettlementStatus(
|
||||||
|
SystemParamsOperation.getInstance().settlementStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
setWavePayStatus(
|
||||||
|
SystemParamsOperation.getInstance().wavePayStatus
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,346 @@
|
|||||||
|
package com.mob.utsmyanmar.viewmodel
|
||||||
|
|
||||||
|
import android.text.TextUtils
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import com.mob.utsmyanmar.model.TransResultStatus
|
||||||
|
import com.utsmyanmar.baselib.repo.Repository
|
||||||
|
import com.utsmyanmar.paylibs.model.PayDetail
|
||||||
|
import com.utsmyanmar.paylibs.model.TradeData
|
||||||
|
import com.utsmyanmar.paylibs.network.ISOSocket
|
||||||
|
import com.utsmyanmar.paylibs.reversal.ReversalAction
|
||||||
|
import com.utsmyanmar.paylibs.reversal.ReversalListener
|
||||||
|
import com.utsmyanmar.paylibs.system.SystemDateTime
|
||||||
|
import com.utsmyanmar.paylibs.transactions.TransactionsOperation
|
||||||
|
import com.utsmyanmar.paylibs.transactions.TransactionsOperationListener
|
||||||
|
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 kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class TransProcessViewModel @Inject constructor(
|
||||||
|
private val repository: Repository
|
||||||
|
) : ViewModel(), ProcessingTransaction {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val RC_APPROVED_V1 = "00"
|
||||||
|
private const val RC_APPROVED_V2 = "000"
|
||||||
|
private const val TRY_SECONDARY = "TRY_SECONDARY"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var pan: String = ""
|
||||||
|
|
||||||
|
private lateinit var tradeData: TradeData
|
||||||
|
|
||||||
|
var payDetail: PayDetail? = null
|
||||||
|
|
||||||
|
private var oldTransPayDetail: PayDetail? = null
|
||||||
|
|
||||||
|
private var isSecondCall = false
|
||||||
|
private var isThirdCall = false
|
||||||
|
|
||||||
|
/*
|
||||||
|
* States
|
||||||
|
*/
|
||||||
|
|
||||||
|
private val _transResultStatus =
|
||||||
|
MutableStateFlow<TransResultStatus?>(null)
|
||||||
|
|
||||||
|
val transResultStatus =
|
||||||
|
_transResultStatus.asStateFlow()
|
||||||
|
|
||||||
|
private val _transType =
|
||||||
|
MutableStateFlow<TransactionsType?>(null)
|
||||||
|
|
||||||
|
val transType =
|
||||||
|
_transType.asStateFlow()
|
||||||
|
|
||||||
|
private val _printStatus =
|
||||||
|
MutableStateFlow(PrintStatus.FIRST_PRINT)
|
||||||
|
|
||||||
|
val printStatus =
|
||||||
|
_printStatus.asStateFlow()
|
||||||
|
|
||||||
|
private val _payDetailResult =
|
||||||
|
MutableStateFlow<PayDetail?>(null)
|
||||||
|
|
||||||
|
val payDetailResult =
|
||||||
|
_payDetailResult.asStateFlow()
|
||||||
|
|
||||||
|
private val _errorMessage =
|
||||||
|
MutableStateFlow<String?>(null)
|
||||||
|
|
||||||
|
val errorMessage =
|
||||||
|
_errorMessage.asStateFlow()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun setTradeData(tradeData: TradeData) {
|
||||||
|
this.tradeData = tradeData
|
||||||
|
payDetail = tradeData.payDetail
|
||||||
|
pan = payDetail?.cardNo ?: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTradeData(): TradeData {
|
||||||
|
return tradeData
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updatePayDetail(payDetail: PayDetail) {
|
||||||
|
this.payDetail = payDetail
|
||||||
|
|
||||||
|
tradeData = TradeData().apply {
|
||||||
|
this.payDetail = payDetail
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setOldTransPayDetail(payDetail: PayDetail) {
|
||||||
|
oldTransPayDetail = payDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Transaction
|
||||||
|
*/
|
||||||
|
|
||||||
|
override fun startOnlineProcess() {
|
||||||
|
|
||||||
|
TransactionsOperation.getInstance()
|
||||||
|
.getStartOperation(
|
||||||
|
tradeData,
|
||||||
|
transType.value
|
||||||
|
)
|
||||||
|
.checkOperation(object : TransactionsOperationListener {
|
||||||
|
|
||||||
|
override fun onSuccess(tradeData: TradeData) {
|
||||||
|
|
||||||
|
val payDetailRes =
|
||||||
|
tradeData.payDetail
|
||||||
|
|
||||||
|
if (
|
||||||
|
TextUtils.equals(
|
||||||
|
payDetailRes.tradeAnswerCode,
|
||||||
|
RC_APPROVED_V1
|
||||||
|
) ||
|
||||||
|
TextUtils.equals(
|
||||||
|
payDetailRes.tradeAnswerCode,
|
||||||
|
RC_APPROVED_V2
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
|
||||||
|
payDetailRes.invoiceNo =
|
||||||
|
SystemParamsOperation
|
||||||
|
.getInstance()
|
||||||
|
.incrementInvoiceNum
|
||||||
|
|
||||||
|
when (transType.value) {
|
||||||
|
|
||||||
|
TransactionsType.VOID -> {
|
||||||
|
processVoidDB(payDetailRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionsType.REFUND -> {
|
||||||
|
processRefundDB(payDetailRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionsType.PRE_AUTH_VOID -> {
|
||||||
|
processPreVoidDb(payDetailRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionsType.PRE_AUTH_COMPLETE -> {
|
||||||
|
processPreCompDb(payDetailRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
TransactionsType.PRE_AUTH_COMPLETE_VOID -> {
|
||||||
|
processPreCompVoidDb(payDetailRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {
|
||||||
|
insertDB(payDetailRes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_payDetailResult.value =
|
||||||
|
payDetailRes
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.SUCCESS
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_payDetailResult.value =
|
||||||
|
payDetailRes
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.FAIL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onReversal(
|
||||||
|
tradeData: TradeData
|
||||||
|
) {
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.REVERSAL_PREPARE
|
||||||
|
|
||||||
|
callReversal(tradeData)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(message: String) {
|
||||||
|
|
||||||
|
if (message == TRY_SECONDARY) {
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.SECONDARY
|
||||||
|
|
||||||
|
startOnlineProcess()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_errorMessage.value = message
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.ERROR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Database
|
||||||
|
*/
|
||||||
|
|
||||||
|
override fun insertDB(payResult: PayDetail) {
|
||||||
|
|
||||||
|
payDetail?.pinCipher = ""
|
||||||
|
|
||||||
|
repository.insertPayDetail(
|
||||||
|
payDetail
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processVoidDB(payResult: PayDetail) {
|
||||||
|
|
||||||
|
payDetail?.isCanceled = true
|
||||||
|
|
||||||
|
payDetail?.let {
|
||||||
|
repository.updatePayDetail(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
repository.insertPayDetail(
|
||||||
|
updateCurrentDateAndTime(payResult)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processRefundDB(payResult: PayDetail) {
|
||||||
|
|
||||||
|
oldTransPayDetail?.apply {
|
||||||
|
isReturnGood = true
|
||||||
|
isCanceled = true
|
||||||
|
|
||||||
|
repository.updatePayDetail(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
repository.insertPayDetail(
|
||||||
|
updateCurrentDateAndTime(payResult)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun processPreVoidDb(payResult: PayDetail) {}
|
||||||
|
override fun processPreCompDb(payResult: PayDetail) {}
|
||||||
|
override fun processPreCompVoidDb(payResult: PayDetail) {}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reversal
|
||||||
|
*/
|
||||||
|
|
||||||
|
private fun callReversal(tradeData: TradeData) {
|
||||||
|
|
||||||
|
payDetail = tradeData.payDetail
|
||||||
|
|
||||||
|
ReversalAction.getInstance()
|
||||||
|
.setData(tradeData)
|
||||||
|
.enqueue()
|
||||||
|
.startReversal(object : ReversalListener {
|
||||||
|
|
||||||
|
override fun onSuccessReversal() {
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.REVERSAL_SUCCESS
|
||||||
|
|
||||||
|
payDetail?.let {
|
||||||
|
repository.insertPayDetail(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNetworkFail(msg: String) {
|
||||||
|
|
||||||
|
SystemParamsOperation
|
||||||
|
.getInstance()
|
||||||
|
.setSecondHostEnable(true)
|
||||||
|
|
||||||
|
if (
|
||||||
|
SystemParamsOperation
|
||||||
|
.getInstance()
|
||||||
|
.isSecondHostEnabled
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (!isSecondCall) {
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.REVERSAL_SECONDARY
|
||||||
|
|
||||||
|
ISOSocket.getInstance()
|
||||||
|
.switchIp()
|
||||||
|
|
||||||
|
isSecondCall = true
|
||||||
|
|
||||||
|
callReversal(tradeData)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.REVERSAL_FAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.REVERSAL_FAIL
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailReversal(msg: String) {
|
||||||
|
|
||||||
|
_transResultStatus.value =
|
||||||
|
TransResultStatus.REVERSAL_FAIL
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Utils
|
||||||
|
*/
|
||||||
|
|
||||||
|
private fun updateCurrentDateAndTime(
|
||||||
|
payDetail: PayDetail
|
||||||
|
): PayDetail {
|
||||||
|
|
||||||
|
payDetail.tradeDate =
|
||||||
|
SystemDateTime.getMMDD()
|
||||||
|
|
||||||
|
payDetail.tradeTime =
|
||||||
|
SystemDateTime.getHHmmss()
|
||||||
|
|
||||||
|
return payDetail
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun resetTransactionStatus() {
|
||||||
|
_transResultStatus.value = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getTransStatus() = TODO()
|
||||||
|
}
|
||||||
@ -98,13 +98,16 @@ public class BaseApplication extends Application {
|
|||||||
mPinPadOptV2 = sunmiPayKernel.mPinPadOptV2;
|
mPinPadOptV2 = sunmiPayKernel.mPinPadOptV2;
|
||||||
mReadCardOptV2 = sunmiPayKernel.mReadCardOptV2;
|
mReadCardOptV2 = sunmiPayKernel.mReadCardOptV2;
|
||||||
mSecurityOptV2 = sunmiPayKernel.mSecurityOptV2;
|
mSecurityOptV2 = sunmiPayKernel.mSecurityOptV2;
|
||||||
//init
|
|
||||||
|
|
||||||
initTerminal();
|
|
||||||
|
|
||||||
PayLibsUtils.getInstance().initLib(mSecurityOptV2,mEMVOptV2,securityOpt,mReadCardOptV2);
|
PayLibsUtils.getInstance().initLib(mSecurityOptV2,mEMVOptV2,securityOpt,mReadCardOptV2);
|
||||||
SunmiSDK.getInstance().initSDK(mReadCardOptV2,basicOptV2);
|
SunmiSDK.getInstance().initSDK(mReadCardOptV2,basicOptV2);
|
||||||
|
|
||||||
|
try {
|
||||||
|
initTerminal();
|
||||||
|
} catch (Exception terminalInitException) {
|
||||||
|
terminalInitException.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
<color name="colorTextTitle">#222222</color>
|
<color name="colorTextTitle">#222222</color>
|
||||||
<color name="colorTextContent">#666666</color>
|
<color name="colorTextContent">#666666</color>
|
||||||
<color name="colorTextHelp">#999999</color>
|
<color name="colorTextHelp">#999999</color>
|
||||||
<color name="colorLineColor"># </color>
|
<color name="colorLineColor">#DDDDDD</color>
|
||||||
<color name="yellow">#FEE135</color>
|
<color name="yellow">#FEE135</color>
|
||||||
<color name="red">#D0312D</color>
|
<color name="red">#D0312D</color>
|
||||||
<color name="FD5A52">#FD5A52</color>
|
<color name="FD5A52">#FD5A52</color>
|
||||||
@ -19,4 +19,4 @@
|
|||||||
|
|
||||||
<color name="CDDDDDD">#dddddd</color>
|
<color name="CDDDDDD">#dddddd</color>
|
||||||
<color name="white">#FFFFFF</color>
|
<color name="white">#FFFFFF</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@ -4,6 +4,7 @@ plugins {
|
|||||||
alias(libs.plugins.android.library) apply false
|
alias(libs.plugins.android.library) apply false
|
||||||
alias(libs.plugins.kotlin.android) apply false
|
alias(libs.plugins.kotlin.android) apply false
|
||||||
alias(libs.plugins.kotlin.compose) apply false
|
alias(libs.plugins.kotlin.compose) apply false
|
||||||
alias(libs.plugins.hilt.android) apply false
|
|
||||||
alias(libs.plugins.kotlin.kapt) apply false
|
alias(libs.plugins.kotlin.kapt) apply false
|
||||||
|
id("com.google.dagger.hilt.android") version "2.59.2" apply false
|
||||||
|
id("com.google.devtools.ksp") version "2.3.4" apply false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
[versions]
|
[versions]
|
||||||
agp = "9.2.0"
|
agp = "9.2.0"
|
||||||
coreKtx = "1.18.0"
|
coreKtx = "1.18.0"
|
||||||
|
hiltAndroidCompiler = "2.59.2"
|
||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.3.0"
|
junitVersion = "1.3.0"
|
||||||
espressoCore = "3.7.0"
|
espressoCore = "3.7.0"
|
||||||
@ -11,10 +12,15 @@ composeBom = "2026.02.01"
|
|||||||
navigationCompose = "2.9.8"
|
navigationCompose = "2.9.8"
|
||||||
hilt = "2.57.1"
|
hilt = "2.57.1"
|
||||||
foundation = "1.11.1"
|
foundation = "1.11.1"
|
||||||
|
runtime = "1.11.1"
|
||||||
|
rxandroid = "3.0.2"
|
||||||
|
rxjava = "3.1.12"
|
||||||
|
hiltNavigationCompose = "1.2.0"
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||||
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
||||||
|
hilt-android-compiler = { module = "com.google.dagger:hilt-android-compiler", version.ref = "hiltAndroidCompiler" }
|
||||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||||
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
androidx-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
|
||||||
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
|
||||||
@ -31,11 +37,14 @@ androidx-compose-material3 = { group = "androidx.compose.material3", name = "mat
|
|||||||
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
|
hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
|
||||||
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
|
hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
|
||||||
androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundation" }
|
androidx-compose-foundation = { group = "androidx.compose.foundation", name = "foundation", version.ref = "foundation" }
|
||||||
|
androidx-compose-runtime = { group = "androidx.compose.runtime", name = "runtime", version.ref = "runtime" }
|
||||||
|
rxandroid = { module = "io.reactivex.rxjava3:rxandroid", version.ref = "rxandroid" }
|
||||||
|
rxjava = { module = "io.reactivex.rxjava3:rxjava", version.ref = "rxjava" }
|
||||||
|
androidx-hilt-navigation-compose = { module = "androidx.hilt:hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
android-library = { id = "com.android.library", version.ref = "agp" }
|
android-library = { id = "com.android.library", version.ref = "agp" }
|
||||||
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
|
||||||
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||||
hilt-android = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
|
|
||||||
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
|
kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" }
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
o/mpulib-1.2-runtime
|
||||||
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
o/PayLib-release-1.4.64-runtime
|
||||||
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
o/PayLib-release-1.4.64-runtime
|
||||||
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
o/sunmiui-1.1.27-runtime
|
||||||
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
o/sunmiui-1.1.27-runtime
|
||||||
Binary file not shown.
@ -2,6 +2,7 @@ package com.kizzy.xpay.util
|
|||||||
|
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import java.util.Locale.getDefault
|
||||||
|
|
||||||
object Sign {
|
object Sign {
|
||||||
|
|
||||||
@ -13,7 +14,7 @@ object Sign {
|
|||||||
val sorted = filtered.toSortedMap()
|
val sorted = filtered.toSortedMap()
|
||||||
val stringA = sorted.entries.joinToString("&") {"${it.key}=${it.value}"}
|
val stringA = sorted.entries.joinToString("&") {"${it.key}=${it.value}"}
|
||||||
val stringToSign = "$stringA&key=$appKey"
|
val stringToSign = "$stringA&key=$appKey"
|
||||||
val hash = stringToSign.hashedWithSha256().toUpperCase()
|
val hash = stringToSign.hashedWithSha256().uppercase(getDefault())
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user