Compare commits
No commits in common. "f827e75b1e13913937ab866584cf26a84dbc5f51" and "ded84bfa8ec51aa955a1b97132bd5e34ca18a8b3" have entirely different histories.
f827e75b1e
...
ded84bfa8e
@ -1,928 +0,0 @@
|
||||
package com.mob.utsmyanmar.ui.dashboard
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.offset
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.pager.HorizontalPager
|
||||
import androidx.compose.foundation.pager.rememberPagerState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.AccountBalanceWallet
|
||||
import androidx.compose.material.icons.filled.BarChart
|
||||
import androidx.compose.material.icons.filled.Check
|
||||
import androidx.compose.material.icons.filled.ChevronRight
|
||||
import androidx.compose.material.icons.filled.CreditCard
|
||||
import androidx.compose.material.icons.filled.Lock
|
||||
import androidx.compose.material.icons.filled.LockOpen
|
||||
import androidx.compose.material.icons.filled.Menu
|
||||
import androidx.compose.material.icons.filled.Notifications
|
||||
import androidx.compose.material.icons.filled.Replay
|
||||
import androidx.compose.material.icons.filled.SwapHoriz
|
||||
import androidx.compose.material.icons.filled.Sync
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Card
|
||||
import androidx.compose.material3.CardDefaults
|
||||
import androidx.compose.material3.DrawerValue
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ModalDrawerSheet
|
||||
import androidx.compose.material3.ModalNavigationDrawer
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.VerticalDivider
|
||||
import androidx.compose.material3.rememberDrawerState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import coil3.compose.AsyncImage
|
||||
import com.mob.utsmyanmar.R
|
||||
import com.mob.utsmyanmar.ui.components.appbar.AppBar
|
||||
import com.mob.utsmyanmar.ui.device_info.DeviceInfoUiState
|
||||
import com.mob.utsmyanmar.ui.preview.P2Preview
|
||||
import com.mob.utsmyanmar.ui.preview.P3Preview
|
||||
import com.mob.utsmyanmar.ui.theme.Color
|
||||
import com.utsmyanmar.paylibs.sign_on.EchoTestProcess
|
||||
import com.utsmyanmar.paylibs.sign_on.SignOnListener
|
||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlin.time.Duration.Companion.milliseconds
|
||||
|
||||
@Composable
|
||||
fun DashboardScreen2(
|
||||
onNavigateAmount: (String) -> Unit = {},
|
||||
onNavigateSignOn: () -> Unit = {},
|
||||
onNavigateSettlement: () -> Unit = {},
|
||||
onNavigateVersion: () -> Unit = {},
|
||||
onNavigateFunctions: () -> Unit = {},
|
||||
onNavigateAction: (String) -> Unit = {},
|
||||
onNavigateNotifications: () -> Unit = {},
|
||||
dashboardUiState: DashboardUiState = DashboardUiState(),
|
||||
deviceInfo: DeviceInfoUiState = DeviceInfoUiState()
|
||||
) {
|
||||
|
||||
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
|
||||
val scope = rememberCoroutineScope()
|
||||
val mainHandler = remember { Handler(Looper.getMainLooper()) }
|
||||
var showHostActionDialog by remember { mutableStateOf(false) }
|
||||
var activeHostAction by remember { mutableStateOf("Log-On") }
|
||||
var isHostActionRunning by remember { mutableStateOf(false) }
|
||||
var dialogMessage by remember { mutableStateOf("") }
|
||||
var reversalEnabled by remember { mutableStateOf(runCatching { SystemParamsOperation.getInstance().isReversalOn }.getOrDefault(false)) }
|
||||
|
||||
val isOnline = true
|
||||
|
||||
fun confirmationMessage(action: String) = "Do you want to start ${action.lowercase()}?"
|
||||
fun processingMessage(action: String) = "Sending ${action.lowercase()} request to host..."
|
||||
fun successMessage(action: String) = "$action success."
|
||||
fun failureMessage(action: String, resultCode: Int?) =
|
||||
"$action failed. Response code: ${resultCode ?: -1}"
|
||||
|
||||
fun networkFailureMessage(action: String) = "Network error during $action."
|
||||
fun openHostActionDialog(action: String) {
|
||||
activeHostAction = action
|
||||
isHostActionRunning = false
|
||||
dialogMessage = confirmationMessage(action)
|
||||
showHostActionDialog = true
|
||||
}
|
||||
|
||||
if (showHostActionDialog) {
|
||||
AlertDialog(
|
||||
onDismissRequest = {
|
||||
if (!isHostActionRunning) {
|
||||
showHostActionDialog = false
|
||||
}
|
||||
}, title = {
|
||||
Text(
|
||||
text = activeHostAction, color = Color.LegacyRed, fontWeight = FontWeight.Bold
|
||||
)
|
||||
}, text = {
|
||||
Text(text = dialogMessage)
|
||||
}, confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
if (isHostActionRunning) return@TextButton
|
||||
|
||||
if (dialogMessage != confirmationMessage(activeHostAction)) {
|
||||
showHostActionDialog = false
|
||||
dialogMessage = confirmationMessage(activeHostAction)
|
||||
return@TextButton
|
||||
}
|
||||
|
||||
isHostActionRunning = true
|
||||
dialogMessage = processingMessage(activeHostAction)
|
||||
|
||||
val signOnProcess = EchoTestProcess.getInstance()
|
||||
val request = when (activeHostAction) {
|
||||
"Echo Test" -> signOnProcess.enqueue(false)
|
||||
"Log-Off" -> signOnProcess.enqueueLogOff()
|
||||
else -> signOnProcess.enqueueLogOn()
|
||||
}
|
||||
|
||||
request.startSignOn(object : SignOnListener {
|
||||
override fun onSuccessSignOn() {
|
||||
mainHandler.post {
|
||||
isHostActionRunning = false
|
||||
dialogMessage = successMessage(activeHostAction)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailureSignOn(resultCode: Int?) {
|
||||
mainHandler.post {
|
||||
isHostActionRunning = false
|
||||
mainHandler.post {
|
||||
isHostActionRunning = false
|
||||
dialogMessage = failureMessage(activeHostAction, resultCode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun onNetworkFailSignOn(message: String?) {
|
||||
mainHandler.post {
|
||||
isHostActionRunning = false
|
||||
dialogMessage = message?.takeIf { it.isNotBlank() }
|
||||
?: networkFailureMessage(activeHostAction)
|
||||
}
|
||||
}
|
||||
})
|
||||
}) {
|
||||
Text(
|
||||
text = when {
|
||||
isHostActionRunning -> "Processing"
|
||||
dialogMessage == confirmationMessage(activeHostAction) -> "Start"
|
||||
else -> "Close"
|
||||
}, color = Color.LegacyRed
|
||||
)
|
||||
}
|
||||
}, dismissButton = {
|
||||
if (!isHostActionRunning) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
showHostActionDialog = false
|
||||
dialogMessage = confirmationMessage(activeHostAction)
|
||||
}) {
|
||||
Text(text = "Cancel", color = Color.Gray)
|
||||
}
|
||||
}
|
||||
}, containerColor = Color.White
|
||||
)
|
||||
}
|
||||
|
||||
ModalNavigationDrawer(
|
||||
drawerState = drawerState, drawerContent = {
|
||||
ModalDrawerSheet(
|
||||
modifier = Modifier.fillMaxWidth(0.78f),
|
||||
drawerContainerColor = Color.White,
|
||||
drawerShape = RoundedCornerShape(topEnd = 24.dp, bottomEnd = 24.dp)
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(Color.IvoryBeige)
|
||||
.padding(horizontal = 20.dp, vertical = 28.dp)
|
||||
) {
|
||||
Row {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(80.dp)
|
||||
.clip(CircleShape)
|
||||
.background(Color.White), contentAlignment = Alignment.Center
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.logo_mob),
|
||||
contentDescription = "mob logo",
|
||||
modifier = Modifier
|
||||
.size(100.dp)
|
||||
.padding(16.dp),
|
||||
contentScale = ContentScale.Fit
|
||||
)
|
||||
}
|
||||
|
||||
Column {
|
||||
Text(
|
||||
text = "MOB Merchant",
|
||||
color = Color.CrimsonRed,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = "S/N:${deviceInfo.serialNumber}",
|
||||
color = Color.Black,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(
|
||||
text = if (isOnline) "Online" else "Offline",
|
||||
color = if (isOnline) Color.Success else Color.Error,
|
||||
fontSize = 12.sp,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
Text(
|
||||
text = "Connection Settings",
|
||||
fontWeight = FontWeight.Medium,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
Item(
|
||||
title = "Echo Test", subTitle = "Test Connection Status",
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
openHostActionDialog("Echo Test")
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_up_down_arrow),
|
||||
contentDescription = "icon",
|
||||
tint = Color.LegacyRed
|
||||
)
|
||||
},
|
||||
trailingIcon = {},
|
||||
)
|
||||
Item(
|
||||
title = "Log-On", subTitle = "Log on to System",
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
openHostActionDialog("Log-On")
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_lock),
|
||||
contentDescription = "icon",
|
||||
tint = Color.LegacyRed
|
||||
)
|
||||
},
|
||||
trailingIcon = {},
|
||||
)
|
||||
Item(
|
||||
title = "Log-Off", subTitle = "Log off from System",
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
openHostActionDialog("Log-Off")
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_cancel_circle),
|
||||
contentDescription = "icon",
|
||||
tint = Color.LegacyRed
|
||||
)
|
||||
},
|
||||
trailingIcon = {},
|
||||
)
|
||||
Item(
|
||||
title = "Reversal", subTitle = "Enable / Disable Reversal",
|
||||
onClick = {
|
||||
reversalEnabled = !reversalEnabled
|
||||
runCatching { SystemParamsOperation.getInstance().setReversalFlag(reversalEnabled) }
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
Icons.Default.Sync,
|
||||
contentDescription = "icon",
|
||||
tint = Color.LegacyRed
|
||||
)
|
||||
},
|
||||
trailingIcon = {
|
||||
Switch(
|
||||
checked = reversalEnabled,
|
||||
onCheckedChange = { isChecked ->
|
||||
reversalEnabled = isChecked
|
||||
runCatching { SystemParamsOperation.getInstance().setReversalFlag(isChecked) }
|
||||
}
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
Text(
|
||||
text = "System Management",
|
||||
fontWeight = FontWeight.Medium,
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
)
|
||||
|
||||
Item(
|
||||
title = "Functions", subTitle = "System Function Settings",
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onNavigateFunctions()
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_four_boxes),
|
||||
contentDescription = "icon",
|
||||
tint = Color.LegacyRed,
|
||||
modifier = Modifier.size(16.dp)
|
||||
)
|
||||
},
|
||||
trailingIcon = {},
|
||||
)
|
||||
Item(
|
||||
title = "Version", subTitle = "View App Version Info",
|
||||
onClick = {
|
||||
scope.launch { drawerState.close() }
|
||||
onNavigateVersion()
|
||||
},
|
||||
leadingIcon = {
|
||||
Icon(
|
||||
painterResource(R.drawable.ic_version),
|
||||
contentDescription = "icon",
|
||||
tint = Color.LegacyRed
|
||||
)
|
||||
},
|
||||
trailingIcon = {},
|
||||
)
|
||||
|
||||
}
|
||||
}) {
|
||||
//body start
|
||||
Scaffold(
|
||||
containerColor = Color.IvoryBeige, topBar = {
|
||||
AppBar(
|
||||
title = "Dashboard",
|
||||
icon = Icons.Default.Menu,
|
||||
onIconClick = { scope.launch { drawerState.open() } },
|
||||
actions = {
|
||||
IconButton(onClick = onNavigateNotifications) {
|
||||
Box {
|
||||
Icon(
|
||||
imageVector = Icons.Default.Notifications,
|
||||
contentDescription = "Notifications",
|
||||
tint = Color.White
|
||||
)
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(8.dp)
|
||||
.background(Color.GoldenGlow, CircleShape)
|
||||
.align(Alignment.TopEnd)
|
||||
.offset(x = 2.dp, y = (-2).dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}) { paddingValues ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.fillMaxSize()
|
||||
) {
|
||||
//top section
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
AdvertisingArea()
|
||||
}
|
||||
//center section
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.fillMaxWidth(),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
SummaryCard()
|
||||
}
|
||||
//pager section
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.weight(1.3f)
|
||||
.fillMaxWidth(),
|
||||
) {
|
||||
MenuPager(
|
||||
items = buildMenuItems(
|
||||
onNavigateAmount = onNavigateAmount,
|
||||
onNavigateSignOn = onNavigateSignOn,
|
||||
onNavigateSettlement = onNavigateSettlement,
|
||||
onNavigateAction = onNavigateAction
|
||||
),
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
//transactions section
|
||||
RecentTransactions(
|
||||
transactions = dashboardUiState.recentTransactions,
|
||||
modifier = Modifier
|
||||
.weight(1.2f)
|
||||
.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun AdvertisingArea() {
|
||||
|
||||
val imageArray = listOf(
|
||||
"https://i.ytimg.com/vi/eRUVxGRp1Ms/maxresdefault.jpg",
|
||||
"https://i.ytimg.com/vi/AwvmgTPd7qw/maxresdefault.jpg",
|
||||
"https://mma.prnewswire.com/media/2080956/SUNMI_3rd_generation_products_T3_PRO_series_V3_MIX.jpg?p=facebook"
|
||||
)
|
||||
val pageState = rememberPagerState(pageCount = { imageArray.size })
|
||||
|
||||
LaunchedEffect(pageState) {
|
||||
while (true) {
|
||||
delay(10000.milliseconds)
|
||||
val nextPage = (pageState.currentPage + 1) % imageArray.size
|
||||
|
||||
pageState.animateScrollToPage(
|
||||
page = nextPage, animationSpec = tween(durationMillis = 700)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Card(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
shape = RoundedCornerShape(0.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color.White),
|
||||
) {
|
||||
HorizontalPager(
|
||||
state = pageState, modifier = Modifier.fillMaxSize()
|
||||
) { page ->
|
||||
AsyncImage(
|
||||
model = imageArray[page],
|
||||
contentDescription = "ads images",
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
contentScale = ContentScale.Crop
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SummaryCard() {
|
||||
Card(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color.White),
|
||||
elevation = CardDefaults.cardElevation(4.dp)
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.CenterVertically) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
SummaryItem(
|
||||
title = "Sales Today",
|
||||
value = "MMK 2,000,000",
|
||||
subtitle = "47 Transactions",
|
||||
icon = Icons.Default.BarChart,
|
||||
iconBg = Color.CrimsonRed
|
||||
)
|
||||
|
||||
HorizontalDivider(
|
||||
color = Color.Gray,
|
||||
modifier = Modifier.padding(vertical = 6.dp, horizontal = 6.dp)
|
||||
)
|
||||
|
||||
SummaryItem(
|
||||
title = "Settlement",
|
||||
value = "Completed",
|
||||
subtitle = "Today 11:00 PM",
|
||||
icon = Icons.Default.Check,
|
||||
iconBg = Color.CrimsonRed
|
||||
)
|
||||
}
|
||||
|
||||
VerticalDivider(color = Color.Gray, modifier = Modifier.height(160.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(0.75f)
|
||||
.padding(start = 18.dp),
|
||||
horizontalAlignment = Alignment.Start
|
||||
) {
|
||||
Row(verticalAlignment = Alignment.Bottom) {
|
||||
Text(
|
||||
text = "Last Sync", fontSize = 12.sp
|
||||
)
|
||||
IconCircle(Icons.Default.Sync, Color.CrimsonRed)
|
||||
}
|
||||
|
||||
Spacer(Modifier.height(6.dp))
|
||||
|
||||
Text(
|
||||
text = "5 mins ago",
|
||||
fontSize = 18.sp,
|
||||
color = Color.LegacyRed,
|
||||
fontWeight = FontWeight.SemiBold
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SummaryItem(
|
||||
title: String,
|
||||
value: String,
|
||||
subtitle: String,
|
||||
icon: ImageVector,
|
||||
iconBg: androidx.compose.ui.graphics.Color
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.Top, modifier = Modifier.padding(6.dp)
|
||||
) {
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(title, fontSize = 12.sp)
|
||||
Text(
|
||||
value, fontSize = 14.sp, color = Color.LegacyRed, fontWeight = FontWeight.Bold
|
||||
)
|
||||
Text(subtitle, fontSize = 12.sp)
|
||||
}
|
||||
IconCircle(icon, iconBg)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun IconCircle(
|
||||
icon: ImageVector, color: androidx.compose.ui.graphics.Color
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(38.dp)
|
||||
.clip(CircleShape)
|
||||
.background(color.copy(alpha = 0.1f)),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Icon(
|
||||
imageVector = icon,
|
||||
contentDescription = null,
|
||||
tint = color,
|
||||
modifier = Modifier.size(22.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class DashboardMenuItem(
|
||||
val title: String,
|
||||
val iconContent: @Composable () -> Unit,
|
||||
val onClick: () -> Unit
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun buildMenuItems(
|
||||
onNavigateAmount: (String) -> Unit,
|
||||
onNavigateSignOn: () -> Unit,
|
||||
onNavigateSettlement: () -> Unit,
|
||||
onNavigateAction: (String) -> Unit
|
||||
): List<DashboardMenuItem> = listOf(
|
||||
DashboardMenuItem("Sale", { Icon(painterResource(R.drawable.ic_terminal), contentDescription = null, modifier = Modifier.size(40.dp), tint = Color.LegacyRed) }) { onNavigateAmount("Sale") },
|
||||
DashboardMenuItem("MMQR", { Image(painter = painterResource(R.drawable.ic_mmqr_logo), contentDescription = null, modifier = Modifier.height(48.dp)) }) { },
|
||||
DashboardMenuItem("History", { Icon(painterResource(R.drawable.ic_history), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { },
|
||||
DashboardMenuItem("Sign On", { Icon(painterResource(R.drawable.ic_sign_on), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateSignOn() },
|
||||
DashboardMenuItem("Settlement", { Icon(painterResource(R.drawable.ic_settlement), contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateSettlement() },
|
||||
DashboardMenuItem("Void", { Icon(Icons.Default.Lock, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Void") },
|
||||
DashboardMenuItem("Refund", { Icon(Icons.Default.Replay, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Refund") },
|
||||
DashboardMenuItem("Pre-Auth", { Icon(Icons.Default.Lock, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth") },
|
||||
DashboardMenuItem("Pre-Auth Void", { Icon(Icons.Default.LockOpen, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Void") },
|
||||
DashboardMenuItem("Pre-Auth Complete", { Icon(Icons.Default.CreditCard, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Complete") },
|
||||
DashboardMenuItem("Pre-Auth Complete Void", { Icon(Icons.Default.SwapHoriz, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Pre-Auth Complete Void") },
|
||||
DashboardMenuItem("Cash Out", { Icon(Icons.Default.AccountBalanceWallet, contentDescription = null, modifier = Modifier.size(32.dp), tint = Color.LegacyRed) }) { onNavigateAction("Cash Out") },
|
||||
)
|
||||
|
||||
@Composable
|
||||
private fun MenuPager(
|
||||
items: List<DashboardMenuItem>,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
val pages = items.chunked(6)
|
||||
val pagerState = rememberPagerState(pageCount = { pages.size })
|
||||
|
||||
Column(modifier = modifier) {
|
||||
HorizontalPager(
|
||||
state = pagerState,
|
||||
modifier = Modifier.weight(1f)
|
||||
) { pageIndex ->
|
||||
MenuPage(items = pages[pageIndex])
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
repeat(pages.size) { index ->
|
||||
val selected = pagerState.currentPage == index
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp)
|
||||
.size(if (selected) 8.dp else 6.dp)
|
||||
.background(
|
||||
color = if (selected) Color.LegacyRed else Color.Gray.copy(alpha = 0.4f),
|
||||
shape = CircleShape
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MenuPage(items: List<DashboardMenuItem>) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||
modifier = Modifier.padding(horizontal = 16.dp)
|
||||
) {
|
||||
Spacer(Modifier.height(8.dp))
|
||||
items.chunked(3).forEach { rowItems ->
|
||||
Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
|
||||
rowItems.forEach { item ->
|
||||
MenuCard(
|
||||
title = item.title,
|
||||
icon = item.iconContent,
|
||||
modifier = Modifier.weight(1f),
|
||||
onClick = item.onClick
|
||||
)
|
||||
}
|
||||
repeat(3 - rowItems.size) {
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun MenuCard(
|
||||
title: String,
|
||||
icon: @Composable () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
onClick: (() -> Unit)? = null
|
||||
) {
|
||||
Card(
|
||||
modifier = modifier
|
||||
.height(100.dp)
|
||||
.then(
|
||||
if (onClick != null) {
|
||||
Modifier.clickable(onClick = onClick)
|
||||
} else {
|
||||
Modifier
|
||||
}
|
||||
),
|
||||
shape = RoundedCornerShape(14.dp),
|
||||
colors = CardDefaults.cardColors(containerColor = Color.White),
|
||||
elevation = CardDefaults.cardElevation(5.dp)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(6.dp)
|
||||
) {
|
||||
Column {
|
||||
icon()
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = title,
|
||||
fontSize = 12.sp,
|
||||
color = Color.Black,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
maxLines = 1,
|
||||
modifier = Modifier.weight(1f)
|
||||
)
|
||||
Icon(
|
||||
imageVector = Icons.Default.ChevronRight,
|
||||
contentDescription = null,
|
||||
tint = Color.LegacyRed,
|
||||
modifier = Modifier.size(28.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RecentTransactions(
|
||||
transactions: List<TrnxRecord>,
|
||||
modifier: Modifier = Modifier
|
||||
) {
|
||||
Column(modifier = modifier) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp, vertical = 6.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "Recent Transactions",
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
fontSize = 14.sp
|
||||
)
|
||||
}
|
||||
HorizontalDivider(
|
||||
modifier = Modifier.padding(horizontal = 16.dp),
|
||||
color = Color.Gray.copy(alpha = 0.2f)
|
||||
)
|
||||
LazyColumn(modifier = Modifier.fillMaxSize()) {
|
||||
if (transactions.isEmpty()) {
|
||||
item {
|
||||
Text(
|
||||
text = "No recent transactions",
|
||||
color = Color.Gray,
|
||||
fontSize = 13.sp,
|
||||
textAlign = TextAlign.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 24.dp)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
items(items = transactions, key = { it.pid }) { record ->
|
||||
TrnxRow(record = record)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun TrnxRow(record: TrnxRecord) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 12.dp, vertical = 4.dp)
|
||||
.clip(RoundedCornerShape(10.dp))
|
||||
.background(Color.White)
|
||||
.padding(horizontal = 12.dp, vertical = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.size(36.dp)
|
||||
.background(Color.LegacyRed.copy(alpha = 0.1f), CircleShape),
|
||||
contentAlignment = Alignment.Center
|
||||
) {
|
||||
Text(
|
||||
text = record.typeLabel.take(1),
|
||||
color = Color.LegacyRed,
|
||||
fontWeight = FontWeight.Bold,
|
||||
fontSize = 15.sp
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.width(10.dp))
|
||||
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = if (record.isVoided) "${record.typeLabel} (Voided)" else record.typeLabel,
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
color = if (record.isVoided) Color.Gray else Color.Black
|
||||
)
|
||||
Text(
|
||||
text = record.maskedCard,
|
||||
fontSize = 11.sp,
|
||||
color = Color.Gray
|
||||
)
|
||||
}
|
||||
|
||||
Column(horizontalAlignment = Alignment.End) {
|
||||
Text(
|
||||
text = record.amountDisplay,
|
||||
fontSize = 13.sp,
|
||||
fontWeight = FontWeight.Bold,
|
||||
color = if (record.isVoided) Color.Gray else Color.LegacyRed
|
||||
)
|
||||
Text(
|
||||
text = record.dateTime,
|
||||
fontSize = 10.sp,
|
||||
color = Color.Gray
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val previewTransactions = listOf(
|
||||
TrnxRecord(1L, "Sale", "MMK 10,000", "**** 1234", "06/10 14:32", isVoided = false, isApproved = true),
|
||||
TrnxRecord(2L, "Void", "MMK 5,500", "**** 5678", "06/10 13:10", isVoided = true, isApproved = false),
|
||||
TrnxRecord(3L, "Refund", "MMK 2,000", "**** 9012", "06/09 09:45", isVoided = false, isApproved = true),
|
||||
TrnxRecord(4L, "Sale", "MMK 30,000", "**** 3456", "06/09 08:00", isVoided = false, isApproved = true),
|
||||
TrnxRecord(5L, "Settlement", "MMK 0", "----", "06/08 18:00", isVoided = false, isApproved = true),
|
||||
)
|
||||
|
||||
@P3Preview
|
||||
@P2Preview
|
||||
@Composable
|
||||
fun PreviewDashboardScreen2() {
|
||||
DashboardScreen2(dashboardUiState = DashboardUiState(previewTransactions))
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun PreviewItem() {
|
||||
Item(
|
||||
onClick = {},
|
||||
title = "title",
|
||||
subTitle = "sub-title"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
fun Item(
|
||||
onClick: () -> Unit,
|
||||
title: String,
|
||||
subTitle: String,
|
||||
leadingIcon: (@Composable () -> Unit)? = null,
|
||||
trailingIcon: (@Composable () -> Unit)? = null,
|
||||
) {
|
||||
Button(
|
||||
onClick = onClick,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.White,
|
||||
contentColor = Color.Black
|
||||
),
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
// Square icon background
|
||||
leadingIcon?.let {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = Modifier
|
||||
.size(40.dp)
|
||||
.clip(RoundedCornerShape(16.dp)) // change to RectangleShape for sharp corners
|
||||
.background(Color.LegacyRed.copy(alpha = 0.1f))
|
||||
.padding(8.dp)
|
||||
) {
|
||||
it()
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(modifier = Modifier.width(12.dp))
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Text(text = title)
|
||||
Text(
|
||||
text = subTitle,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = Color.Gray
|
||||
)
|
||||
}
|
||||
|
||||
trailingIcon?.invoke()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,8 +14,6 @@ import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import java.math.BigDecimal
|
||||
import java.text.DecimalFormat
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@ -59,7 +57,7 @@ class DashboardViewModel @Inject constructor(
|
||||
|
||||
private fun PayDetail.toRecord(): TrnxRecord {
|
||||
val type = transType?.takeIf { it.isNotBlank() }?.let { formatTypeLabel(it) } ?: "Transaction"
|
||||
val amount = "MMK ${formatAmount(amount)}"
|
||||
val amount = "MMK %,d".format(amount)
|
||||
val card = CardNo?.takeIf { it.length >= 4 }?.let { "**** ${it.takeLast(4)}" } ?: "----"
|
||||
val dt = buildDateTime(TradeDate, TradeTime)
|
||||
val approved = tradeAnswerCode == "00" || approvalCode?.isNotBlank() == true
|
||||
@ -75,11 +73,6 @@ private fun PayDetail.toRecord(): TrnxRecord {
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fun formatAmount(amount: Long): String {
|
||||
val scaled = BigDecimal(amount).movePointLeft(2)
|
||||
return DecimalFormat("#,###.00").format(scaled)
|
||||
}
|
||||
private fun formatTypeLabel(raw: String): String = when {
|
||||
raw.contains("SALE", ignoreCase = true) -> "Sale"
|
||||
raw.contains("VOID", ignoreCase = true) -> "Void"
|
||||
|
||||
@ -1,438 +0,0 @@
|
||||
package com.mob.utsmyanmar.ui.manual_entry
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
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.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.outlined.CreditCard
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.TextRange
|
||||
import androidx.compose.ui.text.font.FontFamily
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.input.ImeAction
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import com.mob.utsmyanmar.ui.components.appbar.AppBar
|
||||
import com.mob.utsmyanmar.ui.pinpad.PinPadViewModel
|
||||
import com.mob.utsmyanmar.ui.preview.P2Preview
|
||||
import com.mob.utsmyanmar.ui.preview.P3Preview
|
||||
import com.mob.utsmyanmar.ui.theme.Color
|
||||
import com.mob.utsmyanmar.utils.TransactionUtil
|
||||
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||
import com.mob.utsmyanmar.viewmodel.TransProcessViewModel
|
||||
import com.utsmyanmar.checkxread.model.CardDataX
|
||||
import com.utsmyanmar.checkxread.util.CardTypeX
|
||||
import com.utsmyanmar.paylibs.model.TradeData
|
||||
import com.utsmyanmar.paylibs.utils.POSUtil
|
||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||
import sunmi.sunmiui.utils.LogUtil
|
||||
|
||||
private const val PAN_RAW_MAX = 16
|
||||
private const val EXPIRY_RAW_MAX = 4
|
||||
|
||||
|
||||
@Composable
|
||||
fun InputManualCardRoute(
|
||||
transProcessViewModel: TransProcessViewModel,
|
||||
sharedViewModel: SharedViewModel,
|
||||
pinPadViewModel: PinPadViewModel,
|
||||
onBack: () -> Unit,
|
||||
onNavigatePinPad: () -> Unit
|
||||
) {
|
||||
var pan by rememberSaveable { mutableStateOf("") }
|
||||
var expiry by rememberSaveable { mutableStateOf("") }
|
||||
var panError by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
var expiryError by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
val focusManager = LocalFocusManager.current
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
pan = ""; expiry = ""
|
||||
panError = null; expiryError = null
|
||||
}
|
||||
|
||||
fun validateAndConfirm() {
|
||||
panError = null; expiryError = null
|
||||
val rawPan = pan.filter { it.isDigit() }
|
||||
val rawExp = expiry.filter { it.isDigit() }
|
||||
|
||||
if (rawPan.length < 13 || rawPan.length > PAN_RAW_MAX) {
|
||||
panError = "Invalid card number"; return
|
||||
}
|
||||
if (!luhnCheck(rawPan)) {
|
||||
panError = "Invalid card number"; return
|
||||
}
|
||||
if (rawExp.length != EXPIRY_RAW_MAX) {
|
||||
expiryError = "Enter MM/YY"; return
|
||||
}
|
||||
val month = rawExp.take(2).toIntOrNull() ?: 0
|
||||
if (month < 1 || month > 12) {
|
||||
expiryError = "Invalid month"; return
|
||||
}
|
||||
|
||||
focusManager.clearFocus()
|
||||
|
||||
LogUtil.d("Tag","exp date : $rawExp")
|
||||
val cardNo = rawPan.replace("\\s","")
|
||||
val expDate =
|
||||
POSUtil.getInstance().getISOFormatExpDate(rawExp)
|
||||
|
||||
val mpuCardData = CardDataX()
|
||||
mpuCardData.setPan(cardNo)
|
||||
mpuCardData.setExp(expDate)
|
||||
mpuCardData.setCardHolderName("MANUAL ENTRY")
|
||||
|
||||
val tradeData =
|
||||
TransactionUtil.initMPUTransaction(mpuCardData, CardTypeX.MANUAL)
|
||||
transProcessViewModel.setTransType(sharedViewModel.transactionsType.value)
|
||||
transProcessViewModel.setTradeData(tradeData)
|
||||
pinPadViewModel.setTradeData(tradeData)
|
||||
onNavigatePinPad()
|
||||
}
|
||||
|
||||
ManualCardEntryScreen(
|
||||
pan = pan,
|
||||
expiry = expiry,
|
||||
panError = panError,
|
||||
expiryError = expiryError,
|
||||
onPanChange = { input ->
|
||||
val digits = input.filter { it.isDigit() }.take(PAN_RAW_MAX)
|
||||
pan = digits
|
||||
panError = null
|
||||
},
|
||||
onExpiryChange = { input ->
|
||||
val digits = input.filter { it.isDigit() }.take(EXPIRY_RAW_MAX)
|
||||
expiry = digits
|
||||
expiryError = null
|
||||
},
|
||||
onBackClick = onBack,
|
||||
onCancelClick = onBack,
|
||||
onConfirmClick = ::validateAndConfirm
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun ManualCardEntryScreen(
|
||||
pan: String,
|
||||
expiry: String,
|
||||
panError: String?,
|
||||
expiryError: String?,
|
||||
onPanChange: (String) -> Unit,
|
||||
onExpiryChange: (String) -> Unit,
|
||||
onBackClick: () -> Unit,
|
||||
onCancelClick: () -> Unit,
|
||||
onConfirmClick: () -> Unit
|
||||
) {
|
||||
val panDisplay = remember(pan) {
|
||||
formatPan(pan)
|
||||
}
|
||||
|
||||
val expiryDisplay = remember(expiry) {
|
||||
formatExpiry(expiry)
|
||||
}
|
||||
val cardScheme = detectCardScheme(pan)
|
||||
val confirmEnabled = pan.length >= 13 && expiry.length == 4
|
||||
|
||||
val expiryFocusRequester = remember { FocusRequester() }
|
||||
|
||||
LaunchedEffect(pan) {
|
||||
if (pan.length == PAN_RAW_MAX) expiryFocusRequester.requestFocus()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = { AppBar(title = "Manual Entry", icon = Icons.AutoMirrored.Rounded.ArrowBack, onIconClick = onBackClick) },
|
||||
) { innerPadding ->
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding)
|
||||
.padding(horizontal = 20.dp, vertical = 16.dp),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp)
|
||||
) {
|
||||
|
||||
Surface(
|
||||
shape = MaterialTheme.shapes.medium,
|
||||
tonalElevation = 1.dp,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Column(modifier = Modifier.padding(16.dp)) {
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = Modifier.padding(bottom = 16.dp)
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Outlined.CreditCard,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.primary,
|
||||
modifier = Modifier.size(20.dp)
|
||||
)
|
||||
Spacer(Modifier.width(8.dp))
|
||||
Text(
|
||||
"Card details",
|
||||
style = MaterialTheme.typography.labelLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
if (cardScheme != null) {
|
||||
Spacer(Modifier.weight(1f))
|
||||
SchemeBadge(cardScheme)
|
||||
}
|
||||
}
|
||||
|
||||
OutlinedTextField(
|
||||
value = panDisplay,
|
||||
onValueChange = {
|
||||
onPanChange(it.text)
|
||||
},
|
||||
label = { Text("Card number") },
|
||||
placeholder = { Text("0000 0000 0000 0000") },
|
||||
isError = panError != null,
|
||||
supportingText = {
|
||||
Text(panError ?: " ") // reserve space to avoid layout jump
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number,
|
||||
imeAction = ImeAction.Next
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onNext = { expiryFocusRequester.requestFocus() }
|
||||
),
|
||||
singleLine = true,
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
textStyle = MaterialTheme.typography.bodyLarge.copy(
|
||||
letterSpacing = 2.sp,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
)
|
||||
|
||||
Spacer(Modifier.height(4.dp))
|
||||
|
||||
OutlinedTextField(
|
||||
value = expiryDisplay,
|
||||
onValueChange = {
|
||||
onExpiryChange(it.text)
|
||||
},
|
||||
label = { Text("Expiry date") },
|
||||
placeholder = { Text("MM/YY") },
|
||||
isError = expiryError != null,
|
||||
supportingText = {
|
||||
Text(expiryError ?: " ")
|
||||
},
|
||||
keyboardOptions = KeyboardOptions(
|
||||
keyboardType = KeyboardType.Number,
|
||||
imeAction = ImeAction.Done
|
||||
),
|
||||
keyboardActions = KeyboardActions(
|
||||
onDone = { onConfirmClick() }
|
||||
),
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.width(160.dp)
|
||||
.focusRequester(expiryFocusRequester),
|
||||
textStyle = MaterialTheme.typography.bodyLarge.copy(
|
||||
letterSpacing = 2.sp,
|
||||
fontFamily = FontFamily.Monospace
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(visible = pan.length >= 4) {
|
||||
Surface(
|
||||
shape = MaterialTheme.shapes.small,
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Text(
|
||||
text = "**** **** **** ${pan.takeLast(4)}",
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
fontFamily = FontFamily.Monospace,
|
||||
letterSpacing = 1.5.sp
|
||||
)
|
||||
if (expiry.length == 4) {
|
||||
Text(
|
||||
text = "Exp ${expiryDisplay.text}",
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Spacer(Modifier.weight(1f))
|
||||
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
){
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp)
|
||||
) {
|
||||
Button(
|
||||
onClick = onBackClick,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(56.dp),
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.White,
|
||||
contentColor = Color.LegacyRed
|
||||
)
|
||||
) {
|
||||
Text("Cancel")
|
||||
}
|
||||
|
||||
Button(
|
||||
onClick = onConfirmClick,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.height(56.dp),
|
||||
|
||||
shape = RoundedCornerShape(8.dp),
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = Color.LegacyRed,
|
||||
contentColor = Color.White,
|
||||
disabledContainerColor = Color.LegacyRed.copy(alpha = 0.5f),
|
||||
disabledContentColor = Color.White
|
||||
)
|
||||
) {
|
||||
Text(
|
||||
text = "Confirm",
|
||||
fontSize = 14.sp,
|
||||
fontWeight = FontWeight.Medium
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Composable
|
||||
private fun SchemeBadge(scheme: String) {
|
||||
Surface(
|
||||
color = MaterialTheme.colorScheme.secondaryContainer,
|
||||
shape = MaterialTheme.shapes.small
|
||||
) {
|
||||
Text(
|
||||
text = scheme,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun formatPan(raw: String): TextFieldValue {
|
||||
val formatted = raw.chunked(4).joinToString(" ")
|
||||
|
||||
val cursorPos = buildString {
|
||||
raw.forEachIndexed { index, c ->
|
||||
append(c)
|
||||
if ((index + 1) % 4 == 0 && index != raw.lastIndex) {
|
||||
append(" ")
|
||||
}
|
||||
}
|
||||
}.length
|
||||
|
||||
return TextFieldValue(
|
||||
text = formatted,
|
||||
selection = TextRange(cursorPos)
|
||||
)
|
||||
}
|
||||
|
||||
private fun formatExpiry(raw: String): TextFieldValue {
|
||||
val formatted = when {
|
||||
raw.length > 2 -> "${raw.take(2)}/${raw.drop(2)}"
|
||||
else -> raw
|
||||
}
|
||||
|
||||
val cursorPos = when {
|
||||
raw.length <= 2 -> raw.length
|
||||
else -> raw.length + 1 // account for '/'
|
||||
}
|
||||
|
||||
return TextFieldValue(
|
||||
text = formatted,
|
||||
selection = TextRange(cursorPos)
|
||||
)
|
||||
}
|
||||
private fun detectCardScheme(pan: String): String? = when {
|
||||
pan.startsWith("4") -> "Visa"
|
||||
pan.length >= 2 && (pan.take(2).toInt() in 51..55 || pan.take(4).toIntOrNull() in 2221..2720) -> "Mastercard"
|
||||
pan.length >= 2 && pan.take(2) in listOf("34", "37") -> "Amex"
|
||||
pan.startsWith("6") -> "UnionPay"
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun luhnCheck(pan: String): Boolean {
|
||||
var sum = 0; var alt = false
|
||||
for (i in pan.length - 1 downTo 0) {
|
||||
var n = pan[i].digitToIntOrNull() ?: return false
|
||||
if (alt) { n *= 2; if (n > 9) n -= 9 }
|
||||
sum += n; alt = !alt
|
||||
}
|
||||
return sum % 10 == 0
|
||||
}
|
||||
|
||||
@P2Preview
|
||||
@P3Preview
|
||||
@Composable
|
||||
private fun ManualCardEntryScreenPreview() {
|
||||
MaterialTheme {
|
||||
ManualCardEntryScreen(
|
||||
pan = "4111111111111111",
|
||||
expiry = "1228",
|
||||
panError = null,
|
||||
expiryError = null,
|
||||
onPanChange = {},
|
||||
onExpiryChange = {},
|
||||
onBackClick = {},
|
||||
onCancelClick = {},
|
||||
onConfirmClick = {}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,7 +23,6 @@ import com.mob.utsmyanmar.ui.device_info.DeviceInfoViewModel
|
||||
import com.mob.utsmyanmar.ui.disable.DisableScreen
|
||||
import com.mob.utsmyanmar.ui.functions.FunctionsScreen
|
||||
import com.mob.utsmyanmar.ui.input_amount.AmountRoute
|
||||
import com.mob.utsmyanmar.ui.manual_entry.InputManualCardRoute
|
||||
import com.mob.utsmyanmar.ui.notification.NotificationDetailScreen
|
||||
import com.mob.utsmyanmar.ui.notification.NotificationListScreen
|
||||
import com.mob.utsmyanmar.ui.notification.NotificationViewModel
|
||||
@ -35,7 +34,6 @@ import com.mob.utsmyanmar.ui.print_receipt.PrintReceiptScreen
|
||||
import com.mob.utsmyanmar.ui.processing_card.ProcessingCardRoute
|
||||
import com.mob.utsmyanmar.ui.processing_card.ProcessingCardViewModel
|
||||
import com.mob.utsmyanmar.ui.refund_rrn.InputRrnRoute
|
||||
import com.mob.utsmyanmar.ui.refund_rrn.RRNViewModel
|
||||
import com.mob.utsmyanmar.ui.sale_void.TranDetailPage
|
||||
import com.mob.utsmyanmar.ui.sale_void.VoidTraceScreen
|
||||
import com.mob.utsmyanmar.ui.sale_void.VoidViewModel
|
||||
@ -54,9 +52,7 @@ import com.mob.utsmyanmar.viewmodel.CardReaderViewModel
|
||||
import com.mob.utsmyanmar.viewmodel.EmvTransactionProcessViewModel
|
||||
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||
import com.mob.utsmyanmar.viewmodel.TransProcessViewModel
|
||||
import com.utsmyanmar.paylibs.model.TradeData
|
||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||
import sunmi.sunmiui.utils.LogUtil
|
||||
|
||||
@SuppressLint("ContextCastToActivity")
|
||||
@Composable
|
||||
@ -160,24 +156,7 @@ fun AppNavGraph(
|
||||
},
|
||||
onNavigateAction = { action ->
|
||||
when (action) {
|
||||
"Void" -> {
|
||||
sharedViewModel.transactionsType.value = TransactionsType.VOID
|
||||
navController.navigate(Routes.Password.createRoute(Routes.VoidTrace.route, PasswordType.SYSTEM)) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
"Pre-Auth Void" -> navController.navigate(Routes.Password.createRoute(Routes.Amount.createRoute(action), PasswordType.SYSTEM)) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
"Pre-Auth Complete Void" -> {
|
||||
sharedViewModel.transactionsType.value = TransactionsType.PRE_AUTH_COMPLETE_VOID
|
||||
navController.navigate(Routes.Password.createRoute(Routes.VoidTrace.route, PasswordType.SYSTEM)) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
}
|
||||
"Refund" -> navController.navigate(Routes.Password.createRoute(Routes.Amount.createRoute(action), PasswordType.SYSTEM)) {
|
||||
launchSingleTop = true
|
||||
}
|
||||
"Void" -> navController.navigate(Routes.VoidTrace.route) { launchSingleTop = true }
|
||||
else -> navController.navigate(Routes.Amount.createRoute(action)) { launchSingleTop = true }
|
||||
}
|
||||
},
|
||||
@ -227,10 +206,9 @@ fun AppNavGraph(
|
||||
|
||||
composable(Routes.VoidTrace.route) {
|
||||
val voidViewModel: VoidViewModel = hiltViewModel()
|
||||
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
|
||||
|
||||
VoidTraceScreen(
|
||||
voidViewModel = voidViewModel,
|
||||
sharedViewModel = sharedViewModel,
|
||||
onNavigateTranDetail = { trace ->
|
||||
navController.navigate(Routes.VoidTranDetail.createRoute(trace)) {
|
||||
launchSingleTop = true
|
||||
@ -278,18 +256,8 @@ fun AppNavGraph(
|
||||
trace = trace,
|
||||
onBack = { navController.popBackStack() },
|
||||
onProceedVoid = { payDetail ->
|
||||
if(sharedViewModel.transactionsType.value == TransactionsType.VOID) {
|
||||
sharedViewModel.transactionsType.value = TransactionsType.VOID
|
||||
transProcessViewModel.setTransType(TransactionsType.VOID)
|
||||
payDetail.transType = TransactionsType.VOID.name
|
||||
payDetail.transactionType = TransactionsType.VOID.value
|
||||
} else {
|
||||
transProcessViewModel.setTransType(TransactionsType.PRE_AUTH_COMPLETE_VOID)
|
||||
payDetail.transType = TransactionsType.PRE_AUTH_COMPLETE_VOID.name
|
||||
payDetail.transactionType = TransactionsType.PRE_AUTH_COMPLETE_VOID.value
|
||||
}
|
||||
val tradeData = TradeData()
|
||||
tradeData.payDetail = payDetail
|
||||
transProcessViewModel.setTradeData(tradeData)
|
||||
sharedViewModel.payDetail.value = payDetail
|
||||
navController.navigate(Routes.Processing.route) {
|
||||
popUpTo(Routes.VoidTranDetail.route) {
|
||||
@ -390,14 +358,7 @@ fun AppNavGraph(
|
||||
CardWaitingScreen(
|
||||
viewModel = cardWaitingViewModel,
|
||||
amount = formatAmountForDisplay(sharedViewModel.amount.value),
|
||||
onManualEntry = {
|
||||
navController.navigate(Routes.ManualEntry.route) {
|
||||
popUpTo(Routes.CardWaiting.route) {
|
||||
inclusive = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
onManualEntry = {},
|
||||
onProcessingCard = {
|
||||
navController.navigate(Routes.ProcessingCard.route) {
|
||||
popUpTo(Routes.CardWaiting.route) {
|
||||
@ -493,11 +454,8 @@ fun AppNavGraph(
|
||||
|
||||
composable(Routes.InputRrn.route) {
|
||||
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
|
||||
val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity)
|
||||
val rrnViewModel: RRNViewModel = hiltViewModel(activity)
|
||||
|
||||
InputRrnRoute(
|
||||
rrnViewModel = rrnViewModel,
|
||||
transProcessViewModel = transProcessViewModel,
|
||||
sharedViewModel = sharedViewModel,
|
||||
onBack = { navController.popBackStack() },
|
||||
onNavigateProcessing = {
|
||||
@ -511,27 +469,6 @@ fun AppNavGraph(
|
||||
)
|
||||
}
|
||||
|
||||
composable(Routes.ManualEntry.route) {
|
||||
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
|
||||
val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity)
|
||||
val pinPadViewModel: PinPadViewModel = hiltViewModel(activity)
|
||||
InputManualCardRoute(
|
||||
transProcessViewModel = transProcessViewModel,
|
||||
sharedViewModel = sharedViewModel,
|
||||
pinPadViewModel = pinPadViewModel,
|
||||
onBack = { navController.popBackStack() },
|
||||
onNavigatePinPad = {
|
||||
pinPadViewModel.resetSessionState()
|
||||
navController.navigate(Routes.PinPad.route) {
|
||||
popUpTo(Routes.ProcessingCard.route) {
|
||||
inclusive = true
|
||||
}
|
||||
launchSingleTop = true
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
composable(Routes.Processing.route) {
|
||||
val sharedViewModel: SharedViewModel = hiltViewModel(activity)
|
||||
val transProcessViewModel: TransProcessViewModel = hiltViewModel(activity)
|
||||
|
||||
@ -25,9 +25,6 @@ sealed class Routes(val route: String) {
|
||||
data object PinPad : Routes("pin_pad")
|
||||
data object InputRrn : Routes("input_rrn")
|
||||
data object Processing : Routes("processing")
|
||||
data object ManualEntry : Routes("manual_entry")
|
||||
|
||||
|
||||
data object TransactionResult : Routes("transaction_result")
|
||||
data object PrintReceipt : Routes("print_receipt")
|
||||
data object Version : Routes("version")
|
||||
|
||||
@ -8,7 +8,6 @@ import android.view.View
|
||||
import android.view.ViewTreeObserver
|
||||
import android.widget.TextView
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.kizzy.cmhl.utils.ByteUtils
|
||||
import com.mob.utsmyanmar.config.Constants
|
||||
import com.mob.utsmyanmar.config.SunmiPayManager
|
||||
import com.mob.utsmyanmar.model.PinPadStatus
|
||||
@ -406,21 +405,10 @@ class PinPadViewModel @Inject constructor(
|
||||
|
||||
ON_CONFIRM_CLICK -> {
|
||||
LogUtil.d(TAG, "ON CLICK CONFIRM")
|
||||
|
||||
if (
|
||||
transType.value == TransactionsType.PRE_AUTH_COMPLETE ||
|
||||
transType.value == TransactionsType.PRE_AUTH_VOID ||
|
||||
transType.value == TransactionsType.REFUND
|
||||
) {
|
||||
isTerminalStateReached = true
|
||||
_pinStatus.value = PinPadStatus.ON_NEXT_SCREEN
|
||||
} else {
|
||||
isTerminalStateReached = true
|
||||
_pinStatus.value = PinPadStatus.ON_CONFIRM
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ON_CANCEL_CLICK -> {
|
||||
LogUtil.d(TAG, "ON CLICK CANCEL")
|
||||
if (!isTerminalStateReached) {
|
||||
@ -500,11 +488,18 @@ class PinPadViewModel @Inject constructor(
|
||||
payDetail?.pinCipher = ""
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
transType.value == TransactionsType.PRE_AUTH_COMPLETE ||
|
||||
transType.value == TransactionsType.PRE_AUTH_VOID ||
|
||||
transType.value == TransactionsType.REFUND
|
||||
) {
|
||||
isTerminalStateReached = true
|
||||
_pinStatus.value = PinPadStatus.ON_NEXT_SCREEN
|
||||
} else {
|
||||
handler.obtainMessage(
|
||||
ON_CONFIRM_CLICK
|
||||
).sendToTarget()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCancel() {
|
||||
@ -555,13 +550,10 @@ class PinPadViewModel @Inject constructor(
|
||||
|
||||
private fun getPanBytes(pan: String): ByteArray {
|
||||
|
||||
LogUtil.d(TAG,"pan : $pan")
|
||||
if (pan.length < 13) {
|
||||
return ByteArray(0)
|
||||
}
|
||||
LogUtil.d(TAG,"pan bytes : ${ByteUtils.byteArrayToHexString(pan
|
||||
.substring(pan.length - 13, pan.length - 1)
|
||||
.toByteArray(StandardCharsets.US_ASCII))}")
|
||||
|
||||
return pan
|
||||
.substring(pan.length - 13, pan.length - 1)
|
||||
.toByteArray(StandardCharsets.US_ASCII)
|
||||
|
||||
@ -200,7 +200,6 @@ fun ReceiptPreview(
|
||||
ReceiptDivider()
|
||||
ReceiptRow("Merchant", state.payDetail?.merchantName.toString() )
|
||||
ReceiptRow("Terminal ID", state.payDetail?.terminalNo.toString() )
|
||||
ReceiptRow("Trace No", state.payDetail?.voucherNo.toString() )
|
||||
ReceiptRow("Transaction", state.payDetail?.transType.toString())
|
||||
ReceiptRow("Amount", POSUtil.getInstance().getDecimalAmountSeparatorFormat(state.payDetail?.amount?:0))
|
||||
ReceiptRow("Card Type", state.payDetail?.accountType.toString())
|
||||
|
||||
@ -6,22 +6,14 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.mob.utsmyanmar.ui.components.NumericEntryScreen
|
||||
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||
import com.mob.utsmyanmar.viewmodel.TransProcessViewModel
|
||||
import com.utsmyanmar.paylibs.model.PayDetail
|
||||
import com.utsmyanmar.paylibs.model.TradeData
|
||||
import com.utsmyanmar.paylibs.utils.POSUtil
|
||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||
import sunmi.sunmiui.utils.LogUtil
|
||||
|
||||
private const val RRN_MAX_LENGTH = 12
|
||||
|
||||
@Composable
|
||||
fun InputRrnRoute(
|
||||
transProcessViewModel: TransProcessViewModel,
|
||||
rrnViewModel: RRNViewModel,
|
||||
sharedViewModel: SharedViewModel,
|
||||
onBack: () -> Unit,
|
||||
onNavigateProcessing: () -> Unit
|
||||
@ -36,75 +28,6 @@ fun InputRrnRoute(
|
||||
errorMessage = null
|
||||
}
|
||||
|
||||
val payDetailState by rrnViewModel.payDetailState.collectAsStateWithLifecycle()
|
||||
|
||||
|
||||
fun processPreAuthComp(payDetail: PayDetail) {
|
||||
val newPay = transProcessViewModel.payDetail
|
||||
|
||||
|
||||
|
||||
newPay?.setReferNo(payDetail.referNo)
|
||||
newPay?.setApprovalCode(payDetail.getApprovalCode())
|
||||
newPay?.setTradeTime(payDetail.getTradeTime())
|
||||
newPay?.setTradeDate(payDetail.getTradeDate())
|
||||
|
||||
|
||||
val tradeData = TradeData()
|
||||
tradeData.payDetail = newPay
|
||||
transProcessViewModel.setOldTransPayDetail(payDetail)
|
||||
transProcessViewModel.setTradeData(tradeData)
|
||||
|
||||
rrnViewModel.resetState()
|
||||
onNavigateProcessing()
|
||||
|
||||
}
|
||||
|
||||
fun processPreAuthVoid(payDetail: PayDetail) {
|
||||
val newPay = transProcessViewModel.payDetail
|
||||
|
||||
newPay?.setReferNo(payDetail.referNo)
|
||||
|
||||
|
||||
val tradeData = TradeData()
|
||||
tradeData.payDetail = newPay
|
||||
transProcessViewModel.setOldTransPayDetail(payDetail)
|
||||
transProcessViewModel.setTradeData(tradeData)
|
||||
|
||||
rrnViewModel.resetState()
|
||||
onNavigateProcessing()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LaunchedEffect(payDetailState) {
|
||||
LogUtil.d("RRN","paydetail state: $payDetailState")
|
||||
when (val state = payDetailState) {
|
||||
|
||||
is RRNViewModel.PayDetailState.Success -> {
|
||||
|
||||
|
||||
sharedViewModel.payDetail.value = state.data
|
||||
sharedViewModel.rrNNo.value = state.data.referNo
|
||||
|
||||
if(sharedViewModel.transactionsType.value == TransactionsType.PRE_AUTH_COMPLETE) {
|
||||
processPreAuthComp(state.data)
|
||||
} else if(sharedViewModel.transactionsType.value == TransactionsType.PRE_AUTH_VOID) {
|
||||
processPreAuthVoid(state.data)
|
||||
}
|
||||
|
||||
}
|
||||
is RRNViewModel.PayDetailState.Error -> {
|
||||
errorMessage = state.message
|
||||
rrnViewModel.resetState()
|
||||
// show dialog
|
||||
// navigate to home
|
||||
}
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
NumericEntryScreen(
|
||||
title = "Input RRN",
|
||||
prompt = "Enter RRN",
|
||||
@ -115,32 +38,17 @@ fun InputRrnRoute(
|
||||
onCancelClick = onBack,
|
||||
onConfirmClick = {
|
||||
val trimmedRrn = rrn.trim()
|
||||
|
||||
if (POSUtil.getInstance().checkNumberField(trimmedRrn)) {
|
||||
errorMessage = "Invalid RRN"
|
||||
return@NumericEntryScreen
|
||||
}
|
||||
|
||||
sharedViewModel.rrNNo.value = trimmedRrn
|
||||
|
||||
|
||||
if(sharedViewModel.transactionsType.value == TransactionsType.REFUND ) {
|
||||
val newPay = transProcessViewModel.payDetail
|
||||
|
||||
newPay?.setReferNo(trimmedRrn)
|
||||
val tradeData = TradeData()
|
||||
tradeData.payDetail = newPay
|
||||
transProcessViewModel.setTradeData(tradeData)
|
||||
rrnViewModel.resetState()
|
||||
onNavigateProcessing()
|
||||
} else{
|
||||
rrnViewModel.searchPayDetail(
|
||||
trimmedRrn,
|
||||
sharedViewModel.payDetail.value?.cardNo?:""
|
||||
)
|
||||
sharedViewModel.payDetail.value?.let { payDetail ->
|
||||
payDetail.referNo = trimmedRrn
|
||||
sharedViewModel.payDetail.value = payDetail
|
||||
}
|
||||
|
||||
|
||||
|
||||
onNavigateProcessing()
|
||||
},
|
||||
onKeyClick = { value ->
|
||||
rrn = appendRrnValue(rrn, value)
|
||||
|
||||
@ -1,56 +0,0 @@
|
||||
package com.mob.utsmyanmar.ui.refund_rrn
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.asFlow
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.utsmyanmar.baselib.repo.Repository
|
||||
import com.utsmyanmar.paylibs.model.PayDetail
|
||||
import com.utsmyanmar.paylibs.system.SingleLiveEvent
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
|
||||
@HiltViewModel
|
||||
class RRNViewModel @Inject constructor(
|
||||
private val repository: Repository
|
||||
) : ViewModel() {
|
||||
|
||||
sealed class PayDetailState {
|
||||
object Idle : PayDetailState()
|
||||
object Loading : PayDetailState()
|
||||
data class Success(val data: PayDetail) : PayDetailState()
|
||||
data class Error(val message: String) : PayDetailState()
|
||||
}
|
||||
|
||||
private val _payDetailState = MutableStateFlow<PayDetailState>(PayDetailState.Idle)
|
||||
val payDetailState: StateFlow<PayDetailState> = _payDetailState
|
||||
|
||||
fun searchPayDetail(refNo: String, cardNo: String) {
|
||||
_payDetailState.value = PayDetailState.Loading
|
||||
viewModelScope.launch {
|
||||
try {
|
||||
repository.searchPayDetail(cardNo, refNo)
|
||||
.asFlow()
|
||||
.filterNotNull()
|
||||
.first()
|
||||
.let { result ->
|
||||
_payDetailState.value = PayDetailState.Success(result)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
_payDetailState.value = PayDetailState.Error(e.message ?: "Search failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resetState() {
|
||||
_payDetailState.value = PayDetailState.Idle
|
||||
}
|
||||
|
||||
}
|
||||
@ -40,14 +40,11 @@ import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import com.mob.utsmyanmar.ui.components.appbar.AppBar
|
||||
import com.mob.utsmyanmar.ui.theme.Color
|
||||
import com.mob.utsmyanmar.viewmodel.SharedViewModel
|
||||
import com.utsmyanmar.paylibs.model.PayDetail
|
||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||
import sunmi.sunmiui.utils.LogUtil
|
||||
|
||||
@Composable
|
||||
fun VoidTraceScreen(
|
||||
sharedViewModel: SharedViewModel,
|
||||
voidViewModel: VoidViewModel,
|
||||
onNavigateTranDetail: (String) -> Unit,
|
||||
onBack: () -> Unit = {}
|
||||
@ -60,18 +57,12 @@ fun VoidTraceScreen(
|
||||
val recentTransactions by voidViewModel.getLastThreeTransactions().observeAsState(emptyList())
|
||||
|
||||
val transactionSource: LiveData<PayDetail?> = remember(searchedTrace) {
|
||||
val transType = if(sharedViewModel.transactionsType.value == TransactionsType.VOID) {
|
||||
TransactionsType.SALE.value
|
||||
} else {
|
||||
TransactionsType.PRE_AUTH_COMPLETE.value;
|
||||
}
|
||||
LogUtil.d("void screen","transaction type : $transType and trace number : $searchedTrace")
|
||||
if (searchedTrace.isBlank()) {
|
||||
MutableLiveData<PayDetail?>(null)
|
||||
} else {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
voidViewModel.getVoidTrans(
|
||||
transType,
|
||||
TransactionsType.SALE.value,
|
||||
searchedTrace
|
||||
) as LiveData<PayDetail?>
|
||||
}
|
||||
|
||||
@ -1,9 +1,5 @@
|
||||
package com.mob.utsmyanmar.ui.sending_to_host
|
||||
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
@ -17,14 +13,9 @@ import com.mob.utsmyanmar.viewmodel.ProcessingTransaction
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Modifier
|
||||
import com.mob.utsmyanmar.model.TransactionStatus
|
||||
import com.mob.utsmyanmar.ui.settlement.SettlementViewModel
|
||||
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
|
||||
private const val MOCK_HOST_DELAY_MS = 2000L
|
||||
|
||||
@ -43,28 +34,17 @@ fun ProcessingRoute(
|
||||
|
||||
val settlementStatus by settlementViewModel.uiState.collectAsStateWithLifecycle()
|
||||
|
||||
var showReversalDialog by rememberSaveable { mutableStateOf(false) }
|
||||
var reversalMessage by rememberSaveable { mutableStateOf("") }
|
||||
|
||||
if(sharedViewModel.transactionsType.value == TransactionsType.SETTLEMENT) {
|
||||
LaunchedEffect(Unit) {
|
||||
settlementViewModel.startSettlementProcess()
|
||||
}
|
||||
|
||||
LaunchedEffect(settlementStatus.status) {
|
||||
when(settlementStatus.status) {
|
||||
TransactionStatus.ON_ERROR,
|
||||
TransactionStatus.ON_SUCCESS -> {
|
||||
sharedViewModel.payDetail.value = settlementViewModel.getPayDetail()
|
||||
onNavigateTransactionResult()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LaunchedEffect(Unit) {
|
||||
transProcessViewModel.resetTransactionStatus()
|
||||
transProcessViewModel.startOnlineProcess()
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(transStatus) {
|
||||
when(transStatus) {
|
||||
@ -77,20 +57,18 @@ fun ProcessingRoute(
|
||||
sharedViewModel.payDetail.value = transProcessViewModel.payDetailResult.value
|
||||
onNavigateTransactionResult()
|
||||
}
|
||||
TransResultStatus.REVERSAL_SUCCESS ,
|
||||
TransResultStatus.REVERSAL_FAIL -> {
|
||||
delay(2500)
|
||||
onNavigateMain()
|
||||
}
|
||||
TransResultStatus.REVERSAL_SUCCESS -> onNavigateMain()
|
||||
TransResultStatus.REVERSAL_FAIL -> onNavigateMain()
|
||||
else -> {}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
LaunchedEffect(settlementStatus.status) {
|
||||
when(settlementStatus.status) {
|
||||
TransactionStatus.ON_SUCCESS -> onNavigateTransactionResult()
|
||||
else -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -9,13 +9,8 @@ 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.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Check
|
||||
import androidx.compose.material.icons.rounded.Close
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
@ -25,12 +20,8 @@ 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.input_amount.InputAmount
|
||||
import com.mob.utsmyanmar.ui.preview.P2Preview
|
||||
import com.mob.utsmyanmar.ui.preview.P3Preview
|
||||
import com.mob.utsmyanmar.ui.processing_card.ProcessingCardState
|
||||
import com.mob.utsmyanmar.ui.theme.Black
|
||||
import com.mob.utsmyanmar.ui.theme.Color
|
||||
import com.mob.utsmyanmar.ui.theme.Primary
|
||||
import com.mob.utsmyanmar.ui.theme.White
|
||||
|
||||
@ -62,28 +53,7 @@ fun ProcessingScreen(state: ProcessingState) {
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
when (state.title) {
|
||||
"Reversal Failure" -> {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Close,
|
||||
contentDescription = "Failed",
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(64.dp)
|
||||
)
|
||||
}
|
||||
"Reversal Success" -> {
|
||||
Icon(
|
||||
imageVector = Icons.Rounded.Check,
|
||||
contentDescription = "Success",
|
||||
tint = Color.White,
|
||||
modifier = Modifier.size(64.dp)
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
CircularProgressIndicator(color = White)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Spacer(modifier = Modifier.height(20.dp))
|
||||
|
||||
@ -116,10 +86,3 @@ fun ProcessingScreen(state: ProcessingState) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@P2Preview
|
||||
@P3Preview
|
||||
@Composable
|
||||
fun PreviewSendingToHostScreen(){
|
||||
ProcessingScreen(ProcessingState("Processing"))
|
||||
}
|
||||
|
||||
@ -205,7 +205,6 @@ class SettlementViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
fun getPayDetail() = payDetail
|
||||
fun setSettlementType(type: SettlementType) {
|
||||
_uiState.update {
|
||||
it.copy(settlementType = type)
|
||||
@ -233,7 +232,6 @@ class SettlementViewModel @Inject constructor(
|
||||
deleteTrans.clear()
|
||||
}
|
||||
|
||||
|
||||
fun startSettlementProcess() {
|
||||
_uiState.update {
|
||||
it.copy(isLoading = true)
|
||||
@ -341,11 +339,6 @@ class SettlementViewModel @Inject constructor(
|
||||
currentPayDetail.settleData = settlementData
|
||||
currentPayDetail.amount = totalAmount
|
||||
} else {
|
||||
|
||||
LogUtil.d(TAG,"sale count :$totalSaleCount")
|
||||
LogUtil.d(TAG,"sale amount :$totalSaleAmount")
|
||||
LogUtil.d(TAG,"refund count :$totalRefundCount")
|
||||
LogUtil.d(TAG,"refund amount :$totalRefundAmount")
|
||||
currentPayDetail.settleData =
|
||||
totalSaleCount +
|
||||
totalSaleAmount +
|
||||
@ -357,7 +350,6 @@ class SettlementViewModel @Inject constructor(
|
||||
totalERefundAmount
|
||||
}
|
||||
|
||||
payDetail = currentPayDetail
|
||||
tradeData.payDetail = currentPayDetail
|
||||
tradeData.field60 = field60
|
||||
|
||||
|
||||
@ -66,7 +66,6 @@ class TmsSetupViewModel @Inject constructor(
|
||||
init {
|
||||
viewModelScope.launch {
|
||||
waitForHardware()
|
||||
TMSUtil.getInstance().generateFinalVersion()
|
||||
downloadConfigs()
|
||||
}
|
||||
}
|
||||
@ -76,8 +75,6 @@ class TmsSetupViewModel @Inject constructor(
|
||||
it.copy(isLoading = true, isError = false, statusText = "Connecting to TMS server...")
|
||||
}
|
||||
|
||||
|
||||
|
||||
val disposable = repository.getParams(buildRequest())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
@ -134,7 +131,6 @@ class TmsSetupViewModel @Inject constructor(
|
||||
delay(500.milliseconds)
|
||||
elapsed += 500
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun onConfigApplied() {
|
||||
|
||||
@ -13,40 +13,14 @@ data class MockCardData(
|
||||
|
||||
object MockData {
|
||||
|
||||
// private val mockCardData: MockCardData = MockCardData(
|
||||
// cardNo="9503712156912514",
|
||||
// expDate="2912",
|
||||
// cardScheme="MPU",
|
||||
// cardHolderName="Htin Kyaw Win",
|
||||
// iccData="9503712156912514=29121010000000000000"
|
||||
// )
|
||||
|
||||
// production card
|
||||
// private val mockCardData: MockCardData = MockCardData(
|
||||
// cardNo="9503220100322798",
|
||||
// expDate="2912",
|
||||
// cardScheme="MPU",
|
||||
// cardHolderName="Htin Kyaw Win",
|
||||
// iccData="9503220100322798=300110100000942"
|
||||
// )
|
||||
|
||||
//debit
|
||||
private val mockCardData: MockCardData = MockCardData(
|
||||
cardNo="9503032443884321",
|
||||
expDate="3102",
|
||||
cardNo="9503712156912514",
|
||||
expDate="2912",
|
||||
cardScheme="MPU",
|
||||
cardHolderName="Htin Kyaw Win",
|
||||
iccData="9503032443884321=310220100"
|
||||
iccData="9503712156912514=29121010000000000000"
|
||||
)
|
||||
|
||||
// private val mockCardData: MockCardData = MockCardData(
|
||||
// cardNo="6244310039574344",
|
||||
// expDate="3011",
|
||||
// cardScheme="MPU",
|
||||
// cardHolderName="Htin Kyaw Win",
|
||||
// iccData="6244310039574344=30112011558125900000"
|
||||
// )
|
||||
|
||||
fun generateMPUCard(): CardDataX = CardDataX().apply {
|
||||
pan = mockCardData.cardNo
|
||||
exp = mockCardData.expDate
|
||||
|
||||
@ -267,7 +267,6 @@ class TMSSetupsImpl : TMSSetups {
|
||||
} catch (e: Exception) {
|
||||
"?"
|
||||
}
|
||||
SystemParamsOperation.getInstance().setFinalVersion("PHV$phv-RV$rv-SV$sv")
|
||||
return "PHV$phv-RV$rv-SV$sv"
|
||||
}
|
||||
private fun parseBoolean(data: String): Boolean =
|
||||
|
||||
@ -3,6 +3,7 @@ package com.mob.utsmyanmar.viewmodel
|
||||
import android.text.TextUtils
|
||||
import androidx.lifecycle.ViewModel
|
||||
import com.mob.utsmyanmar.model.TransResultStatus
|
||||
import com.mob.utsmyanmar.ui.processing_card.ProcessingCardState
|
||||
import com.mob.utsmyanmar.ui.sending_to_host.ProcessingState
|
||||
import com.utsmyanmar.baselib.repo.Repository
|
||||
import com.utsmyanmar.paylibs.model.PayDetail
|
||||
@ -108,12 +109,6 @@ class TransProcessViewModel @Inject constructor(
|
||||
fun setOldTransPayDetail(payDetail: PayDetail) {
|
||||
oldTransPayDetail = payDetail
|
||||
}
|
||||
|
||||
fun setNewPayDetail(payDetail: PayDetail) {
|
||||
this.payDetail = payDetail
|
||||
tradeData = TradeData()
|
||||
tradeData.payDetail = payDetail
|
||||
}
|
||||
private val _state = MutableStateFlow(ProcessingState())
|
||||
val state = _state.asStateFlow()
|
||||
|
||||
@ -268,36 +263,9 @@ class TransProcessViewModel @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
override fun processPreVoidDb(payResult: PayDetail) {
|
||||
oldTransPayDetail?.apply {
|
||||
isCanceled = true
|
||||
repository.updatePayDetail(oldTransPayDetail!!)
|
||||
}
|
||||
|
||||
|
||||
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
|
||||
}
|
||||
override fun processPreCompDb(payResult: PayDetail) {
|
||||
if (oldTransPayDetail?.getAmount() == payResult.getAmount()) {
|
||||
oldTransPayDetail?.apply {
|
||||
isCanceled = true
|
||||
repository.updatePayDetail(this)
|
||||
}
|
||||
} else {
|
||||
oldTransPayDetail?.apply {
|
||||
isCanceled = false
|
||||
repository.updatePayDetail(this)
|
||||
}
|
||||
}
|
||||
repository.insertPayDetail(updateCurrentDateAndTime(payResult))
|
||||
}
|
||||
override fun processPreCompVoidDb(payResult: PayDetail) {
|
||||
payDetail?.apply {
|
||||
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
|
||||
@ -317,7 +285,7 @@ class TransProcessViewModel @Inject constructor(
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_SUCCESS
|
||||
_state.value = _state.value.copy("Reversal Success")
|
||||
|
||||
payDetail?.let {
|
||||
repository.insertPayDetail(it)
|
||||
}
|
||||
@ -351,14 +319,12 @@ class TransProcessViewModel @Inject constructor(
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_FAIL
|
||||
_state.value = _state.value.copy("Reversal Failure")
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_FAIL
|
||||
_state.value = _state.value.copy("Reversal Failure")
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,7 +332,6 @@ class TransProcessViewModel @Inject constructor(
|
||||
|
||||
_transResultStatus.value =
|
||||
TransResultStatus.REVERSAL_FAIL
|
||||
_state.value = _state.value.copy("Reversal Failure")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -3,15 +3,10 @@ package com.utsmyanmar.baselib;
|
||||
import android.content.ContentValues;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import com.sunmi.pay.hardware.aidl.AidlConstants;
|
||||
import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
|
||||
import com.sunmi.pay.hardware.aidlv2.security.SecurityOptV2;
|
||||
import com.utsmyanmar.paylibs.Constant;
|
||||
import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil;
|
||||
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
|
||||
import com.utsmyanmar.paylibs.utils.secure.TriDes;
|
||||
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import sunmi.sunmiui.utils.LogUtil;
|
||||
|
||||
@ -28,9 +23,7 @@ public final class TerminalKeyUtil {
|
||||
|
||||
SecurityOptV2 mSecurityOptV2 = BaseApplication.getInstance().mSecurityOptV2;
|
||||
byte[] cvByte = ByteUtil.hexStr2Bytes("B7B520");
|
||||
// byte[] dataByte = ByteUtil.hexStr2Bytes("e121249099a677e8b7d4f6a9d49fe8d1".toUpperCase()); // mpu
|
||||
// byte[] dataByte = ByteUtil.hexStr2Bytes("05FFB893726A5F1E59692D24E72E36AC");
|
||||
byte[] dataByte = ByteUtil.hexStr2Bytes("DB7887664E3A06873342B753171896B1");
|
||||
byte[] dataByte = ByteUtil.hexStr2Bytes("05FFB893726A5F1E59692D24E72E36AC".toUpperCase());
|
||||
|
||||
byte[] makBytes = ByteUtil.hexStr2Bytes("250738083EC15BD3BA67D66B8A7AA13B");
|
||||
// byte[] makCvBytes = ByteUtil.hexStr2Bytes("204E449B97");
|
||||
@ -48,11 +41,10 @@ public final class TerminalKeyUtil {
|
||||
int result = 0;
|
||||
|
||||
SystemParamsOperation.getInstance().setTMKIndex("9");
|
||||
SystemParamsOperation.getInstance().setInjectOnce(false);
|
||||
if(!SystemParamsOperation.getInstance().isInjectOnce()) {
|
||||
try {
|
||||
// result = mSecurityOptV2.saveKeyDukpt(AidlConstantsV2.Security.KEY_TYPE_DUPKT_IPEK,IPEKByte,IPEKKCVByte,KSNByte,AidlConstantsV2.Security.KEY_ALG_TYPE_3DES,9);
|
||||
result = mSecurityOptV2.savePlaintextKey(AidlConstantsV2.Security.KEY_TYPE_TMK,dataByte,null,AidlConstantsV2.Security.KEY_ALG_TYPE_3DES,9);
|
||||
result = mSecurityOptV2.savePlaintextKey(AidlConstantsV2.Security.KEY_TYPE_TMK,dataByte,cvByte,AidlConstantsV2.Security.KEY_ALG_TYPE_3DES,9);
|
||||
LogUtil.d(ContentValues.TAG, "save TMK result:" + result);
|
||||
if (result != 0) {
|
||||
LogUtil.d(TAG, "save TMK fail");
|
||||
|
||||
@ -42,7 +42,7 @@ public class BatchUploadProcess {
|
||||
}
|
||||
|
||||
private BatchUploadProcess() {
|
||||
isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.CARDZONE)
|
||||
isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.BOTH_HEADER_TPDU,HostName.BPC)
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ public class BatchUploadProcess {
|
||||
public void startBatchUpload(BatchListener batchListener) {
|
||||
HostName hostName = HostName.BPC;
|
||||
LogUtil.d(TAG, "Starting Batch Upload");
|
||||
byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.CZ_BATCH_UPLOAD, MessageType.BATCH_UPLOAD);
|
||||
byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.BPC_BATCH_UPLOAD, MessageType.BATCH_UPLOAD);
|
||||
ISOSocket.getInstance().enqueue(sendBytes, sendBytes.length,false, new ISOCallback() {
|
||||
@Override
|
||||
public void onReceive(byte[] bytes, int length) {
|
||||
|
||||
@ -409,8 +409,7 @@ public class DecodePackage {
|
||||
if(hostName == HostName.BPC) {
|
||||
System.arraycopy(body, tmpLen, nextData, 0, datLen);
|
||||
} else {
|
||||
// System.arraycopy(body, tmpLen, nextData, 0, body.length-tmpLen);
|
||||
System.arraycopy(body, tmpLen, nextData, 0, datLen);
|
||||
System.arraycopy(body, tmpLen, nextData, 0, body.length-tmpLen);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
@ -280,7 +280,6 @@ public class EncodePackage {
|
||||
System.arraycopy(fieldBody.getBytes(StandardCharsets.ISO_8859_1), 0, body, index, fieldBody.length());
|
||||
index += fieldBody.length();
|
||||
} else {
|
||||
// MPU
|
||||
String fieldHead = msgField.getDataStr().substring(0,4);
|
||||
int bcdLen = (fieldHead.length() / 2) + (fieldHead.length() % 2);
|
||||
byte dat[] = new byte[bcdLen];
|
||||
|
||||
@ -106,9 +106,6 @@ public class ISOMsgX extends BaseISOMsgX{
|
||||
MTI = "0400";
|
||||
// MTI = "0420";
|
||||
break;
|
||||
case CZ_REVERSAL:
|
||||
MTI = "0420";
|
||||
break;
|
||||
case NETWORK_MANAGEMENT:
|
||||
MTI = "0800";
|
||||
break;
|
||||
@ -127,7 +124,6 @@ public class ISOMsgX extends BaseISOMsgX{
|
||||
|
||||
Map<String, MsgField> map = FieldUtils.fillEachFieldValue(rm, tradeData);
|
||||
|
||||
tradeData.payDetail.setMsgType(MTI);
|
||||
return packByte(map, MTI,hostName,isoMode);
|
||||
}
|
||||
|
||||
|
||||
@ -26,11 +26,14 @@ import java.security.KeyManagementException;
|
||||
import java.security.KeyStore;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.regex.Matcher;
|
||||
@ -64,6 +67,7 @@ import sunmi.sunmiui.utils.LogUtil;
|
||||
|
||||
public class ISOSocket {
|
||||
|
||||
private static final String TAG = ISOSocket.class.getSimpleName();
|
||||
private static final int DEFAULT_TIMEOUT = 30 * 1000;
|
||||
private String serverIP;
|
||||
private int serverPort;
|
||||
@ -148,7 +152,7 @@ public class ISOSocket {
|
||||
private SSLSocketFactory getSSLSocketFactory()
|
||||
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
InputStream caInput = context.getResources().openRawResource(R.raw.mob); // this cert file stored in \app\src\main\res\raw folder path
|
||||
InputStream caInput = context.getResources().openRawResource(R.raw.mpu_crt_2026); // this cert file stored in \app\src\main\res\raw folder path
|
||||
|
||||
Certificate ca = cf.generateCertificate(caInput);
|
||||
caInput.close();
|
||||
@ -175,7 +179,7 @@ public class ISOSocket {
|
||||
private OkHttpClient getClient()
|
||||
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException {
|
||||
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||
InputStream caInput = context.getResources().openRawResource(R.raw.mob); // this cert file stored in \app\src\main\res\raw folder path
|
||||
InputStream caInput = context.getResources().openRawResource(R.raw.mpu_crt_2026); // this cert file stored in \app\src\main\res\raw folder path
|
||||
|
||||
Certificate ca = cf.generateCertificate(caInput);
|
||||
caInput.close();
|
||||
@ -326,9 +330,16 @@ public class ISOSocket {
|
||||
}
|
||||
return port;
|
||||
}
|
||||
private String formatDate(Date d) { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(d); }
|
||||
|
||||
public void switchIp() {
|
||||
isSwitchIp = true;
|
||||
// serverIP = "posuat.myanmarorientalbank.com";
|
||||
// serverPort = 5033;
|
||||
// serverIP = "192.168.0.100";
|
||||
// serverPort = 5001;
|
||||
// serverIP = "103.84.101.82";
|
||||
// serverPort = 60147;
|
||||
serverIP = getSecondaryIp();
|
||||
serverPort = getSecondaryPort();
|
||||
}
|
||||
@ -349,6 +360,13 @@ public class ISOSocket {
|
||||
if (!isSwitchIp) {
|
||||
serverIP = getIp();
|
||||
serverPort = getPort();
|
||||
// serverIP = "192.168.0.100";
|
||||
// serverPort = 5001;
|
||||
// serverIP = "103.84.101.82";
|
||||
// serverPort = 60147;
|
||||
// SystemParamsOperation.getInstance().setSslSwitchStatus(true);
|
||||
// serverIP = "posuat.myanmarorientalbank.com";
|
||||
// serverPort = 5033;
|
||||
} else {
|
||||
isSwitchIp = false;
|
||||
}
|
||||
@ -356,7 +374,11 @@ public class ISOSocket {
|
||||
reversalSwitchFlag = SystemParamsOperation.getInstance().isReversalOn();
|
||||
|
||||
if (reversalSwitchFlag) {
|
||||
reversalTestCaseFlag = reversalTrans;
|
||||
if (reversalTrans) {
|
||||
reversalTestCaseFlag = true;
|
||||
} else {
|
||||
reversalTestCaseFlag = false;
|
||||
}
|
||||
} else {
|
||||
reversalTestCaseFlag = true;
|
||||
}
|
||||
@ -380,8 +402,54 @@ public class ISOSocket {
|
||||
if (SystemParamsOperation.getInstance().isSslOn()) {
|
||||
|
||||
try {
|
||||
OkHttpClient client = getClient();
|
||||
sslSocket = (SSLSocket) client.sslSocketFactory().createSocket();
|
||||
TrustManager[] trustAll = new TrustManager[]{new X509TrustManager() {
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
|
||||
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
|
||||
}};
|
||||
SSLContext ctx = SSLContext.getInstance("TLS");
|
||||
ctx.init(null, trustAll, new SecureRandom());
|
||||
|
||||
SSLSocketFactory factory = ctx.getSocketFactory();
|
||||
|
||||
// try (SSLSocket sslsock = (SSLSocket) factory.createSocket()) {
|
||||
//
|
||||
// sslsock.setEnabledProtocols(new String[]{"TLSv1.2"});
|
||||
//// while (!isSSLOnline(timeout,subscriber)) {
|
||||
//// Thread.sleep(150);
|
||||
//// subscriber.onError(new Throwable("java.net.SocketTimeoutException: connect timed out"));
|
||||
//// }
|
||||
//
|
||||
// sslsock.setSoTimeout(60000);
|
||||
// sslsock.connect(new InetSocketAddress(serverIP, serverPort), connectTimeout);
|
||||
//
|
||||
// sslsock.startHandshake();
|
||||
//
|
||||
// SSLSession session = sslsock.getSession();
|
||||
//
|
||||
// LogUtil.d(TAG, "SSL handshake success to " + serverIP + ":" + serverPort + "\n");
|
||||
// LogUtil.d(TAG, "TLS handshake success to " + serverIP + ":" + serverPort + "\n");
|
||||
// LogUtil.d(TAG, "TLS version: " + session.getProtocol() + "\n");
|
||||
// LogUtil.d(TAG,"Cipher suite: " + session.getCipherSuite() + "\n");
|
||||
//
|
||||
// try {
|
||||
// java.security.cert.Certificate[] chain = session.getPeerCertificates();
|
||||
// if (chain != null && chain.length > 0) {
|
||||
// LogUtil.d(TAG,"Peer certificates:\n");
|
||||
// for (int i = 0; i < chain.length; i++) {
|
||||
// X509Certificate x = (X509Certificate) chain[i];
|
||||
// LogUtil.d(TAG, " [" + i + "] Subject: " + x.getSubjectX500Principal().getName() + "\n");
|
||||
// LogUtil.d(TAG," Issuer: " + x.getIssuerX500Principal().getName() + "\n");
|
||||
// LogUtil.d(TAG," Valid: " + formatDate(x.getNotBefore()) + " - " + formatDate(x.getNotAfter()) + "\n");
|
||||
// }
|
||||
// }
|
||||
// } catch (Exception ignored) { }
|
||||
// }
|
||||
|
||||
// OkHttpClient client = getClient();
|
||||
sslSocket = (SSLSocket) factory.createSocket();
|
||||
sslSocket.setEnabledProtocols(new String[]{"TLSv1.2"});
|
||||
// sslSocket.setEnabledProtocols(new String[]{"TLSv1", "TLSv1.1", "TLSv1.2", "TLSv1.3"});
|
||||
// while (!isSSLOnline(timeout,subscriber)) {
|
||||
// Thread.sleep(150);
|
||||
// subscriber.onError(new Throwable("java.net.SocketTimeoutException: connect timed out"));
|
||||
@ -390,6 +458,28 @@ public class ISOSocket {
|
||||
sslSocket.setSoTimeout(60000);
|
||||
sslSocket.connect(new InetSocketAddress(serverIP, serverPort), connectTimeout);
|
||||
|
||||
sslSocket.startHandshake();
|
||||
|
||||
SSLSession session = sslSocket.getSession();
|
||||
|
||||
LogUtil.d(TAG, "SSL handshake success to " + serverIP + ":" + serverPort + "\n");
|
||||
LogUtil.d(TAG, "TLS handshake success to " + serverIP + ":" + serverPort + "\n");
|
||||
LogUtil.d(TAG, "TLS version: " + session.getProtocol() + "\n");
|
||||
LogUtil.d(TAG,"Cipher suite: " + session.getCipherSuite() + "\n");
|
||||
|
||||
try {
|
||||
java.security.cert.Certificate[] chain = session.getPeerCertificates();
|
||||
if (chain != null && chain.length > 0) {
|
||||
LogUtil.d(TAG,"Peer certificates:\n");
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
X509Certificate x = (X509Certificate) chain[i];
|
||||
LogUtil.d(TAG, " [" + i + "] Subject: " + x.getSubjectX500Principal().getName() + "\n");
|
||||
LogUtil.d(TAG," Issuer: " + x.getIssuerX500Principal().getName() + "\n");
|
||||
LogUtil.d(TAG," Valid: " + formatDate(x.getNotBefore()) + " - " + formatDate(x.getNotAfter()) + "\n");
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) { }
|
||||
|
||||
inputStream = sslSocket.getInputStream();
|
||||
outputStream = sslSocket.getOutputStream();
|
||||
|
||||
@ -403,6 +493,11 @@ public class ISOSocket {
|
||||
int len = -1;
|
||||
if (reversalTestCaseFlag) {
|
||||
len = inputStream.read(recBuff);
|
||||
} else {
|
||||
int lenn = inputStream.read(recBuff);
|
||||
|
||||
String received = ByteUtil.bytes2HexStr(recBuff);
|
||||
LogUtil.d(TAG,"Received Response :"+received);
|
||||
}
|
||||
|
||||
rLen = len;
|
||||
@ -417,7 +512,7 @@ public class ISOSocket {
|
||||
subscriber.onComplete();
|
||||
|
||||
|
||||
} catch (CertificateException | KeyStoreException | IOException |
|
||||
} catch ( IOException |
|
||||
NoSuchAlgorithmException | KeyManagementException e) {
|
||||
e.printStackTrace();
|
||||
subscriber.onError(e);
|
||||
@ -454,6 +549,11 @@ public class ISOSocket {
|
||||
int len = -1;
|
||||
if (reversalTestCaseFlag) {
|
||||
len = inputStream.read(recBuff);
|
||||
} else {
|
||||
int lenn = inputStream.read(recBuff);
|
||||
|
||||
String received = ByteUtil.bytes2HexStr(recBuff);
|
||||
LogUtil.d(TAG,"Received Response :"+received);
|
||||
}
|
||||
|
||||
rLen = len;
|
||||
|
||||
@ -206,7 +206,7 @@ public abstract class BaseXPrint {
|
||||
String finalVersion = SystemParamsOperation.getInstance().getFinalVersion();
|
||||
|
||||
sunmiPrinterService.setFontSize(textSize, innerResultCallback);
|
||||
// sunmiPrinterService.printText("***** MERCHANT COPY *****" + "\n", innerResultCallback);
|
||||
sunmiPrinterService.printText("***** MERCHANT COPY *****" + "\n", innerResultCallback);
|
||||
sunmiPrinterService.printText(finalVersion + "\n", innerResultCallback);
|
||||
sunmiPrinterService.printText(receiptFooter + "\n", innerResultCallback);
|
||||
} catch (RemoteException e) {
|
||||
|
||||
@ -58,14 +58,14 @@ public class PrintXImpl extends BaseXPrint implements PrintX {
|
||||
opts.inJustDecodeBounds = true;
|
||||
|
||||
// Step 1: Only read dimensions first
|
||||
BitmapFactory.decodeResource(resources, R.drawable.mob_print_logo, opts);
|
||||
BitmapFactory.decodeResource(resources, R.drawable.print_logo_mpu, opts);
|
||||
|
||||
// Step 2: Calculate sample size so width <= 384px
|
||||
opts.inSampleSize = calculateInSampleSize(opts, 384, 384);
|
||||
opts.inJustDecodeBounds = false;
|
||||
|
||||
// Step 3: Decode scaled-down bitmap
|
||||
bitmap = BitmapFactory.decodeResource(resources, R.drawable.mob_print_logo, opts);
|
||||
bitmap = BitmapFactory.decodeResource(resources, R.drawable.print_logo_mpu, opts);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -50,14 +50,14 @@ public class ReversalAction {
|
||||
}
|
||||
|
||||
private ReversalAction() {
|
||||
isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.CARDZONE)
|
||||
isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.FINEXUS)
|
||||
.build();
|
||||
}
|
||||
|
||||
public ReversalAction setData(TradeData tradeData) {
|
||||
this.tradeData = tradeData;
|
||||
payDetail = tradeData.getPayDetail();
|
||||
payDetail.setTransactionType(TransactionsType.REVERSAL.value);
|
||||
payDetail.setTransactionType(TransactionType.REVERSAL);
|
||||
// payDetail.setTransType(REVERSAL);
|
||||
if (TextUtils.equals(payDetail.getAccountType(), MPU)) {
|
||||
BITMAP = getBitmapMPU(payDetail);
|
||||
@ -129,7 +129,7 @@ public class ReversalAction {
|
||||
public void startReversal(ReversalListener reversalListener) {
|
||||
HostName hostName = HostName.BPC;
|
||||
LogUtil.d(TAG, "Starting Reversal....");
|
||||
byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.CZ_REVERSAL, MessageType.CZ_REVERSAL);
|
||||
byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.MPU_NEW_REVERSAL, MessageType.REVERSAL);
|
||||
// byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.BPC_AUTOMATIC_REVERSAL, MessageType.REVERSAL);
|
||||
ISOSocket.getInstance().enqueue(sendBytes, sendBytes.length,true, new ISOCallback() {
|
||||
@Override
|
||||
|
||||
@ -50,7 +50,7 @@ public class SignOnProcess {
|
||||
private SignOnProcess() {
|
||||
tradeData = Params.newTrade(true);
|
||||
// payDetail = tradeData.getPayDetail();
|
||||
isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.CARDZONE)
|
||||
isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.ONLY_HEADER,HostName.MPU)
|
||||
.build();
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ public class SignOnProcess {
|
||||
flag = false;
|
||||
return listener -> {
|
||||
// LogUtil.d(TAG, "Starting TX SignOn");
|
||||
HostName hostName = HostName.CARDZONE;
|
||||
HostName hostName = HostName.MPU;
|
||||
PayDetail payDetail = tradeData.getPayDetail();
|
||||
|
||||
payDetail.setProcessCode(TransactionsType.SIGN_ON.processCode);
|
||||
@ -67,7 +67,7 @@ public class SignOnProcess {
|
||||
payDetail.setTransactionType(TransactionsType.SIGN_ON.value);
|
||||
payDetail.setHostName(hostName.name);
|
||||
|
||||
byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.CZ_SIGN_ON, MessageType.NETWORK_MANAGEMENT);
|
||||
byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, BitmapConfig.MPU_NEW_SIGN_ON, MessageType.NETWORK_MANAGEMENT);
|
||||
ISOSocket.getInstance().enqueue(sendBytes, sendBytes.length,false, new ISOCallback() {
|
||||
@Override
|
||||
public void onReceive(byte[] bytes, int length) {
|
||||
@ -94,7 +94,6 @@ public class SignOnProcess {
|
||||
|
||||
System.arraycopy(field62, 0, encryptedPIK, 0, 8);
|
||||
System.arraycopy(field62, 0, encryptedPIK, 8, 8);
|
||||
// System.arraycopy(field62, 0, encryptedPIK, 0, 16);
|
||||
try {
|
||||
byte[] kcv = ByteUtil.hexStr2Bytes(TriDes.getKcv(encryptedPIK));
|
||||
LogUtil.d(TAG, "Encrypted PIK:" + ByteUtil.bytes2HexStr(encryptedPIK));
|
||||
@ -123,7 +122,6 @@ public class SignOnProcess {
|
||||
|
||||
System.arraycopy(field62, 0, encryptedPIK, 0, 8);
|
||||
System.arraycopy(field62, 0, encryptedPIK, 8, 8);
|
||||
|
||||
// System.arraycopy(field62, 0, encryptedPIK, 0, 16);
|
||||
|
||||
try {
|
||||
|
||||
@ -174,8 +174,8 @@ public class TransactionsOperation {
|
||||
if (responseMap.get("F038") != null) {
|
||||
transPayDetail.setApprovalCode(Objects.requireNonNull(responseMap.get("F038")).getDataStr());
|
||||
} else {
|
||||
// transPayDetail.setIsNeedReversal(true);
|
||||
// return;
|
||||
transPayDetail.setIsNeedReversal(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (responseMap.get("F046") != null) {
|
||||
@ -295,7 +295,7 @@ public class TransactionsOperation {
|
||||
|
||||
if(payDetail.getAccountType().equals(MPU)){
|
||||
// payDetail.setIsFreeSign(true);
|
||||
payDetail.setTransCVM(TransCVM.SIGNATURE);
|
||||
payDetail.setTransCVM(TransCVM.NO_CVM);
|
||||
}
|
||||
return tradeData;
|
||||
}
|
||||
@ -376,6 +376,7 @@ public class TransactionsOperation {
|
||||
newPay.setTransCVM(TransCVM.SIGNATURE);
|
||||
|
||||
if((oldPay.getAccountType().equals(CardScheme.MASTERCARD.name) || oldPay.getAccountType().equals(CardScheme.VISA.name))) {
|
||||
|
||||
newPay.setProcessCode(TransactionsType.PRE_AUTH_SALE.processCode);
|
||||
}
|
||||
// for manual entry reversal which need de 35
|
||||
@ -390,14 +391,12 @@ public class TransactionsOperation {
|
||||
newPay.setReferNo(oldPay.getReferNo());
|
||||
newPay.setTempKSN(oldPay.getTempKSN());
|
||||
newPay.setTransCVM(oldPay.getTransCVM()); //added on 26 Nov 2025
|
||||
newPay.setApprovalCode(oldPay.getApprovalCode());
|
||||
newPay.setTradeTime(oldPay.getTradeTime()); // mpu
|
||||
newPay.setTradeDate(oldPay.getTradeDate()); // mpu
|
||||
} else if (transactionsType == TransactionsType.PRE_AUTH_COMPLETE_VOID) {
|
||||
newPay.setVoucherNo(oldPay.getVoucherNo());
|
||||
newPay.setCustomOrderNo(oldPay.getVoucherNo());
|
||||
newPay.setReferNo(oldPay.getReferNo());
|
||||
newPay.setCardInfo(oldPay.getCardInfo());
|
||||
|
||||
/*
|
||||
* new requirements */
|
||||
newPay.setCardType(AidlConstants.CardType.IC.getValue());
|
||||
@ -407,7 +406,7 @@ public class TransactionsOperation {
|
||||
|
||||
|
||||
if(oldPay.getAccountType().equals(CardScheme.MPU.name) || oldPay.getAccountType().equals(CardScheme.MPU_CTLS.name)){
|
||||
newPay.setTransCVM(TransCVM.SIGNATURE);
|
||||
newPay.setTransCVM(TransCVM.NO_CVM);
|
||||
}
|
||||
|
||||
newTrade.setPayDetail(newPay);
|
||||
|
||||
@ -5,7 +5,6 @@ public enum MessageType {
|
||||
AUTHORIZATION,
|
||||
AUTHORIZATION_COMPLETE,
|
||||
REVERSAL,
|
||||
CZ_REVERSAL,
|
||||
NETWORK_MANAGEMENT,
|
||||
TC_ADVICE,
|
||||
BATCH_UPLOAD,
|
||||
|
||||
@ -5,8 +5,7 @@ public enum HostName {
|
||||
FINEXUS("FINEXUS"),
|
||||
CARDZONE("CARDZONE"),
|
||||
|
||||
MPU("MPU"),
|
||||
MOB("MOB");
|
||||
MPU("MPU");
|
||||
|
||||
|
||||
public final String name;
|
||||
|
||||
@ -44,7 +44,7 @@ public class HostUtils {
|
||||
if (hostName == HostName.MPU) {
|
||||
bitmap = BitmapConfig.MPU_NEW_VOID;
|
||||
} else {
|
||||
bitmap = BitmapConfig.CZ_VOID;
|
||||
bitmap = BitmapConfig.FINEXUS_VOID;
|
||||
}
|
||||
break;
|
||||
case SETTLEMENT:
|
||||
@ -58,35 +58,35 @@ public class HostUtils {
|
||||
if (hostName == HostName.MPU) {
|
||||
bitmap = BitmapConfig.MPU_NEW_PRE_AUTH;
|
||||
} else {
|
||||
bitmap = BitmapConfig.CZ_PRE_AUTH;
|
||||
bitmap = BitmapConfig.FUND_TRANSFER_PRE_CHECK;
|
||||
}
|
||||
break;
|
||||
case PRE_AUTH_VOID:
|
||||
if (hostName == HostName.MPU) {
|
||||
bitmap = BitmapConfig.MPU_NEW_PRE_AUTH_CANCEL;
|
||||
} else {
|
||||
bitmap = BitmapConfig.CZ_PRE_AUTH_VOID;
|
||||
bitmap = BitmapConfig.CZ_SALE;
|
||||
}
|
||||
break;
|
||||
case PRE_AUTH_COMPLETE:
|
||||
if (hostName == HostName.MPU) {
|
||||
bitmap = BitmapConfig.MPU_NEW_PRE_AUTH_COMPLETE_BITMAP;
|
||||
} else {
|
||||
bitmap = BitmapConfig.CZ_PRE_AUTH_COMP;
|
||||
bitmap = BitmapConfig.CZ_SALE;
|
||||
}
|
||||
break;
|
||||
case PRE_AUTH_COMPLETE_VOID:
|
||||
if (hostName == HostName.MPU) {
|
||||
bitmap = BitmapConfig.MPU_NEW_PRE_AUTH_COMPLETE_CANCEL;
|
||||
} else {
|
||||
bitmap = BitmapConfig.CZ_PRE_AUTH_COMP_VOID;
|
||||
bitmap = BitmapConfig.FINEXUS_PRE_AUTH_VOID;
|
||||
}
|
||||
break;
|
||||
case REFUND:
|
||||
if (hostName == HostName.MPU) {
|
||||
bitmap = BitmapConfig.MPU_NEW_REFUND;
|
||||
} else {
|
||||
bitmap = BitmapConfig.CZ_REFUND;
|
||||
bitmap = BitmapConfig.CZ_SALE;
|
||||
}
|
||||
break;
|
||||
case TIP_ADJUSTMENT:
|
||||
@ -130,7 +130,7 @@ public class HostUtils {
|
||||
if (hostName == HostName.BPC) {
|
||||
msgType = MessageType.REVERSAL;
|
||||
} else {
|
||||
msgType = MessageType.REVERSAL;
|
||||
msgType = MessageType.FINANCIAL;
|
||||
}
|
||||
break;
|
||||
case SETTLEMENT:
|
||||
|
||||
@ -176,7 +176,7 @@ public class BitmapConfig {
|
||||
// 703C058008C08000 7038058028C00000
|
||||
public static final String MPU_NEW_REFUND ="703C058008C08000";
|
||||
|
||||
public static final String MPU_NEW_PRE_AUTH ="7020058020C09000";
|
||||
public static final String MPU_NEW_PRE_AUTH ="7020058020C08000";
|
||||
|
||||
|
||||
|
||||
@ -193,14 +193,6 @@ public class BitmapConfig {
|
||||
public static final String MPU_NEW_CASH_ADVANCE="7020058020C09000";
|
||||
|
||||
public static final String CZ_SALE="7020058020C09000";
|
||||
public static final String CZ_VOID="7038058008C08010";
|
||||
public static final String CZ_REFUND="703C058008C08000";
|
||||
public static final String CZ_REVERSAL="7020078000C08000";
|
||||
public static final String CZ_BATCH_UPLOAD="703805800CC00010";
|
||||
public static final String CZ_PRE_AUTH="7020058020C09000";
|
||||
public static final String CZ_PRE_AUTH_VOID="7038058028C08000";
|
||||
public static final String CZ_PRE_AUTH_COMP="703805802CC08000";
|
||||
public static final String CZ_PRE_AUTH_COMP_VOID="703805802CC08004";
|
||||
|
||||
public static final String UPI_SALE = "7020058020C09200";
|
||||
|
||||
|
||||
@ -247,7 +247,7 @@ public class FieldConfig {
|
||||
// for TTIP MPU
|
||||
// /* FLD 35 */ {2, SDK_8583_LEN_BCD, 37, SDK_8583_DATA_BCD, SDK_8583_ALIGN_L, '0'},
|
||||
|
||||
/* FLD 35 */ {2, SDK_8583_LEN_BCD, 37, SDK_8583_DATA_BCD, SDK_8583_ALIGN_R, ' '},
|
||||
/* FLD 35 */ {2, SDK_8583_LEN_BCD, 37, SDK_8583_DATA_BCD, SDK_8583_ALIGN_R, '0'},
|
||||
/* FLD 36 */ {3, SDK_8583_LEN_BCD, 999, SDK_8583_DATA_BIT, SDK_8583_ALIGN_L, '0'},
|
||||
|
||||
/* FLD 37 */ {0, SDK_8583_LEN_BCD, 12, SDK_8583_DATA_ASC, SDK_8583_ALIGN_R, '0'},
|
||||
|
||||
@ -4,13 +4,11 @@ import android.text.TextUtils;
|
||||
|
||||
import com.sunmi.pay.hardware.aidl.AidlConstants;
|
||||
import com.utsmyanmar.paylibs.Constant;
|
||||
import com.utsmyanmar.paylibs.batch_upload.BatchUploadProcess;
|
||||
import com.utsmyanmar.paylibs.model.MsgField;
|
||||
import com.utsmyanmar.paylibs.model.PayDetail;
|
||||
import com.utsmyanmar.paylibs.model.TradeData;
|
||||
import com.utsmyanmar.paylibs.model.enums.TransCVM;
|
||||
import com.utsmyanmar.paylibs.utils.enums.CardScheme;
|
||||
import com.utsmyanmar.paylibs.utils.enums.HostName;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Iterator;
|
||||
@ -361,7 +359,7 @@ public class FieldUtils {
|
||||
// } else {
|
||||
// iterator.remove();
|
||||
// }
|
||||
field.setDataStr("000");
|
||||
field.setDataStr("001");
|
||||
break;
|
||||
case 24: //Network International Identifier NII
|
||||
|
||||
@ -376,12 +374,14 @@ public class FieldUtils {
|
||||
08 – mail order/telephone order
|
||||
* */
|
||||
// Service point condition code Fill in 00 for ordinary consumer transactions and mobile phone chip transactions, fill in 08 for order consumer transactions, fill in 64 for installment transactions, fill in 65 for points consumption transactions, fill in 67 for mobile phone card-free reservations
|
||||
if (payDetail.getTransactionType() == PRE_AUTH_SALE.value) {
|
||||
field.setDataStr("06");
|
||||
}
|
||||
else if(payDetail.getTransactionType() == REFUND.value || payDetail.getTransactionType() == REVERSAL.value) {
|
||||
// field.setDataStr("00"); // MPU
|
||||
field.setDataStr("61"); // CZ
|
||||
// if (payDetail.getTransactionType() == PRE_AUTH_VOID.value) {
|
||||
// field.setDataStr("06");
|
||||
// } else {
|
||||
// field.setDataStr("00");
|
||||
// }
|
||||
|
||||
if(payDetail.getTransactionType() == REFUND.value) {
|
||||
field.setDataStr("00"); // MPU
|
||||
} else if(payDetail.getCardType() == -1) {
|
||||
field.setDataStr("08");
|
||||
}
|
||||
@ -507,16 +507,9 @@ public class FieldUtils {
|
||||
|
||||
break;
|
||||
case 60: //Private(oldMPU) //original Amount Void(new MPU)
|
||||
//
|
||||
String field60 = tradeData.getField60();
|
||||
String lengthValue = String.format(Locale.getDefault(),"%04d", field60.length())+field60;
|
||||
field.setDataStr(lengthValue);
|
||||
|
||||
|
||||
// for CardZone
|
||||
// String field60 = tradeData.getField60();
|
||||
// String lengthValue = String.format(Locale.getDefault(),"%04d", field60.length())+field60;
|
||||
// field.setDataStr(field60);
|
||||
break;
|
||||
case 61:
|
||||
// TODO
|
||||
@ -543,9 +536,7 @@ public class FieldUtils {
|
||||
break;
|
||||
case 63: //Private Use
|
||||
String settleData = payDetail.getSettleData();
|
||||
String settleValue = String.format(Locale.getDefault(),"%04d", settleData.length())+settleData;
|
||||
field.setDataStr(settleValue);
|
||||
// field.setDataStr(settleData);
|
||||
field.setDataStr(settleData);
|
||||
break;
|
||||
case 64: //Message Authentication Code (MAC) Required when the 39 field in the response message is "00"
|
||||
field.setDataStr("0000000000000000");
|
||||
|
||||
@ -82,9 +82,7 @@ public class Params {
|
||||
payDetail.setIsCanceled(false);
|
||||
payDetail.transNum = System.currentTimeMillis() / 1000;
|
||||
// need to add host logic in another place
|
||||
// payDetail.setHostName("MPU");
|
||||
payDetail.setHostName("MOB");
|
||||
// payDetail.setHostName("MOB");
|
||||
payDetail.setHostName("MPU");
|
||||
|
||||
payDetail.setOriginalTransDate(SystemDateTime.getMMDD()+SystemDateTime.getYYYY());
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 132 KiB |
@ -1,21 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDYTCCAkmgAwIBAgIETeycDjANBgkqhkiG9w0BAQsFADBhMQswCQYDVQQGEwJt
|
||||
eTELMAkGA1UECBMCa2wxDDAKBgNVBAcTA2trbDERMA8GA1UEChMIY2FyZHpvbmUx
|
||||
ETAPBgNVBAsTCGNhcmR6b25lMREwDwYDVQQDEwhjYXJkem9uZTAeFw0yMTA3MDcw
|
||||
ODU5MzlaFw0zMTA3MDUwODU5MzlaMGExCzAJBgNVBAYTAm15MQswCQYDVQQIEwJr
|
||||
bDEMMAoGA1UEBxMDa2tsMREwDwYDVQQKEwhjYXJkem9uZTERMA8GA1UECxMIY2Fy
|
||||
ZHpvbmUxETAPBgNVBAMTCGNhcmR6b25lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEA2v7WJjmr0b9WpbcsTtk6llJDA5XeReWc3in0sirutMQi+9jLUdgJ
|
||||
0Kdr0Cro0vbJAcVWTBYnMqnqh7oJQYs6vpIFKJA175ZhclQFAcL2jth+Tsqx9Av1
|
||||
DxbuuB7yxU7ErkhXe+/B0R8zOag866R3Xg7u09GG4mlQMx5zmo1Hn3lqMU0lxEXM
|
||||
vhkzVXLUMLhVwu/oJk98u+6pPXoCzXPjBCgy3iR+BaGIR6aiflz8Bi1Rn3XgfnMi
|
||||
PzOzxKRZu5mNBRijs7ztcjA8Pc2uNI0ux3+jUJTgu2JRIBJs+7BkNcJeLzpW5psz
|
||||
qfFdwxTKkgfqU9gJwuPaEbdnP0j7Rv2MBwIDAQABoyEwHzAdBgNVHQ4EFgQUOF7s
|
||||
btNCxmv9HSAkSAPVAHpDXY4wDQYJKoZIhvcNAQELBQADggEBADOJaUnRiVucIb8q
|
||||
jxplpSE0gOHMng+BMq2gKcqqc+QRc/mgM3n0J8F1A3rzj3udbzen3/9TnOiH17uy
|
||||
FGLH12sJ7dJWMGAJ2p15N307ckrCab3+3Y1w6OQJLZ8t3eeXFGPVWQJtiOUbyX73
|
||||
3Fv+TpNl6X1uEdQ0zNDiAvWZQ/e6ynYGF/tSgZLJvgV+8UY5ShCA0Ypousm6sPqb
|
||||
KQXPCs3kRn1eMgMy8PcmUlZK/5qhD+xZswWgNiQ6EyCWmwpB4O0N9wQbLBTFZkGA
|
||||
bDke78LVS1nUam9czcNvSDYyjWsk9ud8mo9JfF21qmwCR68btqDgeU0hM9W6lEQo
|
||||
ezrrz9k=
|
||||
-----END CERTIFICATE-----
|
||||
23
paylibs/src/main/res/raw/mpu_crt_2026.crt
Normal file
23
paylibs/src/main/res/raw/mpu_crt_2026.crt
Normal file
@ -0,0 +1,23 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID3DCCAsSgAwIBAgIJAIuL4ypXInCoMA0GCSqGSIb3DQEBBQUAMGcxCzAJBgNV
|
||||
BAYTAk1SMQswCQYDVQQIDAJNUjEMMAoGA1UECgwDTVBVMQwwCgYDVQQLDANNUFUx
|
||||
DTALBgNVBAMMBHRlc3QxIDAeBgkqhkiG9w0BCQEWEXdhaXlhbkBmcHQuY29tLnZu
|
||||
MB4XDTIxMDIwMzE3MTExMloXDTIyMDIwMzE3MTExMlowdzELMAkGA1UEBhMCTVIx
|
||||
DzANBgNVBAgMBllhbmdvbjEPMA0GA1UEBwwGWWFuZ29uMQwwCgYDVQQKDANNUFUx
|
||||
DDAKBgNVBAsMA01QVTENMAsGA1UEAwwEdGVzdDEbMBkGCSqGSIb3DQEJARYMdGVz
|
||||
dEBtcHUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAujLe6mWJ
|
||||
GXliGUoLdJEA37VyBOQ7zLpge7u2QM2UMQXnKosdtZzMzXnVrnctJ6ehzLnhL0Lv
|
||||
Oissr7qo53haXsJJccHeqcTH5cFkh96IswOrc8/1MMrb4zMjnNjOZaxmB4HeGHKk
|
||||
KjNLKTTO8It3v/MziBhxUEEKVrN4npeUfsGVPfrvYnZXSWuRLhzYYLtEz/LFg4Yh
|
||||
28pCXqk2vmGNV62oZ2+SDisoiYdIVEOMRqb/7cJg+cd0JRdvxHsTNuYRHGtJOM10
|
||||
lEnoI+moE5OIUpp8Z+i4ZcvyThpNbRWf9sRzB8oc32fZ2UWnlN5+bVRLCjlk2jNO
|
||||
SGdMuMaF0bs3GwIDAQABo3sweTAJBgNVHRMEAjAAMCwGCWCGSAGG+EIBDQQfFh1P
|
||||
cGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTAdBgNVHQ4EFgQUipyzRYfqRc2P
|
||||
QCJ0FJp6eAvI1wkwHwYDVR0jBBgwFoAUvYEAOtcvUt4CxCp+9zRG2oJqos8wDQYJ
|
||||
KoZIhvcNAQEFBQADggEBAAjBQroy74ACyyJCZJ50KBTYQI3Sk82hO/+zZFqsJgWm
|
||||
mNum31TtfwhvQmi94sXQSar0UsqLTmLC3UTucwEdSKOPzXF5BK4EEbkYgMm78hNK
|
||||
2zqhGvcWlqun+KPxmnMRFoVmN3Ck2PkcgudvAeV0G3rm0OdLUwLoK2TcREVf1Cwg
|
||||
C7jX5QtGOgVqnKDZBuoSvdbV30ka7pKkdJAy/Wus4N9hHH+bR2FNkLgTDoXnV8LL
|
||||
E2dRKVYAh9TtuXiW/ejhPtEc14sMP+8JpCFX3DYx4yRW8ZeMl5jal4LhRFXdDbVl
|
||||
Wm99KcWM+TNw/nzKwv0zUJXy0HlN82tvLX1/wbBUo8M=
|
||||
-----END CERTIFICATE-----
|
||||
BIN
paylibs/src/main/res/raw/mpucert.crt
Normal file
BIN
paylibs/src/main/res/raw/mpucert.crt
Normal file
Binary file not shown.
BIN
paylibs/src/main/res/raw/my_cert.crt
Normal file
BIN
paylibs/src/main/res/raw/my_cert.crt
Normal file
Binary file not shown.
113
paylibs/src/main/res/raw/smile_uat.crt
Normal file
113
paylibs/src/main/res/raw/smile_uat.crt
Normal file
@ -0,0 +1,113 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIG8DCCBNigAwIBAgIQWgAhSkRBOifV9FjHQOJCuDANBgkqhkiG9w0BAQwFADBL
|
||||
MQswCQYDVQQGEwJBVDEQMA4GA1UEChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NT
|
||||
TCBSU0EgRG9tYWluIFNlY3VyZSBTaXRlIENBMB4XDTI0MDkwMzAwMDAwMFoXDTI1
|
||||
MDkwMzIzNTk1OVowGTEXMBUGA1UEAwwOKi55b21hYmFuay5uZXQwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCAqUfzHF/N4m3xxNr/noBpg9s8edFWghYn
|
||||
sYEAOQmMD1tVsjFavds9eAO5JBhL2+yQ8dxd5P5yqAHuQmEcBpw0YdPEAsKJbrqG
|
||||
4VXU40q1DbQipnHiTrQx0RG5aRFsP6OTrRU0MnQMaFGTSgMKYKg0YM24si/JyyiX
|
||||
eJXpEIXzt10NWpQfJ7T3RrzkkEHsfPzYmiBecUVmCu2Mb0/jym+Hr5eBvEf/mmhR
|
||||
re/0hofitx9OTwmZt85uPVwpP6miOLpby+/46v7k8PSZ7qJhCv34AnnldY3uA+Ws
|
||||
ld+Ria5Kpt6dHiBPzer/8HNd2Xkdpo2Ny3jq8N9vo0UJ2H7rWgy7AgMBAAGjggMA
|
||||
MIIC/DAfBgNVHSMEGDAWgBTI2XhootkZaNU9ct5fCj7ctYaGpjAdBgNVHQ4EFgQU
|
||||
Iu3iisKOIvooYnMumJGFqW4LTEkwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQC
|
||||
MAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEkGA1UdIARCMEAwNAYL
|
||||
KwYBBAGyMQECAk4wJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9D
|
||||
UFMwCAYGZ4EMAQIBMIGIBggrBgEFBQcBAQR8MHowSwYIKwYBBQUHMAKGP2h0dHA6
|
||||
Ly96ZXJvc3NsLmNydC5zZWN0aWdvLmNvbS9aZXJvU1NMUlNBRG9tYWluU2VjdXJl
|
||||
U2l0ZUNBLmNydDArBggrBgEFBQcwAYYfaHR0cDovL3plcm9zc2wub2NzcC5zZWN0
|
||||
aWdvLmNvbTAnBgNVHREEIDAegg4qLnlvbWFiYW5rLm5ldIIMeW9tYWJhbmsubmV0
|
||||
MIIBfAYKKwYBBAHWeQIEAgSCAWwEggFoAWYAdQDd3Mo0ldfhFgXnlTL6x5/4PRxQ
|
||||
39sAOhQSdgosrLvIKgAAAZG2rpYwAAAEAwBGMEQCIAdAYV4eBpRPW8pCNmvriCr0
|
||||
sOJZeBqBHoQ6fBSJHG1CAiAs841ZeuQRpFtLzZxxDXWbQYKJuT8iV6l2bZHsUdDh
|
||||
owB1AA3h8jAr0w3BQGISCepVLvxHdHyx1+kw7w5CHrR+Tqo0AAABkbaulhAAAAQD
|
||||
AEYwRAIgCLjpVhxG/w/Fsm+aAmE4t4PVAgASOgVMzoD/eOuor/MCIHN5h/YzzOzy
|
||||
KbhEl5VkeSLbLUFz99Lq+Ci5Z0jRRTJ9AHYAEvFONL1TckyEBhnDjz96E/jntWKH
|
||||
iJxtMAWE6+WGJjoAAAGRtq6WDwAABAMARzBFAiEA7uQaaiKBOBPRukDoHqvTzifk
|
||||
1N8fcbf34xDC+BlelnUCIAZaPHlu2u+DJcxCAGgBoqVtZhdO64tcV6yy1fYqo2fq
|
||||
MA0GCSqGSIb3DQEBDAUAA4ICAQBrxQPnmGA+CnhEq2ZaqZNQteRXb9+HbLT9Vq/I
|
||||
6je5BtuYZrF1hd8V/NV3ug+vfWwNjUAILM068BnzfCvAaFxQ/kzmzPgttH2S5e0x
|
||||
0fkG/I0pLtNj9ABcIcOKAnLK3Ce4ANgkpoHg8LtlBy2Tu9Aj+QgDCxz3Jhk6fIOi
|
||||
dBlcveoRE3UpzaZ6G6XLz6CLHcFePhca+qlwWh9L3aw7Kr7ykgU62Y+z2R/KBmvg
|
||||
6lPhumXSMffd3ikESgn+RyVXO6VRyszrIG5/B9NGLc1Of4g0+eE+znWIk4T7eVet
|
||||
RnBMO5I4pLZb63Af9tuYBBBBOkoW+oWFeqxu0Y8G5EqReZiBvG8NvNi2Zj/wvDB+
|
||||
aQN8u2oQnWHTqH5TS+3WSymWKsxHu3anYtRsNdLWb898HkYRPENXDLn8jETDyopN
|
||||
cMBA4qou6di0HOaTmGfGn9cDvrJ/ciYZnT3msCdTSwAk19hacpEtgH3T12FMAtjk
|
||||
aDj45VD1rRfmWj6j8xLVuOV6G6gjsloh3ruQv0j9va1vbmGufc9VbeUPCqFzL2UZ
|
||||
vRr8xAggyjtYPpRwtA+SHAD27nnma3XeEBPwdJJs15wvZw2EH7fI4yYwZ3IrTtAq
|
||||
ICt+BIXVlTQhfgtIC2XCuw3f5e5VlThZRKrJEB1TFAcmW9cCpTrKc5R4cs7XcTbt
|
||||
m7MTbw==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIG1TCCBL2gAwIBAgIQbFWr29AHksedBwzYEZ7WvzANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw
|
||||
MTMwMDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBLMQswCQYDVQQGEwJBVDEQMA4GA1UE
|
||||
ChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBSU0EgRG9tYWluIFNlY3VyZSBT
|
||||
aXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAhmlzfqO1Mdgj
|
||||
4W3dpBPTVBX1AuvcAyG1fl0dUnw/MeueCWzRWTheZ35LVo91kLI3DDVaZKW+TBAs
|
||||
JBjEbYmMwcWSTWYCg5334SF0+ctDAsFxsX+rTDh9kSrG/4mp6OShubLaEIUJiZo4
|
||||
t873TuSd0Wj5DWt3DtpAG8T35l/v+xrN8ub8PSSoX5Vkgw+jWf4KQtNvUFLDq8mF
|
||||
WhUnPL6jHAADXpvs4lTNYwOtx9yQtbpxwSt7QJY1+ICrmRJB6BuKRt/jfDJF9Jsc
|
||||
RQVlHIxQdKAJl7oaVnXgDkqtk2qddd3kCDXd74gv813G91z7CjsGyJ93oJIlNS3U
|
||||
gFbD6V54JMgZ3rSmotYbz98oZxX7MKbtCm1aJ/q+hTv2YK1yMxrnfcieKmOYBbFD
|
||||
hnW5O6RMA703dBK92j6XRN2EttLkQuujZgy+jXRKtaWMIlkNkWJmOiHmErQngHvt
|
||||
iNkIcjJumq1ddFX4iaTI40a6zgvIBtxFeDs2RfcaH73er7ctNUUqgQT5rFgJhMmF
|
||||
x76rQgB5OZUkodb5k2ex7P+Gu4J86bS15094UuYcV09hVeknmTh5Ex9CBKipLS2W
|
||||
2wKBakf+aVYnNCU6S0nASqt2xrZpGC1v7v6DhuepyyJtn3qSV2PoBiU5Sql+aARp
|
||||
wUibQMGm44gjyNDqDlVp+ShLQlUH9x8CAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaA
|
||||
FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTI2XhootkZaNU9ct5fCj7c
|
||||
tYaGpjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE
|
||||
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQIC
|
||||
TjAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1
|
||||
c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYG
|
||||
CCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3Qu
|
||||
Y29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
|
||||
Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAVDwoIzQDV
|
||||
ercT0eYqZjBNJ8VNWwVFlQOtZERqn5iWnEVaLZZdzxlbvz2Fx0ExUNuUEgYkIVM4
|
||||
YocKkCQ7hO5noicoq/DrEYH5IuNcuW1I8JJZ9DLuB1fYvIHlZ2JG46iNbVKA3ygA
|
||||
Ez86RvDQlt2C494qqPVItRjrz9YlJEGT0DrttyApq0YLFDzf+Z1pkMhh7c+7fXeJ
|
||||
qmIhfJpduKc8HEQkYQQShen426S3H0JrIAbKcBCiyYFuOhfyvuwVCFDfFvrjADjd
|
||||
4jX1uQXd161IyFRbm89s2Oj5oU1wDYz5sx+hoCuh6lSs+/uPuWomIq3y1GDFNafW
|
||||
+LsHBU16lQo5Q2yh25laQsKRgyPmMpHJ98edm6y2sHUabASmRHxvGiuwwE25aDU0
|
||||
2SAeepyImJ2CzB80YG7WxlynHqNhpE7xfC7PzQlLgmfEHdU+tHFeQazRQnrFkW2W
|
||||
kqRGIq7cKRnyypvjPMkjeiV9lRdAM9fSJvsB3svUuu1coIG1xxI1yegoGM4r5QP4
|
||||
RGIVvYaiI76C0djoSbQ/dkIUUXQuB8AL5jyH34g3BZaaXyvpmnV4ilppMXVAnAYG
|
||||
ON51WhJ6W0xNdNJwzYASZYH+tmCWI+N60Gv2NNMGHwMZ7e9bXgzUCZH5FaBFDGR5
|
||||
S9VWqHB73Q+OyIVvIbKYcSc2w/aSuFKGSA==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
||||
113
paylibs/src/main/res/raw/star_yomabank_net.crt
Normal file
113
paylibs/src/main/res/raw/star_yomabank_net.crt
Normal file
@ -0,0 +1,113 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIG7zCCBNegAwIBAgIQX5oO6r1lg7MfeJb1v5aSwDANBgkqhkiG9w0BAQwFADBL
|
||||
MQswCQYDVQQGEwJBVDEQMA4GA1UEChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NT
|
||||
TCBSU0EgRG9tYWluIFNlY3VyZSBTaXRlIENBMB4XDTIzMDkyOTAwMDAwMFoXDTI0
|
||||
MDkyODIzNTk1OVowGTEXMBUGA1UEAwwOKi55b21hYmFuay5uZXQwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCAqUfzHF/N4m3xxNr/noBpg9s8edFWghYn
|
||||
sYEAOQmMD1tVsjFavds9eAO5JBhL2+yQ8dxd5P5yqAHuQmEcBpw0YdPEAsKJbrqG
|
||||
4VXU40q1DbQipnHiTrQx0RG5aRFsP6OTrRU0MnQMaFGTSgMKYKg0YM24si/JyyiX
|
||||
eJXpEIXzt10NWpQfJ7T3RrzkkEHsfPzYmiBecUVmCu2Mb0/jym+Hr5eBvEf/mmhR
|
||||
re/0hofitx9OTwmZt85uPVwpP6miOLpby+/46v7k8PSZ7qJhCv34AnnldY3uA+Ws
|
||||
ld+Ria5Kpt6dHiBPzer/8HNd2Xkdpo2Ny3jq8N9vo0UJ2H7rWgy7AgMBAAGjggL/
|
||||
MIIC+zAfBgNVHSMEGDAWgBTI2XhootkZaNU9ct5fCj7ctYaGpjAdBgNVHQ4EFgQU
|
||||
Iu3iisKOIvooYnMumJGFqW4LTEkwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQC
|
||||
MAAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMEkGA1UdIARCMEAwNAYL
|
||||
KwYBBAGyMQECAk4wJTAjBggrBgEFBQcCARYXaHR0cHM6Ly9zZWN0aWdvLmNvbS9D
|
||||
UFMwCAYGZ4EMAQIBMIGIBggrBgEFBQcBAQR8MHowSwYIKwYBBQUHMAKGP2h0dHA6
|
||||
Ly96ZXJvc3NsLmNydC5zZWN0aWdvLmNvbS9aZXJvU1NMUlNBRG9tYWluU2VjdXJl
|
||||
U2l0ZUNBLmNydDArBggrBgEFBQcwAYYfaHR0cDovL3plcm9zc2wub2NzcC5zZWN0
|
||||
aWdvLmNvbTAnBgNVHREEIDAegg4qLnlvbWFiYW5rLm5ldIIMeW9tYWJhbmsubmV0
|
||||
MIIBewYKKwYBBAHWeQIEAgSCAWsEggFnAWUAdQB2/4g/Crb7lVHCYcz1h7o0tKTN
|
||||
uyncaEIKn+ZnTFo6dAAAAYrfFnGoAAAEAwBGMEQCID23iGjCqSL5njxZ4dhGR6xC
|
||||
lr6Wrn//LYaRhG3luDIHAiBLPvTSOFO9fz8LpL/QZ+49xE5WbvFYBPW6pVcXYvqA
|
||||
/gB2ANq2v2s/tbYin5vCu1xr6HCRcWy7UYSFNL2kPTBI1/urAAABit8WcgQAAAQD
|
||||
AEcwRQIgANdbNT0g+H+IUw2MxicwxabC/rsHw9/QwF6KRQW1bKMCIQCHPlGpPhow
|
||||
CiXAGeBXMt/of2hI0ePkT+2Wq70vzYLa+QB0AO7N0GTV2xrOxVy3nbTNE6Iyh0Z8
|
||||
vOzew1FIWUZxH7WbAAABit8WcdcAAAQDAEUwQwIfQypm/cC8h3QPtMaBJC5m72O0
|
||||
rY6wDYEhQQQ2vlcehQIgV4tV4sv8dlrkMjMVXDhKAutb9neYewzaYKYgOAD95C8w
|
||||
DQYJKoZIhvcNAQEMBQADggIBAAhDQXNDUdbWDhRVIeFnJuueUrpq6IbG3S+l8tt4
|
||||
qxUEa3xqhUsujry4yNrJvY+rCSjS6QxHytctmLVaFwvKgELNUXqPtEBTYIw/O/v/
|
||||
+RZnLF2wG4rdD7BzhyBGQZsbcY1nxJlJ1BB8m0+b8aNQesL731ARbn1Tf9Tl46jZ
|
||||
C9pDE5+KbJHJRy9yE/cyik+W9ndUBgEHRDwtZaMsQVHTstg2pBg2Sw9XvDraYMQI
|
||||
Qhr2R9hjMHJaZd9pnjXfDkvA2MZvhjGEEHOvPv0k/r+vf4p2eiHhzYZ0Bv0atMVe
|
||||
RG1sFV7jPvgsi/XhWQgAPUPk8nh/zyImgzVfoiHi4hZkGE2Kv0Gri+lxGyFzZ3rk
|
||||
SNkcgMRFYoLI993ypLNIkcWTs8k4w5RjbQXYml7lEZHS1GjBcc4yaxX25Viyto74
|
||||
vVwSjoKj/PrtT6gVOcub1HrXEaWauJgPaeHNcyT7ZpQ0s3PlnLjrLe5YSrlX1Aji
|
||||
acMq7vQKtGG/6NSShCyIcKAQrFy90tmBV7qs8dwuPh/sUeBPT0fkFQQ50GIswMZU
|
||||
10f/D0GAxEJtdFdp8zHdYmuz0CfTTao6EOKsszQVdde1GRlo4bWNifjtQPpulhai
|
||||
dVmhitRmgLHWz2dIgD0kxM5elRsL1U35bumg9ldSacBCthJYvzeHZkPsa7+g2xZD
|
||||
Mrq3
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIG1TCCBL2gAwIBAgIQbFWr29AHksedBwzYEZ7WvzANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMjAw
|
||||
MTMwMDAwMDAwWhcNMzAwMTI5MjM1OTU5WjBLMQswCQYDVQQGEwJBVDEQMA4GA1UE
|
||||
ChMHWmVyb1NTTDEqMCgGA1UEAxMhWmVyb1NTTCBSU0EgRG9tYWluIFNlY3VyZSBT
|
||||
aXRlIENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAhmlzfqO1Mdgj
|
||||
4W3dpBPTVBX1AuvcAyG1fl0dUnw/MeueCWzRWTheZ35LVo91kLI3DDVaZKW+TBAs
|
||||
JBjEbYmMwcWSTWYCg5334SF0+ctDAsFxsX+rTDh9kSrG/4mp6OShubLaEIUJiZo4
|
||||
t873TuSd0Wj5DWt3DtpAG8T35l/v+xrN8ub8PSSoX5Vkgw+jWf4KQtNvUFLDq8mF
|
||||
WhUnPL6jHAADXpvs4lTNYwOtx9yQtbpxwSt7QJY1+ICrmRJB6BuKRt/jfDJF9Jsc
|
||||
RQVlHIxQdKAJl7oaVnXgDkqtk2qddd3kCDXd74gv813G91z7CjsGyJ93oJIlNS3U
|
||||
gFbD6V54JMgZ3rSmotYbz98oZxX7MKbtCm1aJ/q+hTv2YK1yMxrnfcieKmOYBbFD
|
||||
hnW5O6RMA703dBK92j6XRN2EttLkQuujZgy+jXRKtaWMIlkNkWJmOiHmErQngHvt
|
||||
iNkIcjJumq1ddFX4iaTI40a6zgvIBtxFeDs2RfcaH73er7ctNUUqgQT5rFgJhMmF
|
||||
x76rQgB5OZUkodb5k2ex7P+Gu4J86bS15094UuYcV09hVeknmTh5Ex9CBKipLS2W
|
||||
2wKBakf+aVYnNCU6S0nASqt2xrZpGC1v7v6DhuepyyJtn3qSV2PoBiU5Sql+aARp
|
||||
wUibQMGm44gjyNDqDlVp+ShLQlUH9x8CAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaA
|
||||
FFN5v1qqK0rPVIDh2JvAnfKyA2bLMB0GA1UdDgQWBBTI2XhootkZaNU9ct5fCj7c
|
||||
tYaGpjAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHSUE
|
||||
FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwIgYDVR0gBBswGTANBgsrBgEEAbIxAQIC
|
||||
TjAIBgZngQwBAgEwUAYDVR0fBEkwRzBFoEOgQYY/aHR0cDovL2NybC51c2VydHJ1
|
||||
c3QuY29tL1VTRVJUcnVzdFJTQUNlcnRpZmljYXRpb25BdXRob3JpdHkuY3JsMHYG
|
||||
CCsGAQUFBwEBBGowaDA/BggrBgEFBQcwAoYzaHR0cDovL2NydC51c2VydHJ1c3Qu
|
||||
Y29tL1VTRVJUcnVzdFJTQUFkZFRydXN0Q0EuY3J0MCUGCCsGAQUFBzABhhlodHRw
|
||||
Oi8vb2NzcC51c2VydHJ1c3QuY29tMA0GCSqGSIb3DQEBDAUAA4ICAQAVDwoIzQDV
|
||||
ercT0eYqZjBNJ8VNWwVFlQOtZERqn5iWnEVaLZZdzxlbvz2Fx0ExUNuUEgYkIVM4
|
||||
YocKkCQ7hO5noicoq/DrEYH5IuNcuW1I8JJZ9DLuB1fYvIHlZ2JG46iNbVKA3ygA
|
||||
Ez86RvDQlt2C494qqPVItRjrz9YlJEGT0DrttyApq0YLFDzf+Z1pkMhh7c+7fXeJ
|
||||
qmIhfJpduKc8HEQkYQQShen426S3H0JrIAbKcBCiyYFuOhfyvuwVCFDfFvrjADjd
|
||||
4jX1uQXd161IyFRbm89s2Oj5oU1wDYz5sx+hoCuh6lSs+/uPuWomIq3y1GDFNafW
|
||||
+LsHBU16lQo5Q2yh25laQsKRgyPmMpHJ98edm6y2sHUabASmRHxvGiuwwE25aDU0
|
||||
2SAeepyImJ2CzB80YG7WxlynHqNhpE7xfC7PzQlLgmfEHdU+tHFeQazRQnrFkW2W
|
||||
kqRGIq7cKRnyypvjPMkjeiV9lRdAM9fSJvsB3svUuu1coIG1xxI1yegoGM4r5QP4
|
||||
RGIVvYaiI76C0djoSbQ/dkIUUXQuB8AL5jyH34g3BZaaXyvpmnV4ilppMXVAnAYG
|
||||
ON51WhJ6W0xNdNJwzYASZYH+tmCWI+N60Gv2NNMGHwMZ7e9bXgzUCZH5FaBFDGR5
|
||||
S9VWqHB73Q+OyIVvIbKYcSc2w/aSuFKGSA==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
|
||||
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
|
||||
cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
|
||||
BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
|
||||
MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
|
||||
BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
|
||||
aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
|
||||
dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
|
||||
AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
|
||||
3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
|
||||
tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
|
||||
Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
|
||||
VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
|
||||
79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
|
||||
c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
|
||||
Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
|
||||
c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
|
||||
UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
|
||||
Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
|
||||
BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
|
||||
A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
|
||||
Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
|
||||
VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
|
||||
ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
|
||||
8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
|
||||
iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
|
||||
Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
|
||||
XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
|
||||
qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
|
||||
VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
|
||||
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
|
||||
jjxDah2nGN59PRbxYvnKkKj9
|
||||
-----END CERTIFICATE-----
|
||||
Loading…
Reference in New Issue
Block a user