first commit

This commit is contained in:
MooN 2025-11-08 12:20:06 +06:30
commit 2b91093910
901 changed files with 121681 additions and 0 deletions

15
.gitignore vendored Normal file
View File

@ -0,0 +1,15 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
local.properties

33
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,33 @@
# Built files
*.apk
*.aab
*.dex
*.class
# Gradle
.gradle/
build/
*/build/
**/build/
**/build/**
**/.transforms/
**/intermediates/
**/tmp/
paysdk-lib/build/
# Android Studio
*.iml
.idea/
local.properties
# Keystore
*.jks
*.keystore
# OS files
.DS_Store
Thumbs.db
# Logs
*.log

1
.idea/.name Normal file
View File

@ -0,0 +1 @@
KBZ-Master

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AndroidProjectSystem">
<option name="providerId" value="com.android.tools.idea.GradleProjectSystem" />
</component>
</project>

File diff suppressed because one or more lines are too long

6
.idea/compiler.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetSelector">
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-10-28T19:40:02.148831Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=0123456789ABCDEF" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>
</project>

13
.idea/deviceManager.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DeviceTable">
<option name="columnSorters">
<list>
<ColumnSorterState>
<option name="column" value="Name" />
<option name="order" value="ASCENDING" />
</ColumnSorterState>
</list>
</option>
</component>
</project>

28
.idea/gradle.xml Normal file
View File

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="CHOOSE_PER_TEST" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="temurin-17" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/baselib" />
<option value="$PROJECT_DIR$/ecr" />
<option value="$PROJECT_DIR$/ecr-service-lib" />
<option value="$PROJECT_DIR$/mpulib" />
<option value="$PROJECT_DIR$/nexsdk-lib" />
<option value="$PROJECT_DIR$/paylibs" />
<option value="$PROJECT_DIR$/paysdk-lib" />
<option value="$PROJECT_DIR$/qrgen-lib" />
<option value="$PROJECT_DIR$/xpay" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

10
.idea/migrations.xml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

9
.idea/misc.xml Normal file
View File

@ -0,0 +1,9 @@
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="temurin-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.intellij.execution.junit.AbstractAllInDirectoryConfigurationProducer" />
<option value="com.intellij.execution.junit.AllInPackageConfigurationProducer" />
<option value="com.intellij.execution.junit.PatternConfigurationProducer" />
<option value="com.intellij.execution.junit.TestInClassConfigurationProducer" />
<option value="com.intellij.execution.junit.UniqueIdConfigurationProducer" />
<option value="com.intellij.execution.junit.testDiscovery.JUnitTestDiscoveryConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinJUnitRunConfigurationProducer" />
<option value="org.jetbrains.kotlin.idea.junit.KotlinPatternConfigurationProducer" />
</set>
</option>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

28
app/.gitignore vendored Normal file
View File

@ -0,0 +1,28 @@
/build
# Built files
*.apk
*.aab
*.dex
*.class
# Gradle
.gradle/
build/
*/build/
# Android Studio
*.iml
.idea/
local.properties
# Keystore
*.jks
*.keystore
# OS files
.DS_Store
Thumbs.db
# Logs
*.log

210
app/build.gradle Normal file
View File

@ -0,0 +1,210 @@
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
alias(libs.plugins.hilt.android)
alias(libs.plugins.kotlin.kapt)
alias(libs.plugins.navigation)
}
android {
namespace 'com.utsmm.kbz'
compileSdk 34
defaultConfig {
applicationId "com.utsmm.kbz"
minSdk 24
targetSdk 33
versionCode 5
versionName "1.05"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// // Add CMake configuration
// externalNativeBuild {
// cmake {
// cppFlags "-std=c++14"
// }
// }
}
// Configure CMake
// externalNativeBuild {
// cmake {
// path "src/main/cpp/CMakeLists.txt"
// version "3.22.1"
// }
// }
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
}
dataBinding {
enabled = true
}
buildFeatures {
buildConfig = true
}
packagingOptions {
pickFirst '**/libnative-lib.so'
pickFirst '**/libxgd_ddi_jni.so'
}
// Configure native library loading
sourceSets {
main {
jniLibs.srcDirs = ['src/main/jniLibs']
}
}
}
// Exclude old Kotlin stdlib variants to prevent duplicate classes
configurations.all {
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk7'
exclude group: 'org.jetbrains.kotlin', module: 'kotlin-stdlib-jdk8'
}
// Configure kapt for annotation processing
kapt {
correctErrorTypes true
arguments {
arg("room.schemaLocation", "$projectDir/schemas")
arg("room.incremental", "true")
arg("room.expandProjection", "true")
}
}
dependencies {
implementation fileTree(include: ['*.jar', '*.aar'], dir: 'libs')
def nav_version = "2.3.2"
def lottieVersion = "3.5.0"
def fragment_version = "1.2.0"
def espressoVersion = "3.3.0"
def testJunitVersion = "1.1.5"
def androidXTestVersion0 = "1.2.0"
def testRunnerVersion = "1.5.2"
def testRulesVersion = "1.5.0"
// def nav_version = "2.4.1"
implementation 'com.android.support:multidex:1.0.3'
// QR
// implementation 'androidmads.library.qrgenearator:QRGenearator:1.0.5'
// QR Scan
implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
//1.2.0
implementation 'androidx.appcompat:appcompat:1.3.1' //1.2.0
implementation 'com.google.android.material:material:1.4.0' //1.2.1
implementation 'androidx.constraintlayout:constraintlayout:2.0.4' //2.0.4
implementation 'com.github.denzcoskun:ImageSlideshow:0.1.2'
//signature
implementation 'com.github.gcacace:signature-pad:1.3.1'
//lottie
implementation "com.airbnb.android:lottie:$lottieVersion"
implementation "androidx.cardview:cardview:1.0.0"
//Stetho
implementation 'com.facebook.stetho:stetho:1.5.1'
//Navigation Component
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Room dependencies
implementation "androidx.room:room-runtime:2.4.3" //2.2.5
implementation 'androidx.preference:preference:1.1.1'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
// kapt "androidx.room:room-compiler:2.4.3"
implementation "androidx.room:room-rxjava3:2.4.3"
// Hilt Dependencies
implementation libs.hilt.android
kapt libs.hilt.compiler
kapt libs.androidx.hilt.compiler
// Basic dependency injection support for javax.inject
implementation 'javax.inject:javax.inject:1'
//OKHttp 4.8.1
implementation("com.squareup.okhttp3:logging-interceptor:4.8.1")
implementation("com.squareup.okhttp3:okhttp:4.8.1")
//RxJava
implementation 'io.reactivex.rxjava3:rxandroid:3.0.0'
implementation 'io.reactivex.rxjava3:rxjava:3.0.0'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation "com.github.akarnokd:rxjava3-retrofit-adapter:3.0.0"
// ViewModel
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.2.0'
// LiveData
implementation 'androidx.lifecycle:lifecycle-livedata:2.2.0'
//base64
implementation 'commons-codec:commons-codec:1.15'
//bouncy castle
implementation 'org.bouncycastle:bcpkix-jdk15on:1.56'
implementation 'com.squareup.picasso:picasso:2.71828'
implementation 'com.sunmi:printerlibrary:1.0.23'
// implementation 'com.sunmi:sunmiui:1.1.27' //1.1.27
implementation project(path: ':ecr-service-lib')
implementation project(path: ':paylibs')
implementation project(path: ':mpulib')
implementation project(path: ':baselib')
implementation project(path: ':paysdk-lib')
implementation project(path: ':nexsdk-lib')
implementation project(path: ':qrgen-lib')
implementation project(path: ':xpay')
// implementation project(path: ':sunmiui-lib')
implementation project(path: ':qrgen-lib')
//// implementation project(path: ':samlSirius')
implementation project(path: ':ecr')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2' // 1.1.2
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0'
// Add Mockito dependency for mocking
testImplementation 'org.mockito:mockito-core:3.12.4'
androidTestImplementation 'org.mockito:mockito-android:3.12.4'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.9'
testImplementation 'org.powermock:powermock-module-junit4:2.0.9'
}

26
app/proguard-rules.pro vendored Normal file
View File

@ -0,0 +1,26 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# Keep Bouncy Castle classes for security providers
-keep class org.bouncycastle.** { *; }
-dontwarn org.bouncycastle.**

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,37 @@
{
"version": 3,
"artifactType": {
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.utsmm.kbz",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 5,
"versionName": "1.05",
"outputFile": "app-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-release.dm"
]
}
],
"minSdkVersionForDexing": 24
}

View File

@ -0,0 +1,26 @@
package com.utsmm.kbz;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.utsmm.kbz", appContext.getPackageName());
}
}

View File

@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.utsmm.kbz">
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" tools:ignore="QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.sunmi.perm.LED" />
<uses-permission android:name="com.sunmi.perm.MSR" />
<uses-permission android:name="com.sunmi.perm.ICC" />
<uses-permission android:name="com.sunmi.perm.PINPAD" />
<uses-permission android:name="com.sunmi.perm.SECURITY" />
<uses-permission android:name="com.sunmi.perm.CONTACTLESS_CARD" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- android:noHistory="true"-->
<!-- android:excludeFromRecents="true"-->
<!-- android:debuggable="true"-->
<!-- tools:ignore="HardcodedDebugMode"-->
<!-- Jun 14 , 2023 -->
<!--android:largeHeap="true"
android:hardwareAccelerated="false"-->
<application
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
android:name="com.utsmm.kbz.MyApplication"
tools:replace="android:allowBackup"
android:allowBackup="false"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar"
>
<!-- android:manageSpaceActivity="com.utsmyanmar.upos.config.UTSManageSpaceActivity"-->
<!-- <activity-->
<!-- android:screenOrientation="portrait"-->
<!-- android:name=".config.UTSManageSpaceActivity"/>-->
<activity android:name="com.utsmm.kbz.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.journeyapps.barcodescanner.CaptureActivity"
android:screenOrientation="fullSensor"
tools:replace="screenOrientation" />
<receiver android:name="com.utsmm.kbz.service.SmileAlarmReceiver" />
<service
android:name="com.utsmm.kbz.service.SmileSettleService"
android:enabled="true"
android:exported="false">
<meta-data
android:name="androidx.hilt.EntryPoint"
android:value="androidx.hilt.lifecycle.HiltService" />
</service>
</application>
</manifest>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"nm":"Comp 1","ddd":0,"h":500,"w":500,"meta":{"g":"@lottiefiles/toolkit-js 0.25.8"},"layers":[{"ty":4,"nm":"Shape Layer 2","sr":1,"st":0,"op":644.000010477231,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":99,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":4,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[392,392],"ix":2}},{"ty":"tm","bm":0,"hd":false,"mn":"ADBE Vector Filter - Trim","nm":"Trim Paths 1","ix":2,"e":{"a":1,"k":[{"o":{"x":0.48,"y":0.04},"i":{"x":0.52,"y":0.96},"s":[1],"t":0},{"s":[24],"t":8.91800014508687}],"ix":2},"o":{"a":1,"k":[{"o":{"x":0.48,"y":0.04},"i":{"x":0.667,"y":1},"s":[-2],"t":0},{"o":{"x":0.48,"y":0.04},"i":{"x":0.52,"y":0.96},"s":[645],"t":20.798},{"o":{"x":0.48,"y":0.04},"i":{"x":0.52,"y":0.96},"s":[627],"t":30.399},{"s":[636],"t":40.0000006507597}],"ix":3},"s":{"a":1,"k":[{"o":{"x":0.48,"y":0.04},"i":{"x":0.52,"y":0.96},"s":[0],"t":13.839},{"s":[23],"t":20.7980003383625}],"ix":1},"m":1},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":2,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":28,"ix":5},"c":{"a":0,"k":[0.1725,0.2431,0.3137],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[1,0.5765,0.3882],"ix":4},"r":1,"o":{"a":0,"k":0,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":644.000010477231,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[250,250,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":36,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[392,392],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":36,"ix":5},"c":{"a":0,"k":[0.949,0.9686,0.9843],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[1,1,1],"ix":4},"r":1,"o":{"a":0,"k":0,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2}],"v":"5.5.8","fr":30.0130004882813,"op":42.0000006832977,"ip":0,"assets":[]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,499 @@
package com.utsmm.kbz;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController;
import androidx.navigation.NavDestination;
import androidx.navigation.fragment.NavHostFragment;
import androidx.navigation.ui.AppBarConfiguration;
import androidx.navigation.ui.NavigationUI;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.Toast;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.navigation.NavigationView;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.baselib.ui.AnimationDialog;
import com.utsmyanmar.checkxread.sdk.NexGoSDK;
import com.utsmyanmar.ecr.ECRHelper;
import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.databinding.ActivityMainNewBinding;
import com.utsmm.kbz.service.SmileAlarmReceiver;
import com.utsmm.kbz.ui.core_ui.InputPasswordFragment;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.navigation.NaviAdminFragment;
import com.utsmm.kbz.ui.navigation.NaviMainFragment;
import com.utsmm.kbz.ui.navigation.NaviSetupFragment;
import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmm.kbz.util.tms.TMSUtil;
import java.util.Calendar;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
/**
* Main Activity handling application navigation and fragment interactions
*/
@AndroidEntryPoint
public class MainActivity extends AppCompatActivity implements
NaviMainFragment.OnFragmentInteractionListener,
InputPasswordFragment.OnFragmentInteractionListener,
NaviSetupFragment.OnFragmentInteractionListener,
NaviAdminFragment.OnFragmentInteractionListener {
private static final String TAG = MainActivity.class.getSimpleName();
// ViewModels
private SharedViewModel sharedViewModel;
// UI Components
private ActivityMainNewBinding binding;
private DrawerLayout drawerLayout;
private NavigationView navigationView;
private NavController navController;
private ActionBarDrawerToggle drawerToggle;
private AnimationDialog animationDialog;
// Navigation
private AppBarConfiguration appBarConfiguration;
// Resource management
private final CompositeDisposable compositeDisposable = new CompositeDisposable();
// Set of fragment IDs that should handle back press specially
private final Set<Integer> specialBackHandlingFragments = new HashSet<>();
@Inject
Repository repository;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Keep screen on
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
// Initialize ViewModels
initViewModels();
// Setup UI components
setupUI();
// Setup navigation
setupNavigation();
// Setup toolbar navigation
setupToolbarNavigation();
// Initialize fragment in navigation drawer
initNavigationDrawerFragment();
// Set up daily alarm if needed
// setupAlarmIfNeeded();
// Generate app version
generateVersionInfo();
// Retrieve initial data
retrieveData();
// Initialize special back handling fragments
initSpecialBackHandlingFragments();
}
private void initViewModels() {
sharedViewModel = new ViewModelProvider(this).get(SharedViewModel.class);
}
private void setupUI() {
binding = DataBindingUtil.setContentView(this, R.layout.activity_main_new);
binding.setSharedViewModel(sharedViewModel);
binding.setLifecycleOwner(this);
MaterialToolbar toolbar = binding.toolbar;
setSupportActionBar(toolbar);
drawerLayout = binding.drawerLayout;
navigationView = binding.navView;
}
private void setupNavigation() {
NavHostFragment navHostFragment =
(NavHostFragment) getSupportFragmentManager().findFragmentById(R.id.nav_host_fragment);
if (navHostFragment != null) {
navController = navHostFragment.getNavController();
// Define top-level destinations
int[] topLevelDestinations = {
R.id.menu_function, R.id.menu_version, R.id.menu_logout,
R.id.menu_exit, R.id.nav_main
};
appBarConfiguration = new AppBarConfiguration.Builder(topLevelDestinations)
.setOpenableLayout(drawerLayout)
.build();
// Setup navigation with UI components
NavigationUI.setupWithNavController(navigationView, navController);
NavigationUI.setupWithNavController(binding.toolbar, navController, appBarConfiguration);
// Setup drawer toggle
drawerToggle = new ActionBarDrawerToggle(
this, drawerLayout, binding.toolbar,
R.string.nav_app_bar_open_drawer_description,
R.string.navigation_drawer_close
);
drawerToggle.syncState();
}
}
private void setupToolbarNavigation() {
binding.toolbar.setNavigationOnClickListener(v -> handleNavigationClick());
}
private void handleNavigationClick() {
try {
NavDestination currentDestination = navController.getCurrentDestination();
if (currentDestination != null) {
int currentId = currentDestination.getId();
if (currentId == R.id.nav_main) {
openDrawer();
} else if (isSpecialBackHandlingFragment(currentId)) {
checkForInsertedCard();
} else {
handleRegularBackPress();
}
}
} catch (Exception e) {
LogUtil.e(TAG, "Navigation error: " + e.getMessage());
}
}
private void handleRegularBackPress() {
if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) {
finishECR();
}
onBackPressed();
}
private void initSpecialBackHandlingFragments() {
specialBackHandlingFragments.add(R.id.inputAmountFragment);
specialBackHandlingFragments.add(R.id.inputPasswordFragment);
specialBackHandlingFragments.add(R.id.selectHostFragment);
}
private boolean isSpecialBackHandlingFragment(int fragmentId) {
return specialBackHandlingFragments.contains(fragmentId);
}
private void initNavigationDrawerFragment() {
getSupportFragmentManager().beginTransaction()
.replace(R.id.navi_fragment, new NaviMainFragment())
.commit();
}
private void setupAlarmIfNeeded() {
if (!SystemParamsOperation.getInstance().isLoadedOnce()) {
setupDailyAlarm();
SystemParamsOperation.getInstance().setLoadedOnce(true);
}
}
private void setupDailyAlarm() {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 50);
calendar.set(Calendar.SECOND, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
// Set the alarm to trigger at specified time every day
if (alarmManager != null) {
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this,
0,
new Intent(this, SmileAlarmReceiver.class),
PendingIntent.FLAG_UPDATE_CURRENT
);
alarmManager.setRepeating(
AlarmManager.RTC_WAKEUP,
calendar.getTimeInMillis(),
AlarmManager.INTERVAL_DAY,
pendingIntent
);
}
}
/**
* Shows an animation dialog with a message
*/
protected void showAnimationDialog(String msg) {
runOnUiThread(() -> {
if (animationDialog == null) {
animationDialog = new AnimationDialog(this, msg);
} else {
animationDialog.setMessage(msg);
}
if (!animationDialog.isShowing()) {
animationDialog.show();
}
});
}
/**
* Dismisses the animation dialog if showing
*/
protected void dismissAnimationDialog() {
runOnUiThread(() -> {
if (animationDialog != null && animationDialog.isShowing()) {
animationDialog.dismiss();
}
});
}
/**
* Checks if a card is inserted and handles accordingly
*/
private void checkForInsertedCard() {
Disposable disposable = Observable.create((ObservableOnSubscribe<Boolean>) emitter -> {
try {
while (NexGoSDK.getInstance().checkCardExist() == 2) {
emitter.onNext(true);
}
emitter.onComplete();
} catch (Exception e) {
emitter.onError(e);
}
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.throttleLast(2, TimeUnit.SECONDS)
.subscribe(
cardInserted -> {
if (cardInserted) {
dismissAnimationDialog();
showAnimationDialog(getString(R.string.txt_removed_card));
}
},
error -> LogUtil.e(TAG, "Error checking card: " + error.getMessage()),
() -> {
dismissAnimationDialog();
onBackPressed();
}
);
compositeDisposable.add(disposable);
}
/**
* Generates and stores the app version
*/
private void generateVersionInfo() {
try {
String finalVersion = TMSUtil.getInstance().generateFinalVersion();
SystemParamsOperation.getInstance().setFinalVersion(finalVersion);
} catch (Exception e) {
LogUtil.e(TAG, "Error generating version: " + e.getMessage());
}
}
/**
* Retrieves initial data from repository
*/
private void retrieveData() {
Disposable disposable = repository.getAllEmvData()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
lists -> LogUtil.d(Constant.TAG, "Size of EMV data: " + lists.size()),
error -> LogUtil.e(Constant.TAG, "Error retrieving EMV data: " + error.getMessage()),
() -> LogUtil.d(Constant.TAG, "EMV data retrieval complete")
);
compositeDisposable.add(disposable);
}
/**
* Finishes ECR process
*/
private void finishECR() {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getString(R.string.txt_cancel_trans));
sharedViewModel.isEcrFinished.postValue(true);
}
/**
* Opens the navigation drawer
*/
public void openDrawer() {
drawerLayout.openDrawer(Gravity.LEFT);
}
/**
* Closes the navigation drawer
*/
public void closeDrawer() {
drawerLayout.closeDrawer(Gravity.LEFT);
}
/**
* Changes the fragment in the navigation drawer
*/
public void changeNavigationFragment(androidx.fragment.app.Fragment fragment) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.navi_fragment, fragment)
.commit();
}
@Override
public void onResume() {
super.onResume();
SystemParamsOperation.getInstance().setSetupEcr(false);
SystemParamsOperation.getInstance().setDownloadedParams(false);
}
@Override
public void onDestroy() {
super.onDestroy();
// Clean up RxJava disposables
compositeDisposable.clear();
// Reset screen mode
// Disconnect ECR
ECRHelper.INSTANCE.disconnect();
}
// Navigation drawer interaction listeners
@Override
public void onClickSetup() {
closeDrawer();
sharedViewModel.transactionsType.postValue(TransactionsType.SETTING);
navController.navigate(R.id.inputPasswordFragment);
}
@Override
public void onClickFunction() {
closeDrawer();
sharedViewModel.transactionsType.postValue(TransactionsType.FUNCTION);
navController.navigate(R.id.inputPasswordFragment);
}
@Override
public void onClickVersion() {
closeDrawer();
navController.navigate(R.id.action_nav_main_to_versionFragment);
}
@Override
public void onClickExit() {
finishAffinity();
}
@Override
public void onSuccess() {
openDrawer();
changeNavigationFragment(new NaviSetupFragment());
}
@Override
public void onClickBackSetup() {
changeNavigationFragment(new NaviMainFragment());
}
@Override
public void onClickAdmin() {
changeNavigationFragment(new NaviAdminFragment());
}
@Override
public void onClickClearBatch() {
performAdminAction(
TransactionsType.CLEAR_BATCH,
TransMenu.CLEAR_BATCH,
R.id.inputPasswordFragment
);
}
@Override
public void onClickClearReversal() {
performAdminAction(
TransactionsType.CLEAR_REVERSAL,
TransMenu.CLEAR_REVERSAL,
R.id.inputPasswordFragment
);
}
private void performAdminAction(TransactionsType transType, TransMenu transMenu, int destinationId) {
changeNavigationFragment(new NaviMainFragment());
closeDrawer();
sharedViewModel.transactionsType.postValue(transType);
sharedViewModel.setTransMenu(transMenu);
navController.navigate(destinationId);
}
@Override
public void onClickEditStan() {
changeNavigationFragment(new NaviMainFragment());
closeDrawer();
navController.navigate(R.id.editStanFragment);
}
@Override
public void onClickBackAdmin() {
changeNavigationFragment(new NaviSetupFragment());
}
@Override
public void onClickTWKLogin() {
showToast(getString(R.string.txt_twk_login));
}
@Override
public void onClickDestroyAllKeys() {
showToast(getString(R.string.txt_destroy_all_Keys));
}
@Override
public void onClickPrintKeyStatus() {
PrintXReceipt.getInstance().printKeyStatus();
}
private void showToast(String message) {
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show();
}
}

View File

@ -0,0 +1,926 @@
package com.utsmm.kbz;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.RemoteException;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import com.denzcoskun.imageslider.ImageSlider;
import com.denzcoskun.imageslider.constants.ScaleTypes;
import com.denzcoskun.imageslider.models.SlideModel;
import com.pos.connection.bridge.binder.ECRConstant;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.DialogCallback;
import com.utsmyanmar.baselib.util.TerminalUtil;
import com.utsmyanmar.checkxread.sdk.NexGoSDK;
import com.utsmyanmar.ecr.ECRHelper;
import com.utsmyanmar.ecr.ECRProcess;
import com.utsmyanmar.ecr.data.ResultOf;
import com.utsmyanmar.ecr.data.model.Transactions;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.print.PrintHelper;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.CurrencyType;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.config.data.model.ValidityStatus;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TMSProcessViewModel;
import com.utsmm.kbz.util.Connectivity;
import com.utsmm.kbz.util.dialog.AlertXDialog;
import com.utsmm.kbz.util.enums.SettlementType;
import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmm.kbz.util.ProcessCode;
import com.utsmm.kbz.util.ecr.ECRConnectionStatus;
import com.utsmm.kbz.util.tms.TMSUtil;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import com.utsmyanmar.paylibs.utils.LogUtil;
@AndroidEntryPoint
public class MainFragment extends DataBindingFragment {
private static final String TAG = MainFragment.class.getSimpleName();
private SharedViewModel sharedViewModel;
private MainViewModel mainViewModel;
private TMSProcessViewModel tmsProcessViewModel;
private int routeId;
private ImageSlider imgSlider;
private final ArrayList<SlideModel> imgList = new ArrayList<>();
private Observer<PayDetail> observeLastTrans;
private PayDetail lastPay;
@Inject
EmvParamOperation emvParamOperation;
@Override
protected int currentId() {
return R.id.nav_main;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
tmsProcessViewModel = getFragmentScopeViewModel(TMSProcessViewModel.class);
}
@Override
public void onResume() {
super.onResume();
setNavBarIconWithTitle(getResourceString(R.string.menu_dashboard));
// logcat is resetting cuz of this setup , because it is using serial port
if(SystemParamsOperation.getInstance().getECRStatus()){
// setUpECR();
}
sharedViewModel.isEcrFinished.postValue(true);
sharedViewModel.isEcr.postValue(false);
CurrencyType currencyType = SystemParamsOperation.getInstance().getCurrencyType();
sharedViewModel.set_currencyText(currencyType.name);
sharedViewModel.setAmountExist(false);
sharedViewModel.setCardDataExist(false);
sharedViewModel.setTransMenu(null);
updateButtonStatus();
delayFunctionCall(this::checkTerminalStatus);
delayFunctionCall(()-> {
NexGoSDK.getInstance().cancelCheckCard();
NexGoSDK.getInstance().closeReader();
});
}
private void checkTerminalStatus() {
if (!SystemParamsOperation.getInstance().isActive()) {
routeId = R.id.action_nav_main_to_disabledTerminalFragment;
safeNavigateToRouteId();
}
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(SystemParamsOperation.getInstance().isAlertSound()) {
delayFunctionCall(this::checkPrinter);
}
delayFunctionCall(this::checkDownload);
mainViewModel.observeSettlementPOS();
}
private void checkDownload() {
Log.d(TAG, "Calling from Check download: ");
if (!SystemParamsOperation.getInstance().isDownloadedParams() && SystemParamsOperation.getInstance().isActive() && tmsProcessViewModel.getIsCalled().getValue() == null) {
tmsProcessViewModel.setIsCalled(true);
routeId = R.id.action_nav_main_to_TMSProcessFragment;
safeNavigateToRouteId();
}
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
imgSlider = mBinding.getRoot().findViewById(R.id.image_slider);
setUpCarouselImages();
if(TextUtils.equals(SystemParamsOperation.getInstance().getCurrentSerialNum(),"000001")) {
setPreviousTraceNum();
}
sharedViewModel.setManualEntryStatus(SystemParamsOperation.getInstance().getManualEntryStatus());
}
/*
* @param
*
* value - 0 = AID, 1 = CAPK
* */
private void queryAidCAPKList(int value) {
List<String> aidlist = new ArrayList<>();
try {
int result = MyApplication.getInstance().mEMVOptV2.queryAidCapkList(value,aidlist);
LogUtil.d(TAG,"Query "+(value == 0?"AID":"CAPK")+" List result:"+result);
if(result == 0) {
for (String aid : aidlist) {
LogUtil.d(TAG,(value == 0?"AID:":"CAPK:")+aid);
}
}
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
private void setPreviousTraceNum() {
/* this function only needed after application update is performed */
mainViewModel.lastTrans.observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
if(payDetail == null) {
return;
}
SystemParamsOperation.getInstance().saveSerialNumber(payDetail.getVoucherNo());
SystemParamsOperation.getInstance().saveInvoiceNumber(payDetail.getInvoiceNo());
SystemParamsOperation.getInstance().saveBatchNumber(payDetail.getBatchNo());
}
});
}
private void setUpECR() {
if (checkECRServiceAppExistOrNot()) {
if(!SystemParamsOperation.getInstance().isSetupEcr()){
initECR();
delayFunctionCall(this::createECRInstance);
SystemParamsOperation.getInstance().setSetupEcr(true);
onReceivedEcrCommand();
} else {
onReceivedEcrCommand();
}
} else {
Toast.makeText(getContext(), "ECR Service Not Found!", Toast.LENGTH_SHORT).show();
}
}
private void createECRInstance() {
//
// currently will test with Bluetooth , afterward will switch to VSP mode
if(SystemParamsOperation.getInstance().isBluetoothMode()) {
Bundle bundle = new Bundle();
bundle.putString(ECRConstant.Configuration.MODE, ECRConstant.Mode.Bluetooth);
bundle.putString(ECRConstant.Configuration.TYPE, ECRConstant.Type.MASTER);
bundle.putString(ECRConstant.Configuration.BLUETOOTH_MAC_ADDRESS, "");
// mainViewModel.ecrConnectionStatus.setValue(ECRConnectionStatus.CREATED);
ECRHelper.INSTANCE.connect(bundle);
showShortToast("ECR service is created!");
} else {
Bundle bundle = new Bundle();
bundle.putString(ECRConstant.Configuration.MODE, ECRConstant.Mode.VSP);
bundle.putString(ECRConstant.Configuration.TYPE, ECRConstant.Type.MASTER); // MASTER
ECRHelper.INSTANCE.connect(bundle);
// mainViewModel.ecrConnectionStatus.setValue(ECRConnectionStatus.CREATED);
showShortToast("ECR service is created!");
}
}
private void updateButtonStatus() {
mainViewModel.settlementStatus.setValue(SystemParamsOperation.getInstance().getSettlementStatus());
mainViewModel.kPayStatus.setValue(SystemParamsOperation.getInstance().getWavePayStatus());
}
private void setUpCarouselImages() {
String imgUrls = SystemParamsOperation.getInstance().getCarouselUrls();
imgList.clear();
if(imgUrls == null || imgUrls.isEmpty() ) {
String defaultUrl = getResourceString(R.string.txt_default_carousel_img_url);
imgList.add(new SlideModel(defaultUrl,"", ScaleTypes.CENTER_CROP));
imgSlider.setImageList(imgList);
return;
}
ArrayList<String> urls = TMSUtil.getInstance().convertToArray(imgUrls);
for(String url : urls) {
imgList.add(new SlideModel(url.trim(),"", ScaleTypes.CENTER_CROP));
}
imgSlider.setImageList(imgList);
}
private boolean checkECRServiceAppExistOrNot() {
PackageInfo packageInfo;
try {
packageInfo = requireActivity().getPackageManager().getPackageInfo("com.pos.ecr.service", 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return false;
}
return packageInfo != null;
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_dashboard_screen, BR.shareViewModel, sharedViewModel)
.addBindingParam(BR.mainViewModel, mainViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
private void checkPrinter() {
if (PrintHelper.getInstance().paperRollStatus() == 2) {
}
else if (PrintHelper.getInstance().paperRollStatus() == 4) {
mainViewModel.playAtOnce.setValue(false);
showPrinterAlertDialog(getResourceString(R.string.txt_paper_roll_not_ready), new DialogCallback() {
@Override
public void onClickCancel() {
dismissPrinterAlertDialog();
}
@Override
public void onClickRetry() {
dismissPrinterAlertDialog();
checkPrinter();
}
});
// startSound(getResourceString(R.string.txt_audio_printer_alert));
} else if (PrintHelper.getInstance().paperRollStatus() == 1) {
if( mainViewModel.playAtOnce.getValue() != null && !mainViewModel.playAtOnce.getValue()) {
startSound(getResourceString(R.string.txt_audio_paper_ready_alert));
mainViewModel.playAtOnce.setValue(true);
}
} else if (PrintHelper.getInstance().paperRollStatus() == 0) {
LogUtil.d(TAG,"Printer not found!");
// showDeclineDialog(getResourceString(R.string.txt_alert_printer_not_found));
}
}
private void isRouteValidAndNavigateToRoute(int routeId) {
if (Objects.requireNonNull(getNavController(Constants.NAV_HOST_ID).getCurrentDestination()).getId() == R.id.nav_main) {
getNavController(Constants.NAV_HOST_ID).navigate(routeId);
} else {
sharedViewModel.isEcr.postValue(false);
sharedViewModel.isEcrFinished.postValue(true);
ECRHelper.INSTANCE.send(getResourceString(R.string.txt_finish_current_process).getBytes());
showDeclineDialog(getResourceString(R.string.txt_finish_current_process));
}
}
/**
* init ECR service
*/
private void initECR() {
ECRHelper.INSTANCE.registerECRListener();
ECRHelper.INSTANCE.setOnBindSuccess(() -> {
ECRHelper.INSTANCE.registerECRListener();
LogUtil.d(TAG, "on bind success!");
return null;
});
ECRHelper.INSTANCE.setOnBindFailure(() -> {
LogUtil.d(TAG, "on bind failure!");
return null;
});
ECRHelper.INSTANCE.setOnECRConnected(() -> {
delayFunctionCall(() -> mainViewModel.ecrConnectionStatus.postValue(ECRConnectionStatus.CONNECTED));
LogUtil.d(TAG, "On ECR Connected!");
return null;
});
ECRHelper.INSTANCE.setOnECRDisconnected((integer, s) -> {
delayFunctionCall(() -> mainViewModel.ecrConnectionStatus.postValue(ECRConnectionStatus.DISCONNECTED));
LogUtil.d(TAG, "On ECR Disconnected! Code:" + integer + ":Msg:" + s);
return null;
});
ECRHelper.INSTANCE.bindECRService();
LogUtil.d(TAG,"Bind ECR Service successfully!");
}
private void onReceivedEcrCommand() {
ECRHelper.INSTANCE.setOnECRReceive(bytes -> {
String msg = new String(bytes, StandardCharsets.UTF_8);
LogUtil.d(TAG, "Received : " + msg);
if (sharedViewModel.isEcrFinished.getValue() != null) {
if (sharedViewModel.isEcrFinished.getValue()) {
ECRAction(msg);
}
} else {
ECRAction(msg);
}
return null;
});
}
/**
* @param msg ECR Transaction Type
*/
private void ECRAction(String msg) {
// LogUtil.d(TAG, "ECR msg here : " + msg);
String ecrKey = SystemParamsOperation.getInstance().getEcrKey().toUpperCase();
String pkgName = BuildConfig.APPLICATION_ID;
String serialNo = TerminalUtil.getInstance().getSerialNo();
ResultOf<Transactions> result = ECRProcess.INSTANCE.parseECRRequest(ecrKey,pkgName,serialNo,msg);
if (result instanceof ResultOf.Success) {
Transactions trans = ((ResultOf.Success<Transactions>) result).getValue();
CoreUtils.getInstance(sharedViewModel).logTrans(trans);
sharedViewModel.ecrCMD.postValue(trans.getCMD());
sharedViewModel.ecrTrans.postValue(trans);
switch (Objects.requireNonNull(trans.getCMD())) {
case ECHO:
CoreUtils.getInstance(sharedViewModel).setUpECREchoTest();
break;
case SALE:
if (CoreUtils.getInstance(sharedViewModel).setUpECRSale(trans)) {
delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment));
}
break;
case VOID:
if(!SystemParamsOperation.getInstance().getVoidStatus()) {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(trans,"Void is disabled!");
return;
}
if (CoreUtils.getInstance(sharedViewModel).setUpECRVoid(trans)) {
delayFunctionCall(() -> {
if(Objects.requireNonNull(getNavController(Constants.NAV_HOST_ID).getCurrentDestination()).getId() == R.id.nav_main) {
setToolBarTitle(getResourceString(R.string.menu_sale_void));
}
isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_inputPasswordFragment);
});
}
break;
case CASH_ADVANCE: {
if (CoreUtils.getInstance(sharedViewModel).setUpECRCashAdvance(trans)) {
delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_cardWaitingFragment));
}
break;
}
case QR_SALE: {
if (CoreUtils.getInstance(sharedViewModel).setUpECRQR(trans)) {
delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_QRConnectingFragment));
}
break;
}
case SETTLEMENT: {
if(!SystemParamsOperation.getInstance().getSettlementStatus()) {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(trans,"Settlement is disabled!");
return;
}
CoreUtils.getInstance(sharedViewModel).setUpECRSettlement();
delayFunctionCall(() -> isRouteValidAndNavigateToRoute(R.id.action_nav_main_to_inputPasswordFragment));
break;
}
default:
showDeclineDialog("No Action found on \n" + trans.getCMD());
break;
}
} else {
String errorMsg = ((ResultOf.Failure) result).getMessage();
showDeclineDialog("No Action found on \n" + errorMsg);
}
}
private void navigateToAmount() {
routeId = R.id.action_nav_main_to_inputAmountFragment;
safeNavigateToRouteId();
}
private void processBatch() {
calculateLastTransaction();
mainViewModel.observeSettlementPOS();
observeLastTrans = payDetail -> {
if(payDetail == null) {
return;
}
// SystemParamsOperation.getInstance().saveSerialNumber(payDetail.getVoucherNo());
// SystemParamsOperation.getInstance().saveInvoiceNumber(payDetail.getInvoiceNo());
if(lastPay != null) {
Date lastPayDate = POSUtil.getInstance().getDateByString(lastPay.getTransDate());
Date observePayDate = POSUtil.getInstance().getDateByString(payDetail.getTransDate());
if(lastPayDate.compareTo(observePayDate) < 0) {
payDetail = lastPay;
}
}
// LogUtil.d(TAG,"TransDetail :"+payDetail.getTransType() + "- Trans Time :"+payDetail.getTransDate());
if(payDetail.getTransactionType() == TransactionsType.SETTLEMENT.value){
return;
}
/*
* saving for api post request, to send in next time.
* */
SystemParamsOperation.getInstance().setLastTransTime(String.valueOf(payDetail.getTransNum()));
SystemParamsOperation.getInstance().setLastTransName(payDetail.getTransType());
String lastTransDate = payDetail.getTransDate();
String lastTransTime = payDetail.getTransTime();
Date today = POSUtil.getInstance().getCurrentDate();
Date transDate;
Date current = new Date(System.currentTimeMillis());
String configTimer = SystemParamsOperation.getInstance().getClearBatchTime();
// LogUtil.d(TAG,"Config Time :" + configTimer);
String configTime = "23:00";
int configDay = 10;
String configRawDay = SystemParamsOperation.getInstance().getClearBatchDay();
if(configRawDay != null && !configRawDay.trim().isEmpty()) {
try {
configDay = Integer.parseInt(configRawDay);
} catch (Exception e) {
e.printStackTrace();
}
}
if(configTimer != null && !configTimer.trim().isEmpty() && checkValidTime(configTimer.trim())) {
configTime = configTimer.trim();
}
Date configDateTime = POSUtil.getInstance().getDateTime(configTime);
Date yesterdayConfigDateTime = POSUtil.getInstance().getYesterdayConfigDateTime(configTime);
transDate = POSUtil.getInstance().getDateByString(lastTransDate);
Date yesterdayDate = POSUtil.getInstance().getYesterdayDate();
if(today.compareTo(transDate) == 0) {
// LogUtil.d(TAG,"Last Trans is Today!");
// LogUtil.d(TAG,"date current :!"+current);
// LogUtil.d(TAG,"date config :!"+configDateTime);
// Today
if(current.compareTo(configDateTime) > 0) {
// clear batch and force update param
// LogUtil.d(TAG,"Last Trans is Today! Config time is passed!");
// if (!SystemParamsOperation.getInstance().isClearBatch()) {
if (checkSyncTrans() || !SystemParamsOperation.getInstance().isClearBatch() ) {
// LogUtil.d(TAG,"Clearing....");
if(!SystemParamsOperation.getInstance().getSettlementStatus()) {
clearBatchAndDownload(configDay,payDetail);
}
}
} else {
// LogUtil.d(TAG,"Last Trans is Today! Config time is not passed yet.....");
SystemParamsOperation.getInstance().setClearBatch(false);
}
} else {
// LogUtil.d(TAG,"Last Trans is Before Today!");
Date yest;
if(configTime.equals("00:00")) {
yest = configDateTime;
} else {
yest = yesterdayConfigDateTime;
}
Date lastTransDateTime = POSUtil.getInstance().getDateByTransDateTime(lastTransDate,lastTransTime);
// LogUtil.d(TAG,"Compare Result : "+lastTransDateTime.compareTo(yest));
if(yest.compareTo(lastTransDateTime) < 0) {
// LogUtil.d(TAG,"Trans is yesterday, but after config time, no action!");
} else {
// LogUtil.d(TAG,"Trans is yesterday, before config time,");
// if(!checkSyncTrans()) {
// LogUtil.d(TAG,"Clearing....");
if(!SystemParamsOperation.getInstance().getSettlementStatus()) {
clearBatchAndDownload(configDay,payDetail);
}
// }
}
}
};
if(mainViewModel.lastTrans.hasActiveObservers()) {
mainViewModel.lastTrans.removeObserver(observeLastTrans);
}
mainViewModel.lastTrans.observe(getViewLifecycleOwner(),observeLastTrans);
}
private void calculateLastTransaction() {
mainViewModel.allTrans.observe(getViewLifecycleOwner(), new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
if(payDetails == null || payDetails.isEmpty()) {
return;
}
PayDetail tempPay = payDetails.get(0);
for (int i = 0; i < payDetails.size() ; i++) {
Date tempDate = POSUtil.getInstance().getDateByString(tempPay.getTransDate());
Date indexDate = POSUtil.getInstance().getDateByString(payDetails.get(i).getTransDate());
if(tempDate.compareTo(indexDate) > 0) {
// if before
tempPay = payDetails.get(i);
}
}
lastPay = tempPay;
// LogUtil.d(TAG,"Transaction Name : "+tempPay.getTransType());
// LogUtil.d(TAG,"Transaction Type : "+tempPay.getTransactionType());
// LogUtil.d(TAG,"Transaction Amount : "+tempPay.getAmount());
// LogUtil.d(TAG,"Transaction Date/Time : "+tempPay.getTransDate()+"/"+tempPay.getTransTime());
// LogUtil.d(TAG,"RRN/Trace : "+tempPay.getReferNo()+"/"+tempPay.getVoucherNo());
// LogUtil.d(TAG,"Transaction is canceled : "+tempPay.isCanceled());
// LogUtil.d(TAG,"Transaction settlement config : "+tempPay.isSettlementEnabled());
// LogUtil.d(TAG,"----------------------------------------------------------");
}
});
}
private boolean checkSyncTrans() {
String transDateString = SystemParamsOperation.getInstance().getSyncTransDate();
Date today = POSUtil.getInstance().getCurrentDate();
if(transDateString == null || transDateString.isEmpty()) {
return true;
}
Date transDate = POSUtil.getInstance().getDateByString(transDateString);
return today.compareTo(transDate) == 0;
}
private void clearBatchAndDownload(int configDay,PayDetail payDetail) {
Date yesterday = POSUtil.getInstance().getYesterdayDate();
Date lastInputDay = POSUtil.getInstance().getLastInputDay(configDay);
mainViewModel.settlementPOS.observe(getViewLifecycleOwner(), list -> {
Date transDate;
if(list == null || list.size() == 0) {
return;
}
for (PayDetail pay:list) {
/*
* To Hold One day transaction!
* */
transDate = POSUtil.getInstance().getDateByString(pay.getTransDate());
if (pay.getTransactionType() == TransactionsType.SALE.value) {
if(lastInputDay.compareTo(transDate) > 0) {
mainViewModel.deletePayDetail(pay);
}
} else {
if(yesterday.compareTo(transDate) > 0 ) {
mainViewModel.deletePayDetail(pay);
}
}
}
});
mainViewModel.deleteTrans.observe(getViewLifecycleOwner(), lists -> {
Date transDate;
if(lists == null || lists.size() == 0) {
return;
}
for (PayDetail pay:lists) {
/*
* To Hold One day transaction!
* */
transDate = POSUtil.getInstance().getDateByString(pay.getTransDate());
// LogUtil.d(TAG,"Trans Type : "+pay.getTransType()+"<=====> Trans Date :"+pay.getTransDate());
// LogUtil.d(TAG,"Yesterday Date: "+yesterday.toString());
// LogUtil.d(TAG,"Compare result :"+yesterday.compareTo(transDate));
if(yesterday.compareTo(transDate) > 0) {
mainViewModel.deletePayDetail(pay);
}
}
});
mainViewModel.preAuthTrans.observe(getViewLifecycleOwner(), lists -> {
Date transDate;
if(lists == null || lists.size() == 0) {
return;
}
for (PayDetail pay:lists) {
transDate = POSUtil.getInstance().getDateByString(pay.getTransDate());
if (lastInputDay.compareTo(transDate) > 0) {
mainViewModel.deletePayDetail(pay);
}
}
});
/*
*
* Need to think about his problem .... Nov 7, 2024
* */
if(!SystemParamsOperation.getInstance().isClearBatch()) {
// downloadParams(payDetail.getTransType(),String.valueOf(payDetail.getTransNum()),TMSUpdate.UPDATE,false);
}
}
// private void generateMockPreAuth() {
// String transDate = "01/03/24";
// String transTime = "12:27:30";
// TradeData tradeData = MockData.getInstance().generateMockDataWithTime(TransactionsType.PRE_AUTH_SALE, AidlConstantsV2.CardType.IC.getValue(),transDate,transTime);
// PayDetail payDetail = tradeData.getPayDetail();
// sharedViewModel.insertPayDetail(payDetail);
// LogUtil.d(TAG,"------------------- Inserted Mocked Data ------------------");
// LogUtil.d(TAG,"trans date : "+payDetail.getTransDate() +"- Trans Time: "+payDetail.getTransTime());
// }
public class ClickEvent {
public void onClickTrans() {
if (!Connectivity.isConnectedWifi(getContext()) && !Connectivity.isConnectedMobile(getContext())) {
showSingleInfoDialog(getResourceString(R.string.txt_please_enable_internet));
} else if (TMSUtil.getInstance().checkParams().isStatus() == ValidityStatus.FAILURE) {
showDeclineDialog(getResourceString(R.string.txt_please_download_config)+"\n"+TMSUtil.getInstance().checkParams().getMessage());
} else if(SystemParamsOperation.getInstance().isNeedSettlement()) {
AlertXDialog.getInstance().showDialog(requireContext(), getResourceString(R.string.title_need_settle), getResourceString(R.string.txt_do_you_want_to_continue), () -> {
int mainToDashboard = R.id.action_nav_main_to_dashboardTransFragment;
safeRouteTo(R.id.nav_main,mainToDashboard,Constants.NAV_HOST_ID);
});
} else {
int mainToDashboard = R.id.action_nav_main_to_dashboardTransFragment;
safeRouteTo(R.id.nav_main,mainToDashboard,Constants.NAV_HOST_ID);
}
}
public void onClickCard() {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (TMSUtil.getInstance().checkParams().isStatus() == ValidityStatus.FAILURE) {
showDeclineDialog(getResourceString(R.string.txt_please_download_config)+"\n"+TMSUtil.getInstance().checkParams().getMessage());
} else if (!Connectivity.isConnectedWifi(getContext()) && !Connectivity.isConnectedMobile(getContext())) {
showSingleInfoDialog(getResourceString(R.string.txt_please_enable_internet));
} else if(SystemParamsOperation.getInstance().isNeedSettlement()) {
AlertXDialog.getInstance().showDialog(requireContext(), getResourceString(R.string.title_need_settle), getResourceString(R.string.txt_do_you_want_to_continue), () -> {
processBatch();
sharedViewModel.transactionsType.setValue(TransactionsType.SALE);
sharedViewModel.processCode.postValue(ProcessCode.SALE_PURCHASE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT);
navigateToAmount();
});
} else {
processBatch();
sharedViewModel.transactionsType.setValue(TransactionsType.SALE);
sharedViewModel.processCode.postValue(ProcessCode.SALE_PURCHASE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT);
navigateToAmount();
}
}
public void onClickQRPay() {
String mmqrIp = SystemParamsOperation.getInstance().getSecHostIpAddress();
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
}
// else if (TMSUtil.getInstance().checkSecHostParams().isStatus() == ValidityStatus.FAILURE) {
// showDeclineDialog(getResourceString(R.string.txt_please_download_config)+"\n"+TMSUtil.getInstance().checkSecHostParams().getMessage());
// }
else if (!Connectivity.isConnectedWifi(getContext()) && !Connectivity.isConnectedMobile(getContext())) {
showSingleInfoDialog(getResourceString(R.string.txt_please_enable_internet));
}
// else if (!isValidDomain(mmqrIp)) {
// showDeclineDialog(getResourceString(R.string.txt_please_check_mmqr_ip));
// }
else {
CurrencyType currencyType = TMSUtil.getInstance().currencyTextToCurrencyType(SystemParamsOperation.getInstance().getSecHostCurrency());
sharedViewModel.set_currencyText(currencyType.name);
processBatch();
sharedViewModel.transactionsType.setValue(TransactionsType.MMQR);
navigateToAmount();
}
}
public void onClickSettlement() {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (TMSUtil.getInstance().checkParams().isStatus() == ValidityStatus.FAILURE) {
showDeclineDialog(getResourceString(R.string.txt_please_download_config)+"\n"+TMSUtil.getInstance().checkParams().getMessage());
} else if (!Connectivity.isConnectedWifi(getContext()) && !Connectivity.isConnectedMobile(getContext())) {
showSingleInfoDialog(getResourceString(R.string.txt_please_enable_internet));
} else {
sharedViewModel.settlementType.setValue(SettlementType.NORMAL);
sharedViewModel.transactionsType.setValue(TransactionsType.SETTLEMENT);
sharedViewModel.setTransMenu(TransMenu.SETTLEMENT);
setToolBarTitle(getResourceString(R.string.menu_settlement));
routeId = R.id.action_nav_main_to_inputPasswordFragment;
safeNavigateToRouteId();
}
}
public void onClickManagementFeatures() {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog(getResourceString(R.string.txt_please_download_config));
} else {
routeId = R.id.action_nav_main_to_managementFunctionFragment;
safeNavigateToRouteId();
}
}
public void onClickSignOn() {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog(getResourceString(R.string.txt_please_download_config));
} else if (!Connectivity.isConnectedWifi(getContext()) && !Connectivity.isConnectedMobile(getContext())) {
showSingleInfoDialog(getResourceString(R.string.txt_please_enable_internet));
} else if (SystemParamsOperation.getInstance().isNeedSettlement()) {
AlertXDialog.getInstance().showDialog(requireContext(), getResourceString(R.string.title_need_settle), getResourceString(R.string.txt_do_you_want_to_continue), () -> {
routeId = R.id.action_nav_main_to_nav_sign_on;
safeNavigateToRouteId();
});
} else {
routeId = R.id.action_nav_main_to_nav_sign_on;
safeNavigateToRouteId();
}
}
}
}

View File

@ -0,0 +1,251 @@
package com.utsmm.kbz;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.utsmyanmar.baselib.db.model.EmvDetail;
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.network.ISOSocket;
import com.utsmyanmar.paylibs.reversal.ReversalAction;
import com.utsmyanmar.paylibs.reversal.ReversalListener;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.service.SmileSettleService;
import com.utsmm.kbz.util.enums.ReversalStatus;
import com.utsmm.kbz.util.ecr.ECRConnectionStatus;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
import dagger.hilt.android.qualifiers.ApplicationContext;
import io.reactivex.rxjava3.core.Observable;
@HiltViewModel
public class MainViewModel extends ViewModel {
private static final String TAG = MainViewModel.class.getSimpleName();
private final Repository repository;
public SingleLiveEvent<ReversalStatus> reversalStatus = new SingleLiveEvent<>();
public SingleLiveEvent<PayDetail> payDetailSingle = new SingleLiveEvent<>();
private boolean isSecondCall = false;
private static final String REVERSAL = "REVERSAL";
public SingleLiveEvent<ECRConnectionStatus> ecrConnectionStatus = new SingleLiveEvent<>();
public SingleLiveEvent<Boolean> playAtOnce = new SingleLiveEvent<>();
public MutableLiveData<Boolean> settlementStatus = new MutableLiveData<>();
public MutableLiveData<Boolean> kPayStatus = new MutableLiveData<>();
public SingleLiveEvent<String> disabledMsg = new SingleLiveEvent<>();
public SingleLiveEvent<List<PayDetail>> settlementPOS = new SingleLiveEvent<>();
public SingleLiveEvent<List<PayDetail>> deleteTrans = new SingleLiveEvent<>();
public SingleLiveEvent<PayDetail> lastTrans = new SingleLiveEvent<>();
public SingleLiveEvent<List<PayDetail>> allTrans = new SingleLiveEvent<>();
public SingleLiveEvent<List<PayDetail>> preAuthTrans = new SingleLiveEvent<>();
public SingleLiveEvent<String> qrData = new SingleLiveEvent<>();
private int reversalCount = 0;
private BroadcastReceiver dataReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(SmileSettleService.ACTION_DATA_RECEIVED)) {
String data = intent.getStringExtra(SmileSettleService.EXTRA_DATA);
}
}
};
@Inject
public MainViewModel(Repository repository, @ApplicationContext Context context) {
this.repository = repository;
playAtOnce.setValue(false);
LocalBroadcastManager.getInstance(context).registerReceiver(dataReceiver,
new IntentFilter(SmileSettleService.ACTION_DATA_RECEIVED));
settlementStatus.setValue(SystemParamsOperation.getInstance().getSettlementStatus());
kPayStatus.setValue(SystemParamsOperation.getInstance().getWavePayStatus());
disabledMsg.setValue(SystemParamsOperation.getInstance().getDisabledMsg());
}
@Override
protected void onCleared() {
super.onCleared();
// LocalBroadcastManager.getInstance(getApplication()).unregisterReceiver(dataReceiver);
}
public LiveData<List<EmvDetail>> getAllEmvDetails() {
return repository.getAllEmvDetails();
}
public LiveData<PayDetail> getReversalTransaction(String voucherNo) {
return repository.getReversalTransaction(voucherNo);
}
public LiveData<List<PayDetail>> getSettlementPOSClearBatch() {
return repository.getSettlementPOSClearBatch();
}
public LiveData<List<PayDetail>> getDeleteTrans(String batchNo) {
return repository.getDeleteTrans(batchNo);
}
private LiveData<List<PayDetail>> getPreAuthTrans() {
return repository.getPreAuthTrans();
}
private LiveData<List<PayDetail>> getAllTrans() {
return repository.getAllTrans();
}
public void deletePayDetail(PayDetail payDetail) {
repository.deletePayDetail(payDetail);
}
public LiveData<PayDetail> getLastTransaction() {
return repository.getLastTransaction();
}
public Observable<SiriusResponse> getParams(SiriusRequest siriusRequest) {
return repository.getParams(siriusRequest);
}
public void observeSettlementPOS() {
getAllTrans().observeForever(new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
allTrans.postValue(payDetails);
}
});
getLastTransaction().observeForever(new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
lastTrans.postValue(payDetail);
}
});
getSettlementPOSClearBatch().observeForever(new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
settlementPOS.postValue(payDetails);
}
});
getDeleteTrans(SystemParamsOperation.getInstance().getCurrentBatchNum()).observeForever(new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
deleteTrans.postValue(payDetails);
}
});
getPreAuthTrans().observeForever(new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
preAuthTrans.postValue(payDetails);
}
});
}
public void startReversal(PayDetail payDetail) {
reversalCount ++ ;
if(reversalCount > 3) {
payDetailSingle.postValue(null);
reversalStatus.postValue(ReversalStatus.PAUSE);
return;
}
if(!isSecondCall){
reversalStatus.postValue(ReversalStatus.SENDING);
}else{
reversalStatus.postValue(ReversalStatus.SECONDARY);
}
TradeData tradeData = new TradeData();
tradeData.setPayDetail(payDetail);
ReversalAction.getInstance().setData(tradeData).enqueue().startReversal(new ReversalListener() {
@Override
public void onSuccessReversal() {
payDetail.setIsNeedReversal(false);
repository.updatePayDetail(payDetail);
reversalStatus.postValue(ReversalStatus.ON_SUCCESS);
}
@Override
public void onNetworkFail(String msg) {
if(SystemParamsOperation.getInstance().isSecondHostEnabled()) {
if (!isSecondCall) {
ISOSocket.getInstance().switchIp();
isSecondCall = true;
startReversal(payDetail);
} else {
reversalStatus.postValue(ReversalStatus.ON_FAILURE);
isSecondCall = false;
}
} else {
reversalStatus.postValue(ReversalStatus.ON_FAILURE);
}
payDetail.setNeedReversal(true);
repository.updatePayDetail(payDetail);
}
@Override
public void onFailReversal(String msg) {
isSecondCall = false;
reversalStatus.postValue(ReversalStatus.ON_FAILURE);
payDetail.setNeedReversal(true);
repository.updatePayDetail(payDetail);
}
});
}
}

View File

@ -0,0 +1,29 @@
package com.utsmm.kbz;
import com.utsmyanmar.baselib.BaseApplication;
import dagger.hilt.android.HiltAndroidApp;
@HiltAndroidApp
public class MyApplication extends BaseApplication {
private static MyApplication app;
public static MyApplication getInstance(){
return app;
}
// @Inject
// EmvParamOperation emvParamOperation;
@Override
public void onCreate() {
super.onCreate();
app = this;
// emvParamOperation.loadDataFromJSON();
}
}

View File

@ -0,0 +1,17 @@
package com.utsmm.kbz.config;
import com.utsmm.kbz.R;
public class Constants {
public static int NAV_HOST_ID = R.id.nav_host_fragment;
public static final String WALLET = "WALLET";
public static final String MPU_CARD_SCHEME = "MPU";
public static final int TIMEOUT = 30;
public static final int PROCESSING_TIMEOUT = 180;
public static final int PIN_PAD_TIMEOUT = 60;
public static final String REVERSAL = "REVERSAL";
}

View File

@ -0,0 +1,19 @@
package com.utsmm.kbz.config;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import com.utsmm.kbz.R;
public class UTSManageSpaceActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_uts_manage_space);
}
}

View File

@ -0,0 +1,9 @@
package com.utsmm.kbz.config.data.model;
public enum CardTransactionType {
MPU,
EMV,
MAG,
FALLBACK
}

View File

@ -0,0 +1,67 @@
package com.utsmm.kbz.config.data.model;
import com.utsmm.kbz.util.enums.FeaturesType;
public class Features {
private int id;
private String name;
private int drawable;
private FeaturesType featuresType;
private boolean active;
public Features(int id, String name, int drawable, FeaturesType featuresType) {
this.id = id;
this.name = name;
this.drawable = drawable;
this.featuresType = featuresType;
}
public Features(int id, String name, int drawable, FeaturesType featuresType, boolean active) {
this.id = id;
this.name = name;
this.drawable = drawable;
this.featuresType = featuresType;
this.active = active;
}
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setDrawable(int drawable) {
this.drawable = drawable;
}
public void setFeaturesType(FeaturesType featuresType) {
this.featuresType = featuresType;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public FeaturesType getFeaturesType() {
return featuresType;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public int getDrawable() {
return drawable;
}
}

View File

@ -0,0 +1,7 @@
package com.utsmm.kbz.config.data.model;
public enum TMSUpdate {
UPDATE,
CHECK
}

View File

@ -0,0 +1,32 @@
package com.utsmm.kbz.config.data.model;
public class TMSValidity {
private ValidityStatus status;
private String message;
public TMSValidity() {}
public TMSValidity(ValidityStatus status, String message) {
this.status = status;
this.message = message;
}
public ValidityStatus isStatus() {
return status;
}
public String getMessage() {
return message;
}
public void setStatus(ValidityStatus status) {
this.status = status;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,5 @@
package com.utsmm.kbz.config.data.model;
public enum ValidityStatus {
SUCCESS,FAILURE
}

View File

@ -0,0 +1,14 @@
package com.utsmm.kbz.service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class SmileAlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// Start the service to send the API request
Intent serviceIntent = new Intent(context, SmileSettleService.class);
context.startService(serviceIntent);
}
}

View File

@ -0,0 +1,183 @@
package com.utsmm.kbz.service;
import android.annotation.SuppressLint;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmm.kbz.BuildConfig;
import com.utsmm.kbz.R;
import com.utsmm.kbz.ui.settlement.SettlementViewModel;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import com.utsmyanmar.paylibs.utils.LogUtil;
// Temporarily disabled Hilt
// @AndroidEntryPoint
public class SmileSettleService extends Service {
private static final String TAG = SmileSettleService.class.getSimpleName();
public static final String ACTION_DATA_RECEIVED = BuildConfig.APPLICATION_ID + ".ACTION_DATA_RECEIVED";
public static final String EXTRA_DATA = BuildConfig.APPLICATION_ID + ".EXTRA_DATA";
private Handler handler;
private SettlementViewModel settlementViewModel;
@Inject
Repository repository;
public static final String NOTIFICATION_CHANNEL_ID = "10001";
private final static String default_notification_channel_id = "default";
private void createNotification() {
NotificationManager mNotificationManager = (NotificationManager)getSystemService( NOTIFICATION_SERVICE ) ;
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext() , default_notification_channel_id ) ;
mBuilder.setContentTitle( "Alarm manager is running!" ) ;
mBuilder.setContentText( "Wiping out the transactions!" ) ;
mBuilder.setTicker( "Notification Listener Service Example" ) ;
mBuilder.setSmallIcon(R.drawable. ic_launcher_foreground ) ;
mBuilder.setAutoCancel( true ) ;
if (android.os.Build.VERSION. SDK_INT >= android.os.Build.VERSION_CODES. O ) {
int importance = NotificationManager. IMPORTANCE_HIGH ;
NotificationChannel notificationChannel = new NotificationChannel( NOTIFICATION_CHANNEL_ID , "NOTIFICATION_CHANNEL_NAME" , importance) ;
mBuilder.setChannelId( NOTIFICATION_CHANNEL_ID ) ;
assert mNotificationManager != null;
mNotificationManager.createNotificationChannel(notificationChannel) ;
}
assert mNotificationManager != null;
mNotificationManager.notify(( int ) System. currentTimeMillis () , mBuilder.build()) ;
}
private void sendDataToViewModel(String data) {
Intent intent = new Intent(ACTION_DATA_RECEIVED);
intent.putExtra(EXTRA_DATA, data);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
@SuppressLint("CheckResult")
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Perform the Settlement request here
// ...
LogUtil.d(TAG,"<<<<<<<<<<<<<<< This action was called >>>>>>>>>>>>>>>>.");
sendDataToViewModel("Hello there");
createNotification();
// Observer<List<PayDetail>> settleObserver = new Observer<List<PayDetail>>() {
// @Override
// public void onChanged(List<PayDetail> list) {
//
//
// if(list == null || list.size() == 0) {
// LogUtil.d(TAG, "Settle is null");
// return;
// }
// LogUtil.d(TAG,"Size Settle : "+list.size());
//
// for (PayDetail pay:list) {
// repository.deletePayDetail(pay);
// }
//
//
// }
// };
//
//
// repository.getSettlementPOS().observeForever(settleObserver);
//
// repository.getSettlementPOS().removeObserver(settleObserver);
//
// Observer<List<PayDetail>> deleteTransObserver = new Observer<List<PayDetail>>() {
// @Override
// public void onChanged(List<PayDetail> lists) {
// if(lists == null || lists.size() == 0) {
// return;
// }
//
// LogUtil.d(TAG,"Size Delete Trans : "+lists.size());
// for (PayDetail pay:lists) {
// repository.deletePayDetail(pay);
// }
// }
// };
//
// repository.getDeleteTrans(SystemParamsOperation.getInstance().getCurrentBatchNum()).observeForever(deleteTransObserver);
//
// repository.getDeleteTrans(SystemParamsOperation.getInstance().getCurrentBatchNum()).removeObserver(deleteTransObserver);
//
//
// try{
// handler.post(new Runnable() {
// @Override
// public void run() {
// // Create and show the dialog
// AlertDialog.Builder builder = new AlertDialog.Builder(SmileSettleService.this);
// builder.setTitle("Auto Settle!")
// .setMessage("Settlement process is going to start!")
// .setPositiveButton("OK", new DialogInterface.OnClickListener() {
// @Override
// public void onClick(DialogInterface dialog, int which) {
// // Handle OK button click
// dialog.dismiss(); // Dismiss the dialog
// }
// })
// .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
// @Override
// public void onClick(DialogInterface dialog, int which) {
// // Handle Cancel button click
// dialog.dismiss(); // Dismiss the dialog
// }
// });
//
//
// AlertDialog dialog = builder.create();
//// dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
//// dialog.show();
// }
// });
// }catch (Exception e){
// e.printStackTrace();
// }
return START_NOT_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
handler = new Handler();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}

View File

@ -0,0 +1,38 @@
package com.utsmm.kbz.ui;
import dagger.hilt.android.lifecycle.HiltViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.paylibs.model.PayDetail;
import java.util.List;
import javax.inject.Inject;
@HiltViewModel
public class SettingViewModel extends ViewModel {
private Repository repository;
@Inject
public SettingViewModel(Repository repository){
this.repository = repository;
}
public LiveData<PayDetail> getReversalTransaction(String voucherNo) {
return repository.getReversalTransaction(voucherNo);
}
public LiveData<List<PayDetail>> getSettlement(){
return repository.getSettlement();
}
public void updatePayDetail(PayDetail payDetail){
repository.updatePayDetail(payDetail);
}
}

View File

@ -0,0 +1,437 @@
package com.utsmm.kbz.ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.Navigation;
import com.google.gson.Gson;
import com.google.gson.stream.MalformedJsonException;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.sirius.SiriusError;
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.baselib.util.URLValidator;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.MainViewModel;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.data.model.TMSUpdate;
import com.utsmm.kbz.databinding.FragmentSettingsModernBinding;
import com.utsmm.kbz.ui.settlement.SettlementViewModel;
import com.utsmm.kbz.util.tms.TMSUtil;
import java.io.IOException;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import retrofit2.HttpException;
@AndroidEntryPoint
public class SettingsFragment extends DataBindingFragment {
private static final String TAG = SettingsFragment.class.getSimpleName();
private SettlementViewModel settlementViewModel;
private MainViewModel mainViewModel;
private int count = 0;
// Data binding will handle view access automatically
private FragmentSettingsModernBinding binding;
@Inject
public EmvParamOperation emvParamOperation;
@Override
protected void initViewModel() {
// Initialize ViewModels in initViewModel as per pattern
settlementViewModel = getFragmentScopeViewModel(SettlementViewModel.class);
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
// This is the key method that links the XML and fragment properly
return new DataBindingConfig(R.layout.fragment_settings_modern, 0, null)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.nav_settings;
}
@Override
protected int hostId() {
return R.id.nav_host_fragment;
}
@Override
protected int routeId() {
return 0;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
try {
LogUtil.d(TAG, "onViewCreated called");
// Get the binding from the base class - this is automatically created
binding = (FragmentSettingsModernBinding) mBinding;
LogUtil.d(TAG, "Updating settings...");
updateSettings();
LogUtil.d(TAG, "Settings fragment initialized successfully");
} catch (Exception e) {
LogUtil.e(TAG, "Error initializing fragment: " + e.getMessage());
e.printStackTrace();
}
}
@Override
public void onResume() {
super.onResume();
try {
setToolBarTitleWithBackIcon("Settings");
LogUtil.d(TAG, "Settings screen resumed");
} catch (Exception e) {
LogUtil.e(TAG, "Error in onResume: " + e.getMessage());
}
}
private void updateSettings() {
try {
// Set version info
try {
String versionName = requireContext().getPackageManager()
.getPackageInfo(requireContext().getPackageName(), 0).versionName;
binding.versionSummary.setText(versionName);
} catch (Exception ex) {
LogUtil.e(TAG, "Error getting version name: " + ex.getMessage());
binding.versionSummary.setText("Unknown");
}
// Update switch states and summaries
updateDemoSettings();
updateAlertSoundSettings();
updateReversalSettings();
updateMultiHostSettings();
updateTmsAddressSettings();
LogUtil.d(TAG, "Settings updated successfully");
} catch (Exception e) {
LogUtil.e(TAG, "Error updating settings: " + e.getMessage());
}
}
private void updateDemoSettings() {
boolean isDemo = SystemParamsOperation.getInstance().getDemoStatus();
binding.demoSwitch.setChecked(isDemo);
binding.demoSummary.setText(isDemo ?
"Demo mode active - Test transactions without real processing" :
"Simulator mode active - Real transaction processing");
}
private void updateAlertSoundSettings() {
boolean isEnabled = SystemParamsOperation.getInstance().isAlertSound();
binding.alertSoundSwitch.setChecked(isEnabled);
binding.alertSoundSummary.setText(isEnabled ?
"Sound alerts enabled for notifications" :
"Sound alerts disabled - Silent mode");
}
private void updateReversalSettings() {
boolean isEnabled = SystemParamsOperation.getInstance().isReversalOn();
binding.reversalSwitch.setChecked(isEnabled);
binding.reversalSummary.setText(isEnabled ?
"Automatic reversal enabled for failed transactions" :
"Automatic reversal disabled - Manual reversal only");
}
private void updateMultiHostSettings() {
boolean isEnabled = SystemParamsOperation.getInstance().isMultiHost();
binding.multiHostSwitch.setChecked(isEnabled);
binding.multiHostSummary.setText(isEnabled ?
"Multiple host support enabled" :
"Single host mode - Primary host only");
}
private void updateTmsAddressSettings() {
String address = SystemParamsOperation.getInstance().getTmsAddress();
binding.tmsAddressSummary.setText(address != null && !address.isEmpty() ?
address : "Configure terminal management server URL");
}
// ClickEvent class for data binding - this is the proper pattern
public class ClickEvent {
public void onVersionClick() {
try {
count++;
LogUtil.d(TAG, "Version clicked " + count + " times");
if (count == 5) {
count = 0;
// Navigation for hidden settings could be added here
}
} catch (Exception e) {
LogUtil.e(TAG, "Error in version click: " + e.getMessage());
}
}
public void onDemoClick() {
try {
boolean newValue = !SystemParamsOperation.getInstance().getDemoStatus();
SystemParamsOperation.getInstance().setDemoStatus(newValue);
updateDemoSettings();
LogUtil.d(TAG, "Demo mode toggled to: " + newValue);
} catch (Exception e) {
LogUtil.e(TAG, "Error toggling demo mode: " + e.getMessage());
}
}
public void onAlertSoundClick() {
try {
boolean newValue = !SystemParamsOperation.getInstance().isAlertSound();
SystemParamsOperation.getInstance().setAlertSound(newValue);
updateAlertSoundSettings();
LogUtil.d(TAG, "Alert sound toggled to: " + newValue);
} catch (Exception e) {
LogUtil.e(TAG, "Error toggling alert sound: " + e.getMessage());
}
}
public void onReversalClick() {
try {
boolean newValue = !SystemParamsOperation.getInstance().isReversalOn();
SystemParamsOperation.getInstance().setReversalFlag(newValue);
updateReversalSettings();
LogUtil.d(TAG, "Reversal toggled to: " + newValue);
} catch (Exception e) {
LogUtil.e(TAG, "Error toggling reversal: " + e.getMessage());
}
}
public void onMultiHostClick() {
try {
boolean newValue = !SystemParamsOperation.getInstance().isMultiHost();
SystemParamsOperation.getInstance().setMultiHost(newValue);
updateMultiHostSettings();
LogUtil.d(TAG, "Multi-host toggled to: " + newValue);
} catch (Exception e) {
LogUtil.e(TAG, "Error toggling multi-host: " + e.getMessage());
}
}
public void onTmsAddressClick() {
try {
// Show dialog to edit TMS address
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle("TMS Server URL");
builder.setMessage("Enter the Terminal Management Server URL:");
// Add EditText to dialog
final android.widget.EditText input = new android.widget.EditText(requireContext());
input.setText(SystemParamsOperation.getInstance().getTmsAddress());
builder.setView(input);
builder.setPositiveButton("Save", (dialog, which) -> {
String newAddress = input.getText().toString().trim();
if (!newAddress.isEmpty()) {
if (URLValidator.isValidURL(newAddress)) {
SystemParamsOperation.getInstance().setTmsAddress(newAddress);
updateTmsAddressSettings();
showSingleInfoDialog(getResourceString(R.string.txt_kill_app));
LogUtil.d(TAG, "TMS address updated: " + newAddress);
} else {
showSingleInfoDialog(getResourceString(R.string.txt_tms_url_not_valid));
LogUtil.w(TAG, "Invalid TMS URL: " + newAddress);
}
}
});
builder.setNegativeButton("Cancel", (dialog, which) -> dialog.cancel());
builder.show();
} catch (Exception e) {
LogUtil.e(TAG, "Error in TMS address click: " + e.getMessage());
}
}
public void onUpdateConfigClick() {
try {
LogUtil.d(TAG, "Update config clicked");
settlementViewModel.getSettlementPOS().observe(getViewLifecycleOwner(), payDetails -> {
try {
if (payDetails != null && payDetails.size() > 0) {
showRequireSettlementDialog("If you can take your own risk!\nClick continue to download!");
} else {
if (SystemParamsOperation.getInstance().isNeedSettlement()) {
showRequireSettlementDialog("Params changes detected!\nIf you can take your own risk!\nClick continue to download!");
} else {
checkLastTrans();
}
}
} catch (Exception e) {
LogUtil.e(TAG, "Error processing settlement check: " + e.getMessage());
}
});
} catch (Exception e) {
LogUtil.e(TAG, "Error in update config: " + e.getMessage());
}
}
public void onTmsConfigClick() {
try {
LogUtil.d(TAG, "TMS Config clicked");
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
.navigate(R.id.action_nav_settings_to_configSettingsFragment);
} catch (Exception e) {
LogUtil.e(TAG, "Error navigating to TMS config: " + e.getMessage());
}
}
}
// Keep existing methods for settlement and download functionality
private void showRequireSettlementDialog(String message) {
try {
AlertDialog.Builder builderInner = new AlertDialog.Builder(requireContext());
builderInner.setTitle(getResourceString(R.string.txt_please_settle_first));
builderInner.setMessage(message);
builderInner.setNegativeButton("Cancel", (dialog, which) -> dialog.dismiss());
builderInner.setPositiveButton("Continue", (dialog1, which1) -> {
try {
checkLastTrans();
dialog1.dismiss();
} catch (Exception e) {
LogUtil.e(TAG, "Error in settlement dialog positive action: " + e.getMessage());
}
});
builderInner.show();
} catch (Exception e) {
LogUtil.e(TAG, "Error showing settlement dialog: " + e.getMessage());
}
}
private void checkLastTrans() {
try {
LogUtil.d(TAG, "Checking last transaction");
mainViewModel.getLastTransaction().observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
try {
if (payDetail != null) {
downloadParams(payDetail.getTransType(), String.valueOf(payDetail.getTransNum()));
} else {
String lastTransName = SystemParamsOperation.getInstance().getLastTransName();
String lastTransTime = SystemParamsOperation.getInstance().getLastTransTime();
if (lastTransTime != null && !lastTransTime.isEmpty() &&
lastTransName != null && !lastTransName.isEmpty()) {
downloadParams(lastTransName, lastTransTime);
} else {
long transTime = System.currentTimeMillis();
String transTimeInString = String.valueOf(transTime).substring(0, 10);
downloadParams("...", transTimeInString);
}
}
} catch (Exception e) {
LogUtil.e(TAG, "Error processing last transaction: " + e.getMessage());
}
}
});
} catch (Exception e) {
LogUtil.e(TAG, "Error checking last transaction: " + e.getMessage());
}
}
private void downloadParams(String lastTransName, String lastTransTime) {
try {
LogUtil.d(TAG, "Downloading params for transaction: " + lastTransName);
SiriusRequest siriusReq = TMSUtil.getInstance().generateRequestParams(getContext(), lastTransName, lastTransTime);
mainViewModel.getParams(siriusReq)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.rxjava3.core.Observer<SiriusResponse>() {
@Override
public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {
LogUtil.d(TAG, "Starting params download");
}
@Override
public void onNext(@io.reactivex.rxjava3.annotations.NonNull SiriusResponse siriusResponse) {
try {
TMSUtil.getInstance().initParams(siriusResponse, TMSUpdate.UPDATE,emvParamOperation);
showLoadingDialog(getResourceString(R.string.txt_downloading));
LogUtil.d(TAG, "Params download initiated");
} catch (Exception e) {
LogUtil.e(TAG, "Error processing params response: " + e.getMessage());
}
}
@Override
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
try {
dismissLoadingDialog();
LogUtil.e(TAG, "Params download error: " + e.getMessage());
if (e.getClass() == MalformedJsonException.class) {
showDeclineDialog(getResourceString(R.string.txt_terminal_is_not_configure));
} else if (e instanceof HttpException) {
HttpException error = (HttpException) e;
try {
SiriusError siriusError = new Gson().fromJson(error.response().errorBody().string(), SiriusError.class);
showDeclineDialog(siriusError.getMessage());
} catch (IOException ex) {
LogUtil.e(TAG, "Error parsing error response: " + ex.getMessage());
showDeclineDialog(getResourceString(R.string.txt_tms_url_not_valid));
} catch (Exception ex) {
LogUtil.e(TAG, "Unexpected error parsing response: " + ex.getMessage());
showDeclineDialog(getResourceString(R.string.txt_tms_url_not_valid));
}
} else {
showDeclineDialog(getResourceString(R.string.txt_failure_next_line) + e.getMessage());
}
} catch (Exception ex) {
LogUtil.e(TAG, "Error handling download error: " + ex.getMessage());
}
}
@Override
public void onComplete() {
try {
dismissLoadingDialog();
showSuccessDialogAutoHide(getResourceString(R.string.txt_configs_are_updated));
updateSettings();
SystemParamsOperation.getInstance().setDownloadedParams(true);
LogUtil.d(TAG, "Params download completed successfully");
} catch (Exception e) {
LogUtil.e(TAG, "Error completing params download: " + e.getMessage());
}
}
});
} catch (Exception e) {
LogUtil.e(TAG, "Error initiating params download: " + e.getMessage());
dismissLoadingDialog();
showDeclineDialog(getResourceString(R.string.txt_error_occurred));
}
}
}

View File

@ -0,0 +1,73 @@
package com.utsmm.kbz.ui.adapters;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.data.model.Features;
import com.utsmm.kbz.databinding.ItemViewDashboardBinding;
import java.util.List;
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
private List<Features> list;
private final MainAdapter.ItemOnClickListener listener;
public MainAdapter(List<Features> list, MainAdapter.ItemOnClickListener listener){
this.list = list;
this.listener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemViewDashboardBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_view_dashboard,parent,false);
// ItemViewDashboardPremiumBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_view_dashboard_premium,parent,false);
return new MainAdapter.ViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Features features = list.get(position);
holder.bind(features,listener);
}
@Override
public int getItemCount() {
return list.size();
}
public interface ItemOnClickListener{
void onItemClick(Features item);
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ItemViewDashboardBinding binding;
public ViewHolder(ItemViewDashboardBinding binding){
super(binding.getRoot());
this.binding = binding;
}
public void bind(Object object,final MainAdapter.ItemOnClickListener listener){
binding.setVariable(BR.item,object);
binding.getRoot().setOnClickListener(v -> {
Features item = (Features) object;
if(item.isActive()){
listener.onItemClick(item);
}
});
binding.executePendingBindings();
}
}
}

View File

@ -0,0 +1,302 @@
package com.utsmm.kbz.ui.adapters;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.cardview.widget.CardView;
import androidx.lifecycle.MutableLiveData;
import com.airbnb.lottie.LottieAnimationView;
import com.squareup.picasso.Picasso;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.R;
import com.utsmm.kbz.ui.manual_entry.EntryState;
import com.utsmm.kbz.util.QRCodeGenerator;
import com.utsmm.kbz.util.enums.TMSDownloadStatus;
import com.utsmm.kbz.util.recyclerview.SpacesItemDecoration;
import androidx.databinding.BindingAdapter;
import androidx.recyclerview.widget.RecyclerView;
import androidmads.library.qrgenearator.QRGContents;
import androidmads.library.qrgenearator.QRGEncoder;
public class MyBindingAdapter {
private static final String TAG = MyBindingAdapter.class.getSimpleName();
@BindingAdapter({"setAdapter"})
public static void setMainAdapter(RecyclerView recyclerView, MainAdapter adapter) {
recyclerView.setNestedScrollingEnabled(false);
recyclerView.setAdapter(adapter);
}
@BindingAdapter("itemSpacing")
public static void setItemSpacing(RecyclerView recyclerView, int spacing) {
recyclerView.addItemDecoration(new SpacesItemDecoration(spacing));
}
@BindingAdapter({"imgUrl"})
public static void renderIcon(AppCompatImageView imageView, Integer imgUrl) {
Picasso.get().load(imgUrl)
.resize(60, 60)
.placeholder(R.drawable.ic_blur)
.into(imageView);
}
@BindingAdapter({"srcUrl"})
public static void renderIcon(ImageView imageView, Integer imgUrl) {
Picasso.get().load(imgUrl)
.placeholder(R.drawable.ic_blur)
.into(imageView);
}
@BindingAdapter({"entryBg"})
public static void entryBg(EditText et, EntryState entryState) {
int bg = R.drawable.bg_edittext;
if(entryState == EntryState.SELECTED) {
bg = R.drawable.bg_edittext_focus;
} else if( entryState == EntryState.ERROR) {
bg = R.drawable.bg_edittext_error;
}
et.setBackgroundResource(bg);
}
@BindingAdapter({"isColorChanges"})
public static void isColorChanged(TextView textView,PayDetail payDetail) {
if(payDetail.getTransactionType() == TransactionsType.MMQR.value) {
if(payDetail.getQrTransStatus() == -1) {
textView.setTextColor(textView.getResources().getColor(R.color.smilePrimaryColor));
} else {
textView.setTextColor(textView.getResources().getColor(R.color.black));
}
} else {
textView.setTextColor(textView.getResources().getColor(R.color.black));
}
}
@SuppressLint({"RestrictedApi", "ResourceAsColor"})
@BindingAdapter({"isActive"})
public static void isActive(ImageView imageView, boolean active) {
if(active){
imageView.setColorFilter( imageView.getResources().getColor(R.color.white), PorterDuff.Mode.SRC_IN);
} else {
imageView.setColorFilter( imageView.getResources().getColor(R.color.colorGray),PorterDuff.Mode.SRC_IN);
}
}
@SuppressLint({"RestrictedApi", "ResourceAsColor"})
@BindingAdapter({"isEnabled"})
public static void isEnabled(ImageView imageView, int active) {
if(active == 1){
imageView.setColorFilter( imageView.getResources().getColor(R.color.black), PorterDuff.Mode.SRC_IN);
} else {
imageView.setColorFilter( imageView.getResources().getColor(R.color.colorMedGray),PorterDuff.Mode.SRC_IN);
}
}
@BindingAdapter({"imgLogo"})
public static void setCardLogo(AppCompatImageView imageView, String cardType) {
int imgURL = 0;
// LogUtil.d(TAG,"card type : "+cardType);
if(cardType != null){
switch (cardType) {
case "VISA":
imgURL = R.drawable.logo_visa;
break;
case "MASTER":
imgURL = R.drawable.logo_master;
break;
case "UnionPay":
imgURL = R.drawable.logo_upi;
break;
case "JCB":
imgURL = R.drawable.logo_jcb;
break;
case "DISCOVER":
imgURL = R.drawable.logo_discover;
break;
case "MIR":
imgURL = R.drawable.logo_mir;
break;
case "AMEX":
imgURL = R.drawable.logo_amex;
break;
case "MPU":
imgURL = R.drawable.logo_mpu;
break;
case "WALLET":
imgURL = R.drawable.logo_kpay;
break;
default:
imgURL = R.drawable.logo_unk;
break;
}
Picasso.get().load(imgURL)
.resize(60, 60)
.placeholder(R.drawable.ic_blur)
.into(imageView);
}
}
@BindingAdapter({"disableBtn"})
public static void setDisableButton(Button button, boolean flag) {
button.setEnabled(flag);
if(!flag) {
button.setTextColor(button.getResources().getColor(R.color.colorGray));
button.setCompoundDrawableTintList(button.getResources().getColorStateList(R.color.disable_color));
} else {
button.setTextColor(button.getResources().getColor(R.color.colorPrimary));
button.setCompoundDrawableTintList(button.getResources().getColorStateList(R.color.active_color));
}
}
@BindingAdapter({"disableBtn"})
public static void setDisableCardView(CardView cardView, boolean flag) {
cardView.setEnabled(flag);
cardView.setClickable(flag);
if (!flag) {
cardView.setAlpha(0.5f);
} else {
cardView.setAlpha(1.0f);
}
}
@BindingAdapter({"disableBtn"})
public static void setDisableCardViewLiveData(CardView cardView, MutableLiveData<Boolean> flag) {
boolean value = flag != null && flag.getValue() != null ? flag.getValue() : false;
cardView.setEnabled(value);
cardView.setClickable(value);
if (!value) {
cardView.setAlpha(0.5f);
} else {
cardView.setAlpha(1.0f);
}
}
@BindingAdapter({"disableQRBtn"})
public static void setDisableQRButton(Button button, boolean flag) {
button.setEnabled(flag);
if(!flag) {
button.setBackground(button.getResources().getDrawable(R.drawable.bg_rounded_btn_disabled));
} else {
button.setBackground(button.getResources().getDrawable(R.drawable.bg_rounded_btn_cv));
}
}
@BindingAdapter({"disableQRImgBtn"})
public static void setDisableQRImgButton(ImageButton button, boolean flag) {
button.setEnabled(flag);
if(!flag) {
button.setBackground(button.getResources().getDrawable(R.drawable.bg_rounded_btn_disabled));
} else {
button.setBackground(button.getResources().getDrawable(R.drawable.bg_rounded_btn_cv));
}
}
@BindingAdapter({"ecrStatus"})
public static void setECRConnectionStatusImage(AppCompatImageView imageView, String connectionStatus) {
int imgURL = 0;
if(connectionStatus != null){
switch (connectionStatus) {
case "CONNECTED":
imgURL = R.drawable.ic_green_circle;
break;
case "IDLE":
case "CREATED":
imgURL = R.drawable.ic_yellow_circle;
break;
default:
imgURL = R.drawable.ic_red_circle;
break;
}
Picasso.get().load(imgURL)
.resize(30,30)
.placeholder(R.drawable.ic_ecr_place_holder)
.error(R.drawable.ic_ecr_place_holder)
.into(imageView);
}
}
@BindingAdapter({"qrData"})
public static void setQrCode(AppCompatImageView imageView, String data) {
QRGEncoder qrgEncoder = new QRGEncoder(data, null, QRGContents.Type.TEXT, 300);
Bitmap bitmap = qrgEncoder.getBitmap();
imageView.setImageBitmap(bitmap);
}
@BindingAdapter({"mmpayData"})
public static void setMMPayQRCode(AppCompatImageView imageView,String data) {
//250
//290
int width = 270;
int height = 270;
Bitmap logo = QRCodeGenerator.getBitmapFromVectorDrawable(imageView.getContext(),R.drawable.logo_kpay);
Bitmap qrCodeBitmap = QRCodeGenerator.generateQRCode(data, width, height, logo);
imageView.setImageBitmap(qrCodeBitmap);
}
@BindingAdapter({"tmsStatus"})
public static void setLottieView(LottieAnimationView lottieView, TMSDownloadStatus status) {
//250
//290
if(status == TMSDownloadStatus.DOWNLOADING) {
lottieView.setAnimation("lottie_download_loading.json");
} else if(status == TMSDownloadStatus.SUCCESS) {
lottieView.setAnimation("lottie_success.json");
} else if(status == TMSDownloadStatus.FAILURE) {
lottieView.setAnimation("lottie_decline.json");
}
}
@SuppressLint("SetTextI18n")
@BindingAdapter({"isTrace"})
public static void checkIsTraceOrInvoice(TextView textView, PayDetail payDetail) {
if(payDetail.getTransactionType() == TransactionsType.MMQR.value || payDetail.getTransactionType() == TransactionsType.MMQR_REFUND.value) {
textView.setText("INV:"+payDetail.getInvoiceNo());
} else {
textView.setText("TRC:"+payDetail.getVoucherNo());
}
}
}

View File

@ -0,0 +1,74 @@
package com.utsmm.kbz.ui.adapters;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.databinding.library.baseAdapters.BR;
import androidx.recyclerview.widget.RecyclerView;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmm.kbz.R;
import com.utsmm.kbz.databinding.ItemViewVoidBinding;
import java.util.List;
public class VoidAdapter extends RecyclerView.Adapter<VoidAdapter.ViewHolder> {
private List<PayDetail> payDetailList;
private String operationType;
private final ItemOnClickListener listener;
public VoidAdapter(List<PayDetail> payDetailList,String operationType,ItemOnClickListener listener){
this.payDetailList = payDetailList;
this.operationType = operationType;
this.listener = listener;
}
public interface ItemOnClickListener{
void onItemClick(PayDetail item);
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemViewVoidBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.item_view_void,parent,false);
return new ViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
PayDetail payDetail = payDetailList.get(position);
holder.bind(payDetail,listener);
}
@Override
public int getItemCount() {
return payDetailList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public ItemViewVoidBinding binding;
public ViewHolder(ItemViewVoidBinding binding){
super(binding.getRoot());
this.binding = binding;
}
public void bind(Object object,final ItemOnClickListener listener){
binding.setVariable(BR.payDetail,object);
binding.getRoot().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
listener.onItemClick((PayDetail)object);
}
});
binding.executePendingBindings();
}
}
}

View File

@ -0,0 +1,333 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.checkxread.checkcard.CheckCardResultX;
import com.utsmyanmar.checkxread.util.CardTypeX;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.config.data.model.CardTransactionType;
import com.utsmm.kbz.ui.core_viewmodel.CardReadViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.util.HashSet;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class CardWaitingFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback{
private SharedViewModel sharedViewModel;
private CardReadViewModel cardReadViewModel;
private TransProcessViewModel transProcessViewModel;
private static final String TAG = CardWaitingFragment.class.getSimpleName();
private static final int cardWaitingTimeOut = 60;
private int routeId;
private int fallbackCounter = 0;
private boolean fallbackEnabled = false;
private int retryCounter = 0;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
cardReadViewModel = getFragmentScopeViewModel(CardReadViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_capture_card_screen, BR.readCardVM, cardReadViewModel)
.addBindingParam(BR.sharedVM, sharedViewModel)
.addBindingParam(BR.transVM,transProcessViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.cardWaitingFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onBackPress() {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
finishECR();
}
}
popBackStack();
}
private void finishECR() {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans));
sharedViewModel.isEcrFinished.postValue(true);
}
public class ClickEvent {
public void onClickManualEntry() {
// showSingleInfoDialogAutoHide("Coming Soon!");
routeId = R.id.action_cardWaitingFragment_to_manualEntryFragment;
safeNavigateToRouteId();
}
}
@Override
public void onResume() {
super.onResume();
resetUI();
setToolBarTitleWithBackIcon(getResourceString(R.string.txt_title_card_capture));
delayFunctionCall(()-> {
if(sharedViewModel.transactionsType.getValue() == TransactionsType.REFUND) {
sharedViewModel.enableCardStatusIcon(false,false,false,false);
} else {
sharedViewModel.enableCardStatusIcon(true,true,true,false);
}
});
if(sharedViewModel.getIsFallback().getValue() != null && sharedViewModel.getIsFallback().getValue()) {
cardReadViewModel.setCheckCardAlertMsg("Fallback!\nPlease stripe!",false);
setupCardReadProcess(true);
} else {
setupCardReadProcess(false);
}
}
@Override
public void onPause() {
super.onPause();
sharedViewModel.setIsFallback(false);
// cardReadViewModel.cancelCheckCard();
cardReadViewModel.resetOneTimeFlag();
cardReadViewModel.cancelCheckXProcess();
}
private void resetUI() {
cardReadViewModel.resetUI();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initData();
setupBackButtonPressDetection(this);
// if(sharedViewModel.getIsFallback().getValue() != null && sharedViewModel.getIsFallback().getValue()) {
// cardReadViewModel.setCheckCardAlertMsg("Fallback!\nPlease stripe!",false);
// setupCardReadProcess(true);
// } else {
// setupCardReadProcess(false);
// }
}
private void initData() {
retryCounter = 0;
fallbackCounter = SystemParamsOperation.getInstance().getFallbackCounter();
fallbackEnabled = SystemParamsOperation.getInstance().getFallbackEnabled();
}
private void setupCardReadProcess(boolean isFallback) {
initCheckCard(isFallback);
setUpTimer();
}
private void setUpTimer() {
setupTimeout(30, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
// try {
// MyApplication.getInstance().basicOptBinder.buzzerOnDevice(1);
// } catch (RemoteException e) {
// e.printStackTrace();
// }
routeId = R.id.action_cardWaitingFragment_to_timeoutFragment;
safeNavigateToRouteId();
}
});
}
private void initCheckCard(boolean isFallback) {
// int allType = AidlConstants.CardType.NFC.getValue() | AidlConstants.CardType.IC.getValue() | AidlConstants.CardType.MAGNETIC.getValue();
//
//
// if(isFallback) {
// allType = AidlConstants.CardType.MAGNETIC.getValue();
// } else {
// if(SystemParamsOperation.getInstance().isMagStripeEnabled() && !SystemParamsOperation.getInstance().isNfcEnabled()) {
// allType = AidlConstants.CardType.IC.getValue() | AidlConstants.CardType.MAGNETIC.getValue();
// } else if(SystemParamsOperation.getInstance().getFallbackEnabled() && !SystemParamsOperation.getInstance().isNfcEnabled()) {
// allType = AidlConstants.CardType.IC.getValue() | AidlConstants.CardType.MAGNETIC.getValue();
// }
// }
HashSet<CardSlotTypeEnum> allType = new HashSet<>();
allType.add(CardSlotTypeEnum.ICC1);
allType.add(CardSlotTypeEnum.RF);
// int allType = AidlConstants.CardType.IC.getValue() | AidlConstants.CardType.MAGNETIC.getValue();
cardReadViewModel.startCheckXProcessNex(allType, cardWaitingTimeOut + 5, new CheckCardResultX() {
@Override
public void onSuccess(CardTypeX cardType, boolean isMPU) {
LogUtil.d(TAG,"**** on success *****");
LogUtil.d(TAG,"card type:"+cardType);
LogUtil.d(TAG,"is MPU:"+isMPU);
LogUtil.d(TAG,"is fallback:"+isFallback);
if(!isFallback && cardType == CardTypeX.MAG) {
if(SystemParamsOperation.getInstance().isMagStripeEnabled()) {
cardReadViewModel.setCardTransactionType(CardTransactionType.MAG);
} else {
cardReadViewModel.setCheckCardAlertMsg(getResourceString(R.string.txt_mag_stripe_alert),true);
cancelTimeout();
setupCardReadProcess(false);
return;
}
} else if (isFallback && cardType == CardTypeX.MAG) {
/* do fallback transactions */
sharedViewModel.isEmv.setValue(false);
cardReadViewModel.setCardTransactionType(CardTransactionType.FALLBACK);
} else if (cardType == CardTypeX.IC || cardType == CardTypeX.NFC) {
if(isMPU) {
sharedViewModel.isEmv.setValue(false);
cardReadViewModel.setCardTransactionType(CardTransactionType.MPU);
} else {
cardReadViewModel.cardTypeData.postValue(cardType.value);
cardReadViewModel.setCardTransactionType(CardTransactionType.EMV);
}
}
delayFunctionCall(()->{
routeId = R.id.action_cardWaitingFragment_to_processingCardFragment;
safeNavigateToRouteId();
});
}
@Override
public void onError(int code, String message) {
LogUtil.d(TAG,"on error:"+code+" - message :"+message);
ecrActionCancel(getResourceString(R.string.txt_cancel_trans));
showDeclineDialog(message);
routeId = R.id.action_cardWaitingFragment_to_nav_main;
safeNavigateToRouteId();
}
@Override
public void onCommError() {
LogUtil.d(TAG,"on Comm Error...");
/*
* Fallback is almost finished ! need to implement only at ISO library for ISO8583 message.
* 25 Sept,2024
* */
if(fallbackEnabled && retryCounter < fallbackCounter) {
cardReadViewModel.setCheckCardAlertMsg("Card not detected!\n Remain Attempt - "+(fallbackCounter - retryCounter),false);
cancelTimeout();
retryCounter ++;
isCardInserted(()-> {
setupCardReadProcess(false);
});
} else if(retryCounter == fallbackCounter) {
cardReadViewModel.setCheckCardAlertMsg("Fallback!\nPlease stripe!",false);
cancelTimeout();
isCardInserted(()-> {
setupCardReadProcess(true);
});
} else {
ecrActionCancel(getResourceString(R.string.txt_cancel_trans));
showDeclineDialog("Chip not detected!");
routeId = R.id.action_cardWaitingFragment_to_nav_main;
safeNavigateToRouteId();
}
}
});
}
private void ecrActionCancel(String msg) {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg);
sharedViewModel.isEcrFinished.postValue(true);
}
}
}
}

View File

@ -0,0 +1,268 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.nexgo.oaf.apiv3.SdkResult;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.DialogCallback;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.print.PrintHelper;
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
import com.utsmyanmar.paylibs.print.printx.PrintXStatus;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.ui.sale_void.VoidViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
public class ConfirmTransactionFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback{
private VoidViewModel voidViewModel;
private SharedViewModel sharedViewModel;
private TransProcessViewModel transProcessViewModel;
private int routeId;
private boolean isMerchantCopy = true;
@Override
protected void initViewModel() {
voidViewModel = getFragmentScopeViewModel(VoidViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_trans_info_screen, BR.voidViewModel,voidViewModel)
.addBindingParam(BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.transProcessViewModel,transProcessViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
protected int currentId() {
return R.id.confirmTransactionFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setUpTimer();
setupBackButtonPressDetection(this);
String merchantName = SystemParamsOperation.getInstance().getMerchantName();
if(!TextUtils.equals(merchantName,"")){
sharedViewModel.merchantName.postValue(merchantName);
}else{
sharedViewModel.merchantName.postValue("Default Value");
}
// observeData();
}
private void setUpTimer(){
setupTimeout(Constants.TIMEOUT, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
routeId = R.id.action_confirmTransactionFragment_to_timeoutFragment;
safeNavigateToRouteId();
}
});
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getResourceString(R.string.txt_title_trans_info));
isMerchantCopy = true;
if(sharedViewModel.getTransMenu().getValue() == TransMenu.REVIEW) {
sharedViewModel.oneBtnLayout.setValue(0);
sharedViewModel.twoBtnLayout.setValue(8);
sharedViewModel.reprintBtnLayout.setValue(8);
} else if(sharedViewModel.getTransMenu().getValue() == TransMenu.TRANSACTIONS || sharedViewModel.getTransMenu().getValue() == TransMenu.TIP_ADJUSTMENT || sharedViewModel.getTransMenu().getValue() == TransMenu.VOID || sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_COMPLETE_VOID || sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_FULL_VOID) {
sharedViewModel.oneBtnLayout.setValue(8);
sharedViewModel.twoBtnLayout.setValue(0);
sharedViewModel.reprintBtnLayout.setValue(8);
} else if(sharedViewModel.getTransMenu().getValue() == TransMenu.REPRINT) {
sharedViewModel.reprintTransTypeMsg.setValue(getResourceString(R.string.txt_print_merchant_copy));
sharedViewModel.oneBtnLayout.setValue(8);
sharedViewModel.twoBtnLayout.setValue(8);
sharedViewModel.reprintBtnLayout.setValue(0);
// printReceipt(true);
}
}
private void finishECR() {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans));
sharedViewModel.isEcrFinished.postValue(true);
sharedViewModel.isEcr.postValue(false);
}
private void callMainScreen(){
routeId = R.id.action_confirmTransactionFragment_to_nav_main;
safeNavigateToRouteId();
}
private void ECRActionCancel(){
if(sharedViewModel.isEcr.getValue() != null){
if(sharedViewModel.isEcr.getValue()){
sharedViewModel.isEcr.postValue(false);
sharedViewModel.isEcrFinished.postValue(true);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans));
}
}
}
@Override
public void onBackPress() {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
finishECR();
}
}
popBackStack();
}
private void printReceipt(boolean isMerchantCopy) {
if (PrintHelper.getInstance().paperRollStatus() == SdkResult.Printer_PaperLack) {
showPrinterAlertDialog(getResourceString(R.string.txt_paper_roll_empty), new DialogCallback() {
@Override
public void onClickCancel() {
dismissPrinterAlertDialog();
}
@Override
public void onClickRetry() {
cancelTimeout();
setUpTimer();
dismissPrinterAlertDialog();
if (PrintHelper.getInstance().paperRollStatus() == SdkResult.Printer_PaperLack) {
return;
}
printReceipt();
}
});
if(SystemParamsOperation.getInstance().isAlertSound()) {
startSound(getResourceString(R.string.txt_audio_empty_paper_alert));
}
} else if (PrintHelper.getInstance().paperRollStatus() == SdkResult.Success) {
printReceipt();
}
}
private void printReceipt() {
PrintXReceipt.getInstance().printSmileReceipt(sharedViewModel.payDetail.getValue(), isMerchantCopy, new PrintXStatus() {
@Override
public void onSuccess() {
if(!isMerchantCopy) {
delayFunctionCall(ConfirmTransactionFragment.this::callMainScreen);
}
toggleCustomerMerchant();
}
@Override
public void onFailure() {
cancelTimeout();
printReceipt(isMerchantCopy);
}
});
}
private void toggleCustomerMerchant() {
isMerchantCopy = !isMerchantCopy;
sharedViewModel.reprintTransTypeMsg.postValue(getResourceString(R.string.txt_print_customer_copy));
}
public class ClickEvent {
public void onConfirm(){
if (sharedViewModel.transactionsType.getValue() == TransactionsType.TIP_ADJUSTMENT) {
routeId = R.id.action_confirmTransactionFragment_to_inputTipAmountFragment;
safeNavigateToRouteId();
} else {
routeId = R.id.action_confirmTransactionFragment_to_processingFragment;
safeNavigateToRouteId();
}
}
public void onCancel(){
ECRActionCancel();
callMainScreen();
}
public void onClose() {
popBackStack();
}
public void onPrint() {
printReceipt(isMerchantCopy);
}
}
}

View File

@ -0,0 +1,68 @@
package com.utsmm.kbz.ui.core_ui;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.InputTraceViewModel;
public class EditStanFragment extends DataBindingFragment {
private InputTraceViewModel inputTraceViewModel;
@Override
protected void initViewModel() {
inputTraceViewModel = getFragmentScopeViewModel(InputTraceViewModel.class);
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getResourceString(R.string.title_edit_stan));
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_edit_stan_screen, BR.inputTraceViewModel,inputTraceViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
protected int currentId() {
return R.id.editStanFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return 0;
}
public class ClickEvent {
public void onCancel() {
popBackStack();
}
public void onConfirm() {
String traceNo = inputTraceViewModel.invoiceNo.getValue();
if(traceNo != null && traceNo.length() > 0 && traceNo.length() <= 6) {
int trace = Integer.parseInt(traceNo);
SystemParamsOperation.getInstance().setSTAN(trace);
showSuccessDialog("Success!");
inputTraceViewModel.invoiceNo.setValue("");
} else {
showDeclineDialog("Invalid STAN!");
}
}
}
}

View File

@ -0,0 +1,295 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import com.sunmi.pay.hardware.aidlv2.bean.EMVCandidateV2;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.ui.ListDialog;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmyanmar.paylibs.utils.params.Params;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.EmvReadCardViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.ui.pre_auth.PreAuthCompViewModel;
import com.utsmm.kbz.util.enums.EmvReadStatus;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.util.ArrayList;
import java.util.List;
import com.utsmyanmar.paylibs.utils.LogUtil;
/**
* Currently this class is not used
*/
public class EmvReadCardFragment extends DataBindingFragment {
private EmvReadCardViewModel emvReadCardViewModel;
private SharedViewModel sharedViewModel;
private PreAuthCompViewModel preAuthCompViewModel;
private TransProcessViewModel transProcessViewModel;
private ListDialog mListDialog;
private static final String TAG = EmvReadCardFragment.class.getSimpleName();
private int routeID;
private int popBackID;
private List<PayDetail> lists = new ArrayList<>();
private String currentCardNo = "";
@Override
protected void initViewModel() {
emvReadCardViewModel = getFragmentScopeViewModel(EmvReadCardViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
preAuthCompViewModel = getFragmentScopeViewModel(PreAuthCompViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_emv_card_read, BR.emv,emvReadCardViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
protected int currentId() {
return 0;
}
@Override
protected int hostId() {
return 0;
}
@Override
protected int routeId() {
return 0;
}
@Override
public void onResume() {
super.onResume();
observeData();
}
@Override
public void onDestroyView() {
super.onDestroyView();
}
@Override
public void onDestroy() {
super.onDestroy();
emvReadCardViewModel.terminateTrans();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
emvReadCardViewModel.startProcess();
emvReadCardViewModel.resultStatus.observe(getViewLifecycleOwner(), new Observer<EmvReadStatus>() {
@Override
public void onChanged(EmvReadStatus emvReadStatus) {
switch (emvReadStatus){
case SUCCESS: emvReadCardViewModel.isButtonVisible.postValue(true);
currentCardNo = emvReadCardViewModel.cardNum.getValue();
break;
case FAIL: cardReadFailAction(emvReadCardViewModel.errorCode.getValue()); break;
case SELECT_APP: observeList();break;
}
}
});
}
private void cardReadFailAction(String message){
try{
if(message == null){
message = getResourceString(R.string.txt_card_read_fail);
}else if(message.contains(":")){
message = message.split(":")[1];
}
getNavController(Constants.NAV_HOST_ID).navigate(popBackID);
showSingleInfoDialog(message);
if(sharedViewModel.isEcr.getValue() != null){
if(sharedViewModel.isEcr.getValue()){
sharedViewModel.isEcr.postValue(false);
sharedViewModel.isEcrFinished.postValue(true);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(message);
// ECRHelper.INSTANCE.send(message.getBytes());
}
}
}catch (IllegalArgumentException e){
e.printStackTrace();
getNavController(Constants.NAV_HOST_ID).navigate(popBackID);
}
}
private void observeData(){
switch (sharedViewModel.transactionsType.getValue()){
case PRE_AUTH_COMPLETE:
observePreAuthComp();
routeID = R.id.action_emvReadCardFragment_to_inputRRNFragment;
popBackID = R.id.action_emvReadCardFragment_to_nav_main;
break;
case PRE_AUTH_VOID:
routeID = R.id.action_emvReadCardFragment_to_inputRRNFragment;
popBackID = R.id.action_emvReadCardFragment_to_nav_main;
break;
}
}
private void observePreAuthComp() {
preAuthCompViewModel.getPreAuthComData().observe(getViewLifecycleOwner(), new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
if(payDetails.size() > 0) {
LogUtil.d(TAG,"Pre Auth Comp size :"+payDetails.size());
lists.addAll(payDetails);
sharedViewModel.payDetailList.postValue(payDetails);
} else {
LogUtil.d(TAG,"Pre Auth Comp data not found!");
}
}
});
}
private boolean checkPreAuthCardNo() {
if(sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_VOID) {
return sharedViewModel.payDetail.getValue().getCardNo().equals(currentCardNo);
} else if (sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_COMPLETE) {
for(PayDetail payDetail: lists) {
if(payDetail.getCardNo().equals(currentCardNo)){
sharedViewModel.cardNo.postValue(currentCardNo);
return true;
}else{
LogUtil.d(TAG,"not found 1!");
}
}
return false;
}
else {
return true;
}
}
private void observeList(){
emvReadCardViewModel.emvList.observe(getViewLifecycleOwner(), new Observer<List<EMVCandidateV2>>() {
@Override
public void onChanged(List<EMVCandidateV2> emvCandidateV2s) {
showListDialog(emvCandidateV2s);
}
});
}
private void showListDialog(List<EMVCandidateV2> list) {
if (mListDialog == null) {
mListDialog = new ListDialog(getContext());
mListDialog.setTitleText(R.string.index_select_app);
mListDialog.setCancelable(true);
mListDialog.setCanceledOnTouchOutside(true);
}
List<String> tempList = new ArrayList<>();
for (EMVCandidateV2 emvCandidateV2 : list) {
tempList.add(emvCandidateV2.appLabel);
}
mListDialog.setData(tempList);
mListDialog.setOnItemClickListener(
position -> {
emvReadCardViewModel.setEmvAppSelect(position);
}
);
try {
mListDialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
private void buildCardData(){
TradeData tradeData = Params.newTrade(false);
PayDetail payDetails = tradeData.getPayDetail();
payDetails.setCardNo(emvReadCardViewModel.cardNum.getValue());
payDetails.setEXPDate(emvReadCardViewModel.expDate.getValue());
payDetails.setCardType(1);
payDetails.setAccountType("VISA");
payDetails.setCardHolderName("card holder");
// payDetails.setCardInfo();
transProcessViewModel.setTradeData(tradeData);
transProcessViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
}
private void checkRoute(){
buildCardData();
if(checkPreAuthCardNo()){
getNavController(Constants.NAV_HOST_ID).navigate(routeID);
}else{
showDeclineDialog("Mismatch Card No!");
}
}
public class ClickEvent {
public void onConfirm() {
checkRoute();
}
public void onCancel() {
if(sharedViewModel.isEcr.getValue() != null){
if(sharedViewModel.isEcr.getValue()){
sharedViewModel.isEcr.postValue(false);
sharedViewModel.isEcrFinished.postValue(true);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg("Canceled Transactions!");
// ECRHelper.INSTANCE.send("Canceled Transactions!".getBytes());
}
}
getNavController(Constants.NAV_HOST_ID).navigate(popBackID);
}
}
}

View File

@ -0,0 +1,443 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.navigation.NavController;
import androidx.navigation.NavDestination;
import com.utsmm.kbz.ui.pinpad.PinPadViewModel;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.ui.CustomPinPadKeyboard;
import com.utsmyanmar.baselib.ui.ListDialog;
import com.utsmyanmar.baselib.util.CardDetectCallback;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.checkxread.util.CardTypeX;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.databinding.FragmentEmvInputPinBinding;
import com.utsmm.kbz.ui.core_viewmodel.EmvTransactionProcessViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmyanmar.baselib.util.enums.PinUtil;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class EmvTransactionFragment extends DataBindingFragment {
private EmvTransactionProcessViewModel emvTransactionViewModel;
private PinPadViewModel pinPadViewModel;
private SharedViewModel sharedViewModel;
private static final String TAG = EmvTransactionFragment.class.getSimpleName();
private ListDialog mListDialog;
private TradeData tradeData;
private PayDetail payDetail;
private String ecrErrorMsg = "";
private int routeId;
private int cardType;
private CustomPinPadKeyboard customPinPadKeyboard;
private FragmentEmvInputPinBinding binding;
private final NavController.OnDestinationChangedListener listener = new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
if (destination.getId() == R.id.nav_main) {
ECRActionCancel(ecrErrorMsg);
emvTransactionViewModel.onCancelEmvTransaction();
}
}
};
@Override
protected void initViewModel() {
emvTransactionViewModel = getFragmentScopeViewModel(EmvTransactionProcessViewModel.class);
pinPadViewModel = getFragmentScopeViewModel(PinPadViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_emv_input_pin, BR.emv, emvTransactionViewModel)
.addBindingParam(BR.sharedViewModel, sharedViewModel);
}
@Override
protected int currentId() {
return R.id.emvTransactionFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
private void initSharedData() {
if (sharedViewModel.transactionsType.getValue() == TransactionsType.PIN_CHANGE) {
emvTransactionViewModel.pinUtil.postValue(PinUtil.OLD_PIN);
}
}
private void initData() {
tradeData = emvTransactionViewModel.getTradeData();
try {
payDetail = tradeData.getPayDetail();
cardType = payDetail.getCardType();
} catch (Exception e) {
e.printStackTrace();
showDeclineDialog(getResourceString(R.string.txt_please_try_again));
navigateToMain();
}
String amount = sharedViewModel.amount.getValue();
String processCode = sharedViewModel.processCode.getValue();
payDetail.setAmount(POSUtil.getInstance().convertAmount(amount));
if (!TextUtils.equals(processCode, "")) {
payDetail.setProcessCode(processCode);
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding = (FragmentEmvInputPinBinding) mBinding;
emvTransactionViewModel.customPinPadKeyboard = binding.customPinPad;
initSharedData();
initData();
if(isNotManualTransaction())
emvTransactionViewModel.startProcess();
else {
if(SystemParamsOperation.getInstance().isManualEntryPinEnable()) {
pinPadViewModel.setTradeData(tradeData);
navigateToPinPad();
} else {
navigateToProcessing();
}
}
observeEmvResultStatus();
}
private boolean isNotManualTransaction() {
return cardType != CardTypeX.MANUAL.value;
}
private void showConfirmCodeVerifyDialog() {
new AlertDialog.Builder(requireContext())
.setTitle("See Phone")
.setMessage("execute See Phone flow")
.setPositiveButton("OK", (dia, which) -> {
dia.dismiss();
// Restart transaction procedure.
try {
// mEMVOptV2.initEmvProcess();
// checkCard();
navigateToCheckCard();
} catch (Exception e) {
e.printStackTrace();
}
}
).show();
}
private void navigateToPinPad() {
routeId = R.id.action_emvTransactionFragment_to_pinPadFragment;
safeNavigateToRouteId();
}
private void isCardTaped(String alertMsg) {
isCardTaped(alertMsg,this::navigateToCheckCard);
}
private void observeEmvResultStatus() {
emvTransactionViewModel.emvResultStatus.observe(getViewLifecycleOwner(), emvResultStatus -> {
LogUtil.d(TAG, "EMV Result Status : " + emvResultStatus);
switch (emvResultStatus) {
case SELECT_APP:
observeCandiList();
break;
case READ_CARD:
isCardInserted(new CardDetectCallback() {
@Override
public void onComplete() {
sharedViewModel.setIsFallback(true);
navigateToCheckCard();
}
});
break;
case PIN_PAD_CANCEL:
navigateToMain();
break;
case ON_NEXT_SCREEN:
navigateToRRNScreen();
break;
case READ_CARD_RETRY:
sharedViewModel.set_errorFragmentMsg("Interface not found!");
navigateToError();
break;
case READ_CARD_NO_APP:
isCardTaped("Terminal has no APP!");
break;
case TRY_AGAIN:
sharedViewModel.set_errorFragmentMsg("Please replace the card");
navigateToError();
break;
case OFFLINE_DECLINE:
sharedViewModel.set_errorFragmentMsg("Offline Denial");
navigateToError();
break;
case CONFIRM_CODE_VERIFY:
showConfirmCodeVerifyDialog();
break;
case SECONDARY:
LogUtil.d(TAG, "TRY_SECONDARY Here!");
dismissLoadingDialog();
showLoadingDialog("Sending secondary.....");
break;
// new code
case PIN_MISMATCH:
showDeclineDialog("PIN MISMATCH!");
navigateToMain();
break;
case SUCCESS:
navigateToProcessing();
break;
case SUCCESS_ONLINE:
case FAIL_ONLINE:
updateData();
dismissLoadingDialog();
navigateToNext();
break;
case REVERSAL_PROCESS:
dismissLoadingDialog();
showLoadingDialog("Sending reversal.....");
break;
case REVERSAL_SECONDARY:
dismissLoadingDialog();
showLoadingDialog("Sending reversal secondary...");
break;
case REVERSAL_FAIL:
ECRActionCancel("Reversal failed!");
dismissLoadingDialog();
showDeclineDialog("Reversal failed!");
navigateToMain();
break;
case REVERSAL_SUCCESS:
ECRActionCancel("Reversal success!");
dismissLoadingDialog();
showSuccessDialog("Reversal success!");
navigateToMain();
break;
case FAIL:
showDeclineDialog("");
dismissLoadingDialog();
navigateToMain();
break;
case NETWORK_ERROR:
dismissLoadingDialog();
showDeclineDialog("Com Error!");
navigateToMain();
break;
case ERROR:
observeEmvErrorCode();
break;
default:
LogUtil.d(TAG,"EmvResult Status : "+emvResultStatus);
break;
}
});
}
private void observeEmvErrorCode() {
dismissLoadingDialog();
emvTransactionViewModel.errorCodeMsg.observe(getViewLifecycleOwner(), pair -> {
LogUtil.e(TAG, "ERROR CODE MSG :" + pair);
if (!TextUtils.equals(pair, "")) {
if (pair.contains(":")) {
String code = pair.split(":")[0];
String msg = pair.split(":")[1];
if (TextUtils.equals(code, "-4100") || TextUtils.equals(code, "-4125")) {
sharedViewModel.set_errorFragmentMsg("Card read failed!");
} else {
sharedViewModel.set_errorFragmentMsg(code + "\n" + msg);
}
ecrErrorMsg = msg;
} else {
ecrErrorMsg = pair;
sharedViewModel.set_errorFragmentMsg(pair);
}
} else {
sharedViewModel.set_errorFragmentMsg("Emv process timeout!");
ecrErrorMsg = "Emv process timeout!";
}
navigateToError();
});
}
private void ECRActionCancel(String message) {
if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) {
LogUtil.d(TAG, "isECR true");
sharedViewModel.isEcrFinished.postValue(true);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(message);
if (isEmvTrans()) {
emvTransactionViewModel.onCancelEmvTransaction();
}
}
}
private boolean isEmvTrans() {
return sharedViewModel.isEmv.getValue() != null && sharedViewModel.isEmv.getValue();
}
private void updateData() {
emvTransactionViewModel.payDetailResult.observe(getViewLifecycleOwner(), payDetail -> {
sharedViewModel.payDetail.setValue(payDetail);
});
}
@Override
public void onResume() {
super.onResume();
emvTransactionViewModel.resetUI();
getNavController(Constants.NAV_HOST_ID).addOnDestinationChangedListener(listener);
}
@Override
public void onPause() {
super.onPause();
resetEmvResult();
// enableNavigationBar();
getNavController(Constants.NAV_HOST_ID).removeOnDestinationChangedListener(listener);
}
private void resetEmvResult() {
emvTransactionViewModel.resetTransactionStatus();
}
private void navigateToNext() {
routeId = R.id.action_emvTransactionFragment_to_transactionResultFragment;
safeNavigateToRouteId();
}
private void navigateToProcessing() {
routeId = R.id.action_emvTransactionFragment_to_processingFragment;
safeNavigateToRouteId();
}
private void navigateToMain() {
routeId = R.id.action_emvTransactionFragment_to_nav_main;
safeNavigateToRouteId();
}
private void navigateToError() {
routeId = R.id.action_emvTransactionFragment_to_errorFragment;
safeNavigateToRouteId();
}
private void navigateToCheckCard() {
routeId = R.id.action_emvTransactionFragment_to_cardWaitingFragment;
safeNavigateToRouteId();
}
private void navigateToRRNScreen() {
routeId = R.id.action_emvTransactionFragment_to_inputRRNFragment;
safeNavigateToRouteId();
}
private void observeCandiList() {
emvTransactionViewModel.candiList.observe(getViewLifecycleOwner(), this::showCandiListDialog);
}
private void showCandiListDialog(String[] list) {
if (mListDialog == null) {
mListDialog = new ListDialog(requireContext());
mListDialog.setTitleText(R.string.index_select_app);
mListDialog.setCancelable(true);
mListDialog.setCanceledOnTouchOutside(true);
}
List<String> tempList = new ArrayList<>(Arrays.asList(list));
mListDialog.setData(tempList);
mListDialog.setOnItemClickListener(
position -> {
LogUtil.d(TAG,"SELECTED APP:"+list[position]);
emvTransactionViewModel.setEmvAppSelect(position);
}
);
try {
mListDialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,78 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class ErrorFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_error_screen, BR.sharedViewModel,sharedViewModel );
}
@Override
protected int currentId() {
return R.id.errorFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return R.id.action_errorFragment_to_nav_main;
}
@Override
public void onResume() {
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_error));
delayFunctionCall(this::navigateToMain,2000);
super.onResume();
}
@Override
public void onPause() {
super.onPause();
sharedViewModel.setTransMenu(null);
}
private void navigateToMain() {
LogUtil.d("ERROR Fragment","navigating to Main....");
safeNavigateToRouteId();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
}

View File

@ -0,0 +1,242 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.CardDetectCallback;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsSettings;
import com.utsmyanmar.paylibs.utils.enums.InvalidAmount;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.InputAmountViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.util.Objects;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class InputAmountFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback{
private static final String TAG = InputAmountFragment.class.getSimpleName();
private InputAmountViewModel inputAmountViewModel;
private SharedViewModel sharedViewModel;
private TransProcessViewModel transProcessViewModel;
private int routeId;
@Override
protected void initViewModel() {
inputAmountViewModel = getFragmentScopeViewModel(InputAmountViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_amount_screen, BR.inputAmountVM,inputAmountViewModel)
.addBindingParam(BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
protected int currentId() {
return R.id.inputAmountFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setUpTimer();
setupBackButtonPressDetection(this);
}
private void setUpTimer(){
setupTimeout(Constants.TIMEOUT, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
routeId = R.id.action_inputAmountFragment_to_timeoutFragment;
safeNavigateToRouteId();
}
});
}
/*May 16 2022*/
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getResourceString(R.string.txt_subtitle_amount));
if(sharedViewModel.isEcr.getValue() != null){
if(sharedViewModel.isEcr.getValue()){
delayFunctionCall(()->{
observeRouteId(true);
});
}
}
inputAmountViewModel.inputAmountView.setValue("0");
inputAmountViewModel.invalidAmountMsg.setValue("");
}
@Override
public void onPause() {
super.onPause();
inputAmountViewModel.inputAmountView.postValue("0");
}
private void finishECR() {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg("Invalid Amount!");
sharedViewModel.isEcr.postValue(false);
getNavController(Constants.NAV_HOST_ID).popBackStack();
}
private void observeRouteId(boolean isECR) {
if(sharedViewModel.transactionsType.getValue() == TransactionsType.MMQR) {
// here implement logic for min - max amount QR
String minAmount;
String maxAmount;
if(SystemParamsOperation.getInstance().getMinAmount() != null && !SystemParamsOperation.getInstance().getMinAmount().isEmpty() && SystemParamsOperation.getInstance().getMaxAmount() != null && !SystemParamsOperation.getInstance().getMaxAmount().isEmpty()) {
minAmount = SystemParamsOperation.getInstance().getMinAmount();
maxAmount = SystemParamsOperation.getInstance().getMaxAmount();
} else {
minAmount = "0";
maxAmount = "99999999";
}
if(POSUtil.getInstance().checkMinMaxAmount(sharedViewModel.amount.getValue(),minAmount,maxAmount) == InvalidAmount.OKAY) {
routeId = R.id.action_inputAmountFragment_to_QRConnectingFragment;
safeNavigateToRouteId();
} else {
// routeId = R.id.action_inputAmountFragment_to_nav_main;
inputAmountViewModel.invalidAmountMsg.setValue(POSUtil.getInstance().checkMinMaxAmount(sharedViewModel.amount.getValue(),minAmount,maxAmount).msg);
}
} else {
sharedViewModel.setAmountExist(true);
if(sharedViewModel.getCardDataExist().getValue() != null && sharedViewModel.getCardDataExist().getValue()) {
routeId = R.id.action_inputAmountFragment_to_pinPadFragment;
} else {
routeId = R.id.action_inputAmountFragment_to_cardWaitingFragment;
}
safeNavigateToRouteId();
}
}
@Override
public void onBackPress() {
checkCard();
}
private void checkCard() {
isCardInserted(new CardDetectCallback() {
@Override
public void onComplete() {
LogUtil.d(TAG,"Going to main");
safePopBackStack();
// delayFunctionCall(()->{
// LogUtil.d(TAG,"popup stack!");
//
// });
}
});
}
public class ClickEvent{
public void onConfirm(){
if(isInputValid(Objects.requireNonNull(inputAmountViewModel.inputAmountView.getValue()))){
inputAmountViewModel.invalidAmountMsg.setValue("");
boolean decimalEnabled = SystemParamsOperation.getInstance().getDecimalEnable();
String inputValue = inputAmountViewModel.inputAmountView.getValue();
if (decimalEnabled) {
// SMILE requested to add ".00" even they type non decimal amount...
// 23/09/2024
if (!inputValue.contains(".")) {
sharedViewModel.amount.setValue(inputValue + ".00");
} else {
sharedViewModel.amount.setValue(inputValue);
}
} else {
// If decimal is not enabled, only allow integer values.
if (inputValue.contains(".")) {
// Show error if decimals are entered when disabled
showSingleInfoDialog("Decimal values are not allowed.");
return;
} else {
sharedViewModel.amount.setValue(inputValue);
}
}
observeRouteId(false);
} else {
showSingleInfoDialog(getResourceString(R.string.txt_please_input_amount));
}
}
public void onCancel() {
checkCard();
}
}
}

View File

@ -0,0 +1,172 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.InputApprovalViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class InputApprovalFragment extends DataBindingFragment {
private static final String TAG = InputApprovalFragment.class.getSimpleName();
private InputApprovalViewModel inputApprovalViewModel;
private SharedViewModel sharedViewModel;
private TransProcessViewModel transProcessViewModel;
private String approvalCode = "";
private int routeId;
@Override
protected void initViewModel() {
inputApprovalViewModel = getFragmentScopeViewModel(InputApprovalViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_input_approval_screen, BR.approvalViewModel,inputApprovalViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
protected int currentId() {
return R.id.inputApprovalFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onResume() {
super.onResume();
if(sharedViewModel.isEcr.getValue() != null){
if(sharedViewModel.isEcr.getValue()){
approvalCode = sharedViewModel.approvalCode.getValue();
delayFunctionCall(()-> {
validateApprovalCode(true);
});
}
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setUpTimer();
}
private void setUpTimer(){
setupTimeout(Constants.TIMEOUT, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
routeId = R.id.action_inputApprovalFragment_to_timeoutFragment;
safeNavigateToRouteId();
}
});
}
private void navigationECR(){
CoreUtils.getInstance(sharedViewModel).responseRejectMsg("Approval Not Match!");
getNavController(Constants.NAV_HOST_ID).popBackStack();
}
private void checkApproval(boolean isECR) {
sharedViewModel.payDetail.observe(getViewLifecycleOwner(), payDetail -> {
if( payDetail != null ) {
LogUtil.d(TAG,"approval code: "+payDetail.getApprovalCode());
if(payDetail.getApprovalCode().equals(approvalCode)) {
transProcessViewModel.setPayDetail(payDetail);
//route to confirm fragment
routeId = R.id.action_inputApprovalFragment_to_confirmTransactionFragment;
safeNavigateToRouteId();
} else {
if(isECR)
navigationECR();
showDeclineDialog(getResourceString(R.string.txt_please_enter_correct_approval));
}
} else {
if(isECR)
navigationECR();
showDeclineDialog(getResourceString(R.string.txt_please_enter_correct_approval));
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
sharedViewModel.isEcr.postValue(false);
sharedViewModel.approvalCode.postValue(null);
sharedViewModel.rrNNo.postValue(null);
}
private void validateApprovalCode(boolean isECR) {
if (!TextUtils.equals(approvalCode,"") && approvalCode.length() == 6) {
checkApproval(isECR);
} else {
showDeclineDialog(getResourceString(R.string.txt_please_enter_approval));
}
}
public class ClickEvent{
public void onCancel() {
popBackStack();
}
public void onConfirm() {
approvalCode = inputApprovalViewModel.txtApproval.getValue();
validateApprovalCode(false);
}
}
}

View File

@ -0,0 +1,262 @@
package com.utsmm.kbz.ui.core_ui;
import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.CardDetectCallback;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.InputPasswordViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.util.enums.InputPasswordType;
import java.util.Objects;
public class InputPasswordFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback {
private static final String TAG = InputPasswordFragment.class.getSimpleName();
private InputPasswordViewModel inputPasswordViewModel;
private static final String PRE_AUTH_COMPLETE = "PRE_AUTH_COMPLETE";
private static final String SALE = "SALE";
private SharedViewModel sharedViewModel;
private int routeId;
private OnFragmentInteractionListener mListener;
@Override
protected void initViewModel() {
inputPasswordViewModel = getFragmentScopeViewModel(InputPasswordViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_password_screen, BR.passwordViewModel, inputPasswordViewModel)
.addBindingParam(BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.inputPasswordFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
@Override
public void onDetach() {
super.onDetach();
mListener = null;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setUpTimer();
setupBackButtonPressDetection(this);
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getResourceString(R.string.title_password));
try{
checkRoute();
} catch (NullPointerException e){
e.printStackTrace();
showShortToast(getResourceString(R.string.txt_cannot_find_route));
routeId = R.id.action_inputPasswordFragment_to_nav_main;
safeNavigateToRouteId();
}
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
safeNavigateToRouteId();
}
}
// disableNavigationBar();
}
@Override
public void onPause() {
super.onPause();
inputPasswordViewModel.passwordType.postValue(null);
// enableNavigationBar();
}
@Override
public void onDestroyView() {
super.onDestroyView();
clearLiveData();
}
private void clearLiveData() {
inputPasswordViewModel.clearInput();
inputPasswordViewModel.passwordInput.postValue("");
inputPasswordViewModel.maskedPassword.postValue("");
}
private void checkRoute() {
switch (Objects.requireNonNull(sharedViewModel.transactionsType.getValue())) {
case PRE_AUTH_COMPLETE_VOID:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
sharedViewModel.transactionName.postValue(getResourceString(R.string.title_pre_auth_complete));
sharedViewModel.setTransMenu(TransMenu.PRE_AUTH_COMPLETE_VOID);
routeId = R.id.action_inputPasswordFragment_to_inputTraceFragment;
// routeId = R.id.action_inputPasswordFragment_to_selectHostFragment;
break;
case TIP_ADJUSTMENT:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
sharedViewModel.transactionName.postValue(SALE);
sharedViewModel.setTransMenu(TransMenu.TIP_ADJUSTMENT);
routeId = R.id.action_inputPasswordFragment_to_selectHostFragment;
break;
case VOID:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
sharedViewModel.transactionName.postValue(SALE);
sharedViewModel.setTransMenu(TransMenu.VOID);
routeId = R.id.action_inputPasswordFragment_to_inputTraceFragment;
// routeId = R.id.action_inputPasswordFragment_to_selectHostFragment;
break;
case PRE_AUTH_VOID:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
if(sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_FULL_VOID) {
routeId = R.id.action_inputPasswordFragment_to_selectHostFragment;
} else {
routeId = R.id.action_inputPasswordFragment_to_inputAmountFragment;
}
break;
case REFUND:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
routeId = R.id.action_inputPasswordFragment_to_selectRefundFragment;
break;
case PRE_AUTH_COMPLETE:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
routeId = R.id.action_inputPasswordFragment_to_inputAmountFragment;
break;
case SETTLEMENT:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SETTLEMENT);
routeId = R.id.action_inputPasswordFragment_to_settlementTransactionFragment;
break;
case SETTING:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SETTING);
routeId = R.id.action_inputPasswordFragment_to_nav_main;
break;
case FUNCTION:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SETTING);
routeId = R.id.action_inputPasswordFragment_to_nav_settings;
break;
case CLEAR_BATCH:
case CLEAR_REVERSAL:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
routeId = R.id.action_inputPasswordFragment_to_selectHostFragment;
break;
}
}
@Override
public void onBackPress() {
checkCard();
}
private void setUpTimer(){
setupTimeout(Constants.TIMEOUT, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
routeId = R.id.action_inputPasswordFragment_to_timeoutFragment;
safeNavigateToRouteId();
}
});
}
public interface OnFragmentInteractionListener {
void onSuccess();
}
private void checkCard() {
isCardInserted(new CardDetectCallback() {
@Override
public void onComplete() {
delayFunctionCall(()->{
safePopBackStack();
});
}
});
}
public class ClickEvent {
public void onConfirm() {
if(inputPasswordViewModel.onClickEnter()) {
clearLiveData();
if(sharedViewModel.transactionsType.getValue() == TransactionsType.SETTING) {
mListener.onSuccess();
}
safeNavigateToRouteId();
} else {
clearLiveData();
Toast.makeText(getContext(), "Wrong Password", Toast.LENGTH_LONG).show();
}
}
public void onCancel() {
checkCard();
}
}
}

View File

@ -0,0 +1,696 @@
package com.utsmm.kbz.ui.core_ui;
import android.content.Context;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import androidx.navigation.NavController;
import androidx.navigation.NavDestination;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.CardDetectCallback;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.databinding.FragmentInputRrnScreenBinding;
import com.utsmm.kbz.ui.core_viewmodel.EmvTransactionProcessViewModel;
import com.utsmm.kbz.ui.core_viewmodel.InputRRNViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class InputRRNFragment extends DataBindingFragment {
private static final String TAG = InputRRNFragment.class.getSimpleName();
private SharedViewModel sharedViewModel;
private InputRRNViewModel rrnViewModel;
private TransProcessViewModel transProcessViewModel;
private EmvTransactionProcessViewModel emvTransactionProcessViewModel;
private String rrnNo = "";
private String cardNo = "";
private int routeId;
private FragmentInputRrnScreenBinding binding;
private EditText etRRN;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
rrnViewModel = getFragmentScopeViewModel(InputRRNViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
emvTransactionProcessViewModel = getFragmentScopeViewModel(EmvTransactionProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_input_rrn_screen, BR.inputRRNVM, rrnViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.inputRRNFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
private final NavController.OnDestinationChangedListener listener = new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
if (destination.getId() == R.id.nav_main) {
if(isEmvTrans()) {
emvTransactionProcessViewModel.onCancelEmvTransaction();
}
}
}
};
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setUpTimer();
etRRN = mBinding.getRoot().findViewById(R.id.et_rrn);
etRRN.setOnKeyListener(new View.OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
cancelTimeout();
setUpTimer();
}
return false;
}
});
}
private void setUpTimer(){
setupTimeout(Constants.TIMEOUT , new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
routeId = R.id.action_inputRRNFragment_to_timeoutFragment;
safeNavigateToRouteId();
}
});
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getResourceString(R.string.title_reference_number));
getNavController(Constants.NAV_HOST_ID).addOnDestinationChangedListener(listener);
showKeyboard();
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
rrnNo = sharedViewModel.rrNNo.getValue();
delayFunctionCall(()-> {
validateRRN(true);
});
}
}
}
public void showKeyboard(){
etRRN.requestFocus();
InputMethodManager imm = (InputMethodManager)requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
}
public void closeKeyboard(){
InputMethodManager imm = (InputMethodManager) requireActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(etRRN.getWindowToken(), 0);
etRRN.clearFocus();
}
@Override
public void onPause() {
super.onPause();
closeKeyboard();
rrnViewModel.txtRRN.setValue("");
resetEmvResult();
getNavController(Constants.NAV_HOST_ID).removeOnDestinationChangedListener(listener);
}
private void resetEmvResult() {
emvTransactionProcessViewModel.resetTransactionStatus();
}
private void callNextScreen(){
routeId = R.id.action_inputRRNFragment_to_processingFragment;
safeNavigateToRouteId();
}
private void callResultScreen() {
routeId = R.id.action_inputRRNFragment_to_transactionResultFragment;
safeNavigateToRouteId();
}
private void checkRRNPreAuthVoid(boolean isECR) {
rrnViewModel.searchPayDetail(cardNo,rrnNo).observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
if(payDetail != null) {
Date transDate = POSUtil.getInstance().getDateByString(payDetail.getTransDate());
if(payDetail.getTransactionType() != TransactionsType.PRE_AUTH_SALE.value) {
terminateProcess(isECR);
return;
}
PayDetail newPay;
if(isEmvTrans()) {
newPay = emvTransactionProcessViewModel.getPayDetail();
} else {
newPay = transProcessViewModel.getPayDetail();
}
newPay.setReferNo(rrnNo);
if(sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_FULL_VOID) {
newPay.setAmount(payDetail.getAmount());
}
newPay.setTradeDateTime(payDetail.getTradeDateTime());
if(isEmvTrans()) {
emvTransactionProcessViewModel.setOldTransPayDetail(payDetail);
newPay.setCardInfo(payDetail.getCardInfo());
emvTransactionProcessViewModel.setPayDetail(newPay);
} else {
transProcessViewModel.setOldTransPayDetail(payDetail);
transProcessViewModel.setPayDetail(newPay);
}
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen();
} else {
terminateProcess(isECR);
}
}
});
}
private void terminateProcess(boolean isECR) {
showDeclineDialog(getResourceString(R.string.txt_ref_no_not_found));
if (isECR) {
navigationECR();
} else {
routeId = R.id.action_inputRRNFragment_to_nav_main;
safeNavigateToRouteId();
}
}
private int getConfigDay() {
int configDay = 10;
String configRawDay = SystemParamsOperation.getInstance().getClearBatchDay();
if(configRawDay != null && !configRawDay.trim().isEmpty()) {
try {
configDay = Integer.parseInt(configRawDay);
} catch (Exception e) {
e.printStackTrace();
}
}
return configDay;
}
private boolean isEmvTrans() {
return sharedViewModel.isEmv.getValue() != null && sharedViewModel.isEmv.getValue();
}
private void preAuthCompProcess(boolean isECR) {
Date lastInputDay = POSUtil.getInstance().getLastInputDay(getConfigDay());
rrnViewModel.searchPayDetail(cardNo,rrnNo).observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
if(payDetail != null) {
LogUtil.d(TAG,"Transaction Type : "+payDetail.getTransType());
LogUtil.d(TAG,"Transaction Amount : "+payDetail.getAmount());
LogUtil.d(TAG,"Transaction Date/Time : "+payDetail.getTransDate()+"/"+payDetail.getTransTime());
LogUtil.d(TAG,"RRN/Trace : "+payDetail.getReferNo()+"/"+payDetail.getVoucherNo());
LogUtil.d(TAG,"Transaction is canceled : "+payDetail.isCanceled());
LogUtil.d(TAG,"----------------------------------------------------------");
Date transDate = POSUtil.getInstance().getDateByString(payDetail.getTransDate()) ;
// transaction type must be pre auth & must be within 10 days.
if (payDetail.getTransactionType() == TransactionsType.PRE_AUTH_SALE.value && lastInputDay.compareTo(transDate) < 0) {
PayDetail newPay = new PayDetail();
if(isEmvTrans()) {
newPay = emvTransactionProcessViewModel.getPayDetail();
} else {
newPay = transProcessViewModel.getPayDetail();
}
newPay.setReferNo(rrnNo);
if(newPay.getAmount() > payDetail.getAmount()) {
newPay.setTradeAnswerCode("C1"); // ---> refer to BaseErrorCode class// ,
newPay.setTransType(sharedViewModel.transactionsType.getValue().name);
if(isEmvTrans()) {
emvTransactionProcessViewModel.setPayDetail(newPay);
} else {
transProcessViewModel.setPayDetail(newPay);
}
sharedViewModel.payDetail.setValue(newPay);
sharedViewModel.rrNNo.setValue(rrnNo);
callResultScreen();
return;
} else {
if(isEmvTrans()) {
emvTransactionProcessViewModel.setOldTransPayDetail(payDetail);
emvTransactionProcessViewModel.setPayDetail(newPay);
} else {
transProcessViewModel.setOldTransPayDetail(payDetail);
transProcessViewModel.setPayDetail(newPay);
}
sharedViewModel.rrNNo.setValue(rrnNo);
}
// transProcessViewModel.setPayDetail(newPay);
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen();
} else {
isCardInserted(new CardDetectCallback() {
@Override
public void onComplete() {
showDeclineDialog(getResourceString(R.string.txt_ref_no_not_found));
if (isECR) {
navigationECR();
} else {
routeId = R.id.action_inputRRNFragment_to_nav_main;
safeNavigateToRouteId();
}
}
});
}
} else {
isCardInserted(new CardDetectCallback() {
@Override
public void onComplete() {
showDeclineDialog(getResourceString(R.string.txt_ref_no_not_found));
if (isECR) {
navigationECR();
} else {
routeId = R.id.action_inputRRNFragment_to_nav_main;
safeNavigateToRouteId();
}
}
});
}
}
});
}
private void checkRRNPreAuthComp(boolean isECR) {
// pre auth complete doesn't need exact date time of pre auth sale.
// need to check it
//**************************************************//
// This code block is used in certification process //
//**************************************************//
/* PayDetail payDetail = transProcessViewModel.getPayDetail();
payDetail.setReferNo(rrnNo);
transProcessViewModel.setPayDetail(payDetail);
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen();*/
Date lastInputDay = POSUtil.getInstance().getLastInputDay(getConfigDay());
rrnViewModel.searchPayDetail(cardNo,rrnNo).observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
if(payDetail != null) {
LogUtil.d(TAG,"Transaction Type : "+payDetail.getTransType());
LogUtil.d(TAG,"Transaction Amount : "+payDetail.getAmount());
LogUtil.d(TAG,"Transaction Date/Time : "+payDetail.getTransDate()+"/"+payDetail.getTransTime());
LogUtil.d(TAG,"RRN/Trace : "+payDetail.getReferNo()+"/"+payDetail.getVoucherNo());
LogUtil.d(TAG,"Transaction is canceled : "+payDetail.isCanceled());
LogUtil.d(TAG,"----------------------------------------------------------");
Date transDate = POSUtil.getInstance().getDateByString(payDetail.getTransDate()) ;
// transaction type must be pre auth & must be within 10 days.
if (payDetail.getTransactionType() == TransactionsType.PRE_AUTH_SALE.value && lastInputDay.compareTo(transDate) < 0) {
PayDetail newPay = transProcessViewModel.getPayDetail();
newPay.setReferNo(rrnNo);
if(newPay.getAmount() > payDetail.getAmount()) {
newPay.setTradeAnswerCode("C1"); // ---> refer to BaseErrorCode class// ,
newPay.setTransType(sharedViewModel.transactionsType.getValue().name);
transProcessViewModel.setPayDetail(newPay);
sharedViewModel.payDetail.setValue(newPay);
sharedViewModel.rrNNo.setValue(rrnNo);
callResultScreen();
} else {
transProcessViewModel.setOldTransPayDetail(payDetail);
transProcessViewModel.setPayDetail(newPay);
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen();
}
transProcessViewModel.setPayDetail(newPay);
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen();
} else {
showDeclineDialog(getResourceString(R.string.txt_ref_no_not_found));
if (isECR) {
navigationECR();
} else {
routeId = R.id.action_inputRRNFragment_to_nav_main;
safeNavigateToRouteId();
}
}
} else {
showDeclineDialog(getResourceString(R.string.txt_ref_no_not_found));
if (isECR) {
navigationECR();
} else {
routeId = R.id.action_inputRRNFragment_to_nav_main;
safeNavigateToRouteId();
}
}
}
});
}
private void refundProcessEmv(boolean isECR) {
PayDetail payDetail = emvTransactionProcessViewModel.getPayDetail();
payDetail.setReferNo(rrnNo);
emvTransactionProcessViewModel.setPayDetail(payDetail);
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen();
}
private void checkRRNRefund(boolean isECR) {
/* 19/1/2024 Working Code! just commented for new requirements ! */
/* PayDetail payDetail = transProcessViewModel.getPayDetail();
payDetail.setReferNo(rrnNo);
transProcessViewModel.setPayDetail(payDetail);
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen(); */
String configTimer = SystemParamsOperation.getInstance().getClearBatchTime();
String configTime;
if(configTimer != null && !configTimer.trim().isEmpty() && checkValidTime(configTimer.trim())) {
configTime = configTimer.trim();
} else {
configTime = "23:00";
}
rrnViewModel.searchPayDetail(cardNo,rrnNo).observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
if(payDetail != null) {
LogUtil.d(TAG,"Trans Type:"+payDetail.getTransactionType());
if(payDetail.getTransactionType() != TransactionsType.SALE.value) {
terminatedTransRefund(isECR);
return;
}
String date = payDetail.getTransDate();
String time = payDetail.getTransTime();
if(checkRefund(configTime,date,time)) {
PayDetail newPay = transProcessViewModel.getPayDetail();
newPay.setReferNo(rrnNo);
transProcessViewModel.setOldTransPayDetail(payDetail);
transProcessViewModel.setPayDetail(newPay);
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen();
} else {
terminatedTransRefund(isECR);
}
} else {
PayDetail newPay = transProcessViewModel.getPayDetail();
newPay.setReferNo(rrnNo);
transProcessViewModel.setPayDetail(newPay);
sharedViewModel.rrNNo.setValue(rrnNo);
callNextScreen();
}
}
});
}
private void terminatedTransRefund(boolean isECR) {
showDeclineDialog(getResourceString(R.string.txt_refund_not_allow));
if (isECR) {
navigationECR();
} else {
routeId = R.id.action_inputRRNFragment_to_nav_main;
safeNavigateToRouteId();
// safePopBack(currentId,hostId);
}
}
private boolean checkRefund(String configTime,String date,String time) {
Date yesterday = POSUtil.getInstance().getYesterdayConfigDateTime(configTime);
Date transDateTime = POSUtil.getInstance().getDateByTransDateTime(date,time);
Date configDate = POSUtil.getInstance().getDateTime(configTime);
Date transDate = POSUtil.getInstance().getDateByString(date);
Date today = POSUtil.getInstance().getCurrentDate();
Date current = new Date(System.currentTimeMillis());
System.out.println("Yesterday : "+yesterday.toString());
System.out.println("transDateTime : "+transDateTime.toString());
System.out.println("Compare : "+transDateTime.compareTo(yesterday));
if(transDate.compareTo(today) == 0 ) {
// trans is today
if(current.compareTo(configDate) > 0) {
System.out.println("Trans is today ! config time is passed yet! can do refund!");
return transDateTime.compareTo(configDate) < 0;
} else {
System.out.println("Trans is today ! config time is not passed yet! can't do refund");
return false;
}
} else {
Date yest;
if(configTime.equals("00:00")) {
yest = configDate;
} else {
yest = yesterday;
}
System.out.println("Trans is Yesterday ! trans is before config time ! can do refund!");
return transDateTime.compareTo(yest) < 0; //false
}
}
private void navigationECR() {
sharedViewModel.isEcrFinished.postValue(true);
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_rrn_not_match));
getNavController(Constants.NAV_HOST_ID).popBackStack();
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_VOID) {
sharedViewModel.traceNo.postValue(null);
sharedViewModel.rrNNo.postValue(null);
}
rrnViewModel.inputRRNView.removeObservers(getViewLifecycleOwner());
}
private static boolean isValidReferenceNo(String referNo) {
// Define a regular expression for a valid email address
String regex = "^[a-zA-Z0-9 \\\\t]{12}$";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(referNo);
return matcher.matches();
}
private void validateRRN(boolean isECR) {
if (isValidReferenceNo(rrnNo)) {
if (sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_VOID) {
checkRRNPreAuthVoid(isECR);
} else if (sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_COMPLETE) {
// checkRRNPreAuthComp(isECR);
preAuthCompProcess(isECR);
} else {
if(isEmvTrans()) {
refundProcessEmv(isECR);
} else {
checkRRNRefund(isECR);
}
}
} else {
if(isECR)
navigationECR();
showDeclineDialog(getResourceString(R.string.txt_please_enter_correct_rrn));
}
}
public class ClickEvent {
public void onCancel() {
routeId = R.id.action_inputRRNFragment_to_nav_main;
safeNavigateToRouteId();
}
public void onConfirm() {
if(isEmvTrans()) {
cardNo = emvTransactionProcessViewModel.cardNum.getValue();
} else {
cardNo = transProcessViewModel.getPayDetail().getCardNo();
}
rrnNo = rrnViewModel.txtRRN.getValue();
validateRRN(false);
}
}
}

View File

@ -0,0 +1,170 @@
package com.utsmm.kbz.ui.core_ui;
import android.text.TextUtils;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.InputAmountViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.EmvTransactionProcessViewModel;
import java.util.Objects;
public class InputTipAmountFragment extends DataBindingFragment {
private InputAmountViewModel inputAmountViewModel;
private SharedViewModel sharedViewModel;
private EmvTransactionProcessViewModel emvTransactionProcessViewModel;
private int routeId;
@Override
protected void initViewModel() {
inputAmountViewModel = getFragmentScopeViewModel(InputAmountViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
emvTransactionProcessViewModel = getFragmentScopeViewModel(EmvTransactionProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_tip_amount_screen, BR.inputAmountVM,inputAmountViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
protected int currentId() {
return R.id.inputTipAmountFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
/*May 16 2022*/
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getResourceString(R.string.title_tip_amount));
if(sharedViewModel.isEcr.getValue() != null){
if(sharedViewModel.isEcr.getValue()){
delayFunctionCall(()->{
startTransactionProcess(true);
});
}
}
}
@Override
public void onPause() {
super.onPause();
inputAmountViewModel.inputAmountView.postValue("0.00");
}
private void callNextScreen(){
routeId = R.id.action_inputTipAmountFragment_to_processingFragment;
safeNavigateToRouteId();
}
private void startTransactionProcess(boolean isEcr) {
String amount = "";
if(isEcr) {
amount = sharedViewModel.amount.getValue();
} else {
amount = inputAmountViewModel.inputAmountView.getValue();
sharedViewModel.amount.setValue(amount);
}
PayDetail payDetail = emvTransactionProcessViewModel.getPayDetail();
String processCode = sharedViewModel.processCode.getValue();
payDetail.setAmount(POSUtil.getInstance().convertAmount(amount));
if (!TextUtils.equals(processCode, "")) {
payDetail.setProcessCode(processCode);
}
emvTransactionProcessViewModel.setPayDetail(payDetail);
callNextScreen();
}
private boolean isAmountValid() {
String amount = inputAmountViewModel.inputAmountView.getValue();
if (amount != null ) {
if(amount.contains(",")){
amount = amount.replace(",","");
}
long amt = 0;
if(amount.contains(".")) {
amt = Long.parseLong(amount.substring(0,amount.length()-3));
} else {
amt = Long.parseLong(amount);
}
// 100 is amount from TMS
return amt <= 100;
}
return false;
}
public class ClickEvent{
public void onConfirm(){
if(isInputValid(Objects.requireNonNull(inputAmountViewModel.inputAmountView.getValue()))){
if(isAmountValid()) {
startTransactionProcess(false);
} else {
showSingleInfoDialog(getResourceString(R.string.txt_tip_amount_exceeded));
}
} else {
showSingleInfoDialog(getResourceString(R.string.txt_please_input_amount));
}
}
public void onCancel() {
popBackStack();
}
}
}

View File

@ -0,0 +1,451 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.EmvTransactionProcessViewModel;
import com.utsmm.kbz.ui.core_viewmodel.InputTraceViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.ui.pre_auth.PreAuthVoidViewModel;
import com.utsmm.kbz.ui.sale_void.VoidViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmyanmar.paylibs.utils.enums.HostType;
import com.utsmm.kbz.util.enums.VoidStatus;
import java.util.ArrayList;
import java.util.Objects;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class InputTraceNoFragment extends DataBindingFragment {
private static final String TAG = InputTraceNoFragment.class.getSimpleName();
private InputTraceViewModel traceViewModel;
private PreAuthVoidViewModel preAuthVoidViewModel;
private TransProcessViewModel transProcessViewModel;
private EmvTransactionProcessViewModel emvTransactionProcessViewModel;
private VoidViewModel voidViewModel;
private SharedViewModel sharedViewModel;
private boolean isContain = false;
private VoidStatus voidStatus = VoidStatus.NOT_FOUND;
private String traceNo = "";
private int routeId;
ArrayList<PayDetail> payLists = new ArrayList<>();
@Override
protected void initViewModel() {
traceViewModel = getFragmentScopeViewModel(InputTraceViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
preAuthVoidViewModel = getFragmentScopeViewModel(PreAuthVoidViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
voidViewModel = getFragmentScopeViewModel(VoidViewModel.class);
emvTransactionProcessViewModel = getFragmentScopeViewModel(EmvTransactionProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_input_invoice_screen, BR.inputTraceViewModel, traceViewModel)
.addBindingParam(BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.voidViewModel, voidViewModel)
.addBindingParam(BR.transProcessViewModel, transProcessViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.inputTraceFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setUpTimer();
}
private void setUpTimer(){
setupTimeout(Constants.TIMEOUT, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
routeId = R.id.action_inputTraceFragment_to_timeoutFragment;
safeNavigateToRouteId();
}
});
}
@Override
public void onResume() {
super.onResume();
clearInputView();
setToolBarTitleWithBackIcon(getResourceString(R.string.title_trace_number));
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
/* init trace no from shared View model*/
traceNo = POSUtil.getInstance().formatTrace(Objects.requireNonNull(sharedViewModel.traceNo.getValue()));
delayFunctionCall(()->{
observeRouteId(true);
});
}
}
}
private void voidProcess(boolean isEcr) {
int transType = 0;
if(sharedViewModel.getTransMenu().getValue() == TransMenu.VOID || sharedViewModel.getTransMenu().getValue() == TransMenu.TIP_ADJUSTMENT) {
transType = TransactionsType.SALE.value;
} else if(sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_COMPLETE_VOID) {
transType = TransactionsType.PRE_AUTH_COMPLETE.value;
}
String configTimer = SystemParamsOperation.getInstance().getClearBatchTime();
String configTime;
if(configTimer != null && !configTimer.trim().isEmpty() && checkValidTime(configTimer.trim())) {
configTime = configTimer.trim();
} else {
configTime = "23:00";
}
LogUtil.d(TAG,"Input trace :"+traceNo);
// voidViewModel.getGenericVoidTransactions(transType,POSUtil.getInstance().formatTrace(traceNo),isEmv).observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
voidViewModel.getVoidTrans(transType,POSUtil.getInstance().formatTrace(traceNo)).observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
if(payDetail != null) {
String date = payDetail.getTransDate();
String time = payDetail.getTransTime();
LogUtil.d(TAG,"transactions trace :"+payDetail.getVoucherNo());
if(POSUtil.getInstance().checkVoid(configTime,date,time)) {
if(payDetail.getIsCanceled()) {
clearInputView();
showDeclineDialog(getResourceString(R.string.txt_trans_voided));
return;
}
sharedViewModel.payDetail.setValue(payDetail);
if(sharedViewModel.hostType.getValue() == HostType.MPU) {
sharedViewModel.isEmv.setValue(false);
transProcessViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
transProcessViewModel.setOldTransPayDetail(payDetail);
transProcessViewModel.setPayDetail(payDetail);
} else {
sharedViewModel.isEmv.setValue(true);
emvTransactionProcessViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
emvTransactionProcessViewModel.setPayDetail(payDetail);
}
safeNavigateToRouteId();
}
} else {
if (isEcr)
navigationECR();
showDeclineDialog(getResourceString(R.string.txt_void_not_found));
}
}
});
}
private void preAuthVoidProcess(boolean isEcr) {
preAuthVoidViewModel.getVoidablePreAuth(traceNo).observe(getViewLifecycleOwner(), payDetail -> {
if (payDetail != null) {
if(payDetail.getIsCanceled()) {
clearInputView();
showDeclineDialog(getResourceString(R.string.txt_trans_voided));
return;
}
sharedViewModel.payDetail.setValue(payDetail);
sharedViewModel.isEmv.setValue(true);
emvTransactionProcessViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
emvTransactionProcessViewModel.setPayDetail(payDetail);
safeNavigateToRouteId();
} else {
if (isEcr) {
navigationECR();
}
showDeclineDialog(getResourceString(R.string.txt_void_not_found));
}
});
}
private void preAuthVoidAction(boolean isEcr) {
preAuthVoidViewModel.getVoidablePreAuth(traceNo).observe(getViewLifecycleOwner(), payDetail -> {
if (payDetail != null) {
traceViewModel.inputTraceView.postValue("");
sharedViewModel.payDetail.postValue(payDetail);
// route to Check card
safeNavigateToRouteId();
} else {
if (isEcr) {
navigationECR();
}
showDeclineDialog(getResourceString(R.string.txt_trace_no_not_found));
}
});
}
private void voidAction(boolean isEcr) {
int transType = 0;
if(sharedViewModel.getTransMenu().getValue() == TransMenu.VOID) {
transType = TransactionsType.SALE.value;
} else if(sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_COMPLETE_VOID) {
transType = TransactionsType.PRE_AUTH_COMPLETE.value;
}
String configTimer = SystemParamsOperation.getInstance().getClearBatchTime();
String configTime;
if(configTimer != null && !configTimer.trim().isEmpty() && checkValidTime(configTimer.trim())) {
configTime = configTimer.trim();
} else {
configTime = "23:00";
}
LogUtil.d(TAG,"Input trace :"+traceNo);
voidViewModel.getVoidTransactions(transType).observe(getViewLifecycleOwner(), payDetails -> {
if (payDetails != null) {
LogUtil.d(TAG,"first list size :"+payDetails.size());
if(!payDetails.isEmpty()){
payLists.addAll(payDetails);
}
LogUtil.d(TAG,"second list size :"+payLists.size());
voidStatus = VoidStatus.NOT_FOUND;
for (PayDetail payDetail : payLists) {
String date = payDetail.getTransDate();
String time = payDetail.getTransTime();
LogUtil.d(TAG,"transactions trace :"+payDetail.getVoucherNo());
if ( payDetail.getVoucherNo().equals(POSUtil.getInstance().formatTrace(traceNo))) {
if(POSUtil.getInstance().checkVoid(configTime,date,time)) {
if(payDetail.getIsCanceled()) {
voidStatus = VoidStatus.ALREADY_VOIDED;
break;
}
isContain = true;
voidStatus = VoidStatus.OK;
sharedViewModel.payDetail.postValue(payDetail);
if(sharedViewModel.hostType.getValue() == HostType.MPU) {
sharedViewModel.isEmv.setValue(false);
transProcessViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
transProcessViewModel.setOldTransPayDetail(payDetail);
transProcessViewModel.setPayDetail(payDetail);
} else {
sharedViewModel.isEmv.setValue(true);
emvTransactionProcessViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
emvTransactionProcessViewModel.setPayDetail(payDetail);
}
safeNavigateToRouteId();
return;
}
}
}
if (isEcr)
navigationECR();
else {
clearInputView();
if (voidStatus == VoidStatus.ALREADY_VOIDED) {
showDeclineDialog(getResourceString(R.string.txt_trans_voided));
} else {
showDeclineDialog(getResourceString(R.string.txt_void_not_found));
}
}
} else {
if (isEcr)
navigationECR();
else {
clearInputView();
showDeclineDialog(getResourceString(R.string.txt_void_not_found));
}
}
});
}
private void reviewTransAction() {
voidViewModel.searchTransaction(traceNo).observe(getViewLifecycleOwner(), payDetail -> {
if (payDetail != null) {
traceViewModel.inputTraceView.postValue("");
sharedViewModel.payDetail.postValue(payDetail);
// route to Check card
safeNavigateToRouteId();
} else {
showDeclineDialog(getResourceString(R.string.txt_trace_no_not_found));
}
});
}
private void navigationECR() {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_void_not_found));
showDeclineDialog(getResourceString(R.string.txt_void_not_found));
sharedViewModel.isEcrFinished.postValue(true);
sharedViewModel.isEcr.postValue(false);
routeId = R.id.action_inputTraceFragment_to_nav_main;
safeNavigateToRouteId();
}
@Override
public void onPause() {
super.onPause();
}
private void clearInputView() {
traceViewModel.invoiceNo.setValue("");
}
private void observeRouteId(boolean isEcr) {
switch (Objects.requireNonNull(sharedViewModel.transactionsType.getValue())) {
case TIP_ADJUSTMENT:
case VOID:
case PRE_AUTH_COMPLETE_VOID:
// sharedViewModel.transMenu.postValue(TransMenu.TRANSACTIONS);
routeId = R.id.action_inputTraceFragment_to_confirmTransactionFragment;
if (!TextUtils.equals(traceNo, "")) {
// voidAction(isEcr);
voidProcess(isEcr);
} else {
showDeclineDialog(getResourceString(R.string.txt_empty_trace_no));
}
break;
case PRE_AUTH_VOID:
routeId = R.id.action_inputTraceFragment_to_confirmTransactionFragment;
// routeId = R.id.action_inputTraceFragment_to_cardWaitingFragment;
if (!TextUtils.equals(traceNo, "")) {
preAuthVoidProcess(isEcr);
// preAuthVoidAction(isEcr);
} else {
showDeclineDialog(getResourceString(R.string.txt_empty_trace_no));
}
break;
case REVIEW_TRANS:
routeId = R.id.action_inputTraceFragment_to_confirmTransactionFragment;
if (!TextUtils.equals(traceNo, "")) {
reviewTransAction();
} else {
showDeclineDialog(getResourceString(R.string.txt_empty_trace_no));
}
break;
}
}
public class ClickEvent {
public void onCancel() {
routeId = R.id.action_inputTraceFragment_to_nav_main;
safeNavigateToRouteId();
}
public void onConfirm() {
traceNo = POSUtil.getInstance().formatTrace(Objects.requireNonNull(traceViewModel.invoiceNo.getValue()));
clearInputView();
observeRouteId(false);
}
}
}

View File

@ -0,0 +1,284 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.lifecycle.Observer;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.CardDetectCallback;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.DialogCallback;
import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.print.PaperRollStatusCallback;
import com.utsmyanmar.paylibs.print.PrintHelper;
import com.utsmyanmar.paylibs.print.PrintReceipt;
import com.utsmyanmar.paylibs.utils.PrintStatus;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
public class PrintReceiptFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback {
private SharedViewModel sharedViewModel;
private static final String TAG = PrintReceipt.class.getSimpleName();
@Override
protected int currentId() {
return R.id.printReceiptFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return R.id.action_printReceiptFragment_to_nav_main;
}
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onResume() {
super.onResume();
/*
* check TMS parameter here
* if this device is ECR or contain some parameter
* skip this screen immediately
* */
/*
* send e-receipt to portal
*
* */
// navigateNextScreen();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.title_print_receipt));
sharedViewModel.printReceiptButtons.setValue(0);
PayDetail payDetail = sharedViewModel.payDetail.getValue();
if(payDetail != null && !payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_APPROVED) && !payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_ACCEPT) && sharedViewModel.transactionsType.getValue() != TransactionsType.MMQR && sharedViewModel.transactionsType.getValue() != TransactionsType.MMQR_REFUND && sharedViewModel.transactionsType.getValue() != TransactionsType.MMQR_INQUIRY_STATUS) {
navigateNextScreen();
}
}
@Override
public void onPause() {
super.onPause();
sharedViewModel.isReprint.postValue(false);
}
private void isCardInside() {
isCardInserted(new CardDetectCallback() {
@Override
public void onComplete() {
delayFunctionCall(()->{
navigateNextScreen();
});
}
});
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_print_receipt_screen, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
sharedViewModel.setPrintStatus(PrintStatus.FIRST_PRINT);
observePrintProcess();
setBackPressCallback(this);
}
private void observePrintProcess() {
sharedViewModel.getPrintStatus().observe(this, new Observer<PrintStatus>() {
@Override
public void onChanged(PrintStatus printStatus) {
switch(printStatus) {
case FIRST_PRINT:
sharedViewModel.postPrintReceiptMsg("Printing Receipt for Merchant");
startPrintProcess(true);
break;
case FIRST_PRINT_DONE:
sharedViewModel.postPrintReceiptMsg("Confirm Print Receipt for Customer");
if(sharedViewModel.isEcr.getValue() != null &&
sharedViewModel.isEcr.getValue() &&
SystemParamsOperation.getInstance().isAutoPrintCustomerCopy()) {
sharedViewModel.setVisibilityPrintReceiptButtons(8);
sharedViewModel.setPrintStatus(PrintStatus.SECOND_PRINT);
} else {
sharedViewModel.setVisibilityPrintReceiptButtons(0);
}
break;
case SECOND_PRINT:
sharedViewModel.postPrintReceiptMsg("Printing Receipt for Customer");
startPrintProcess(false);
break;
case SECOND_PRINT_DONE:
isCardInside();
break;
case EMPTY_PAPER_ROLL_FIRST:
handleEmptyPaperRoll(true);
break;
case EMPTY_PAPER_ROLL_SECOND:
handleEmptyPaperRoll(false);
break;
}
}
});
}
private void startPrintProcess(boolean isFirstPrint) {
PrintHelper.getInstance().checkPaperRollStatus(new PaperRollStatusCallback() {
@Override
public void printerReady() {
sharedViewModel.startPrintReceipt(isFirstPrint);
}
@Override
public void paperRollIsEmpty() {
handleEmptyPaperRoll(isFirstPrint);
}
@Override
public void printNotComplete() {
}
@Override
public void printerTooHot() {
}
@Override
public void printerFailed() {
}
@Override
public void unknownStatusOccur(int code) {
// showDeclineDialog("Check Printer Status : "+code);
}
});
}
private void handleEmptyPaperRoll(boolean isFirstPrint) {
sharedViewModel.printReceiptButtons.setValue(0);
sharedViewModel.printReceiptMsg.setValue(getResourceString(R.string.txt_print_receipt_failed));
showPrinterAlertDialog(getResourceString(R.string.txt_printing_paper_not_ready), new DialogCallback() {
@Override
public void onClickCancel() {
dismissPrinterAlertDialog();
}
@Override
public void onClickRetry() {
sharedViewModel.startPrintReceipt(isFirstPrint);
dismissPrinterAlertDialog();
}
});
if(SystemParamsOperation.getInstance().isAlertSound()) {
startSound(getResourceString(R.string.txt_audio_printer_alert));
}
}
@SuppressWarnings("ConstantConditions")
private void navigateNextScreen() {
if(sharedViewModel.isReprint.getValue()) {
safePopBackStack();
} else {
safeNavigateToRouteId();
}
}
@Override
public void onBackPress() {
sharedViewModel.printReceiptButtons.setValue(8);
isCardInside();
}
public class ClickEvent {
public void onConfirm() {
sharedViewModel.setVisibilityPrintReceiptButtons(8);
sharedViewModel.setPrintStatus(PrintStatus.SECOND_PRINT);
}
public void onCancel() {
sharedViewModel.setVisibilityPrintReceiptButtons(8);
isCardInside();
}
}
private void alertPaperRoll(String title, String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle(title)
.setMessage(message)
.setNegativeButton(getResourceString(R.string.txt_print_later), (dialog, which) -> {
dialog.dismiss();
})
.setPositiveButton(getResourceString(R.string.txt_retry_now), (dialog, which) -> {
sharedViewModel.startPrintProcess();
})
.setCancelable(false)
.create();
builder.show();
}
}

View File

@ -0,0 +1,258 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.checkxread.model.CardDataX;
import com.utsmyanmar.checkxread.readcard.MAGXReadCard;
import com.utsmyanmar.checkxread.readcard.MPUXReadCard;
import com.utsmyanmar.checkxread.readcard.ReadCardResultX;
import com.utsmyanmar.checkxread.util.CardTypeX;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.model.enums.TransCVM;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmyanmar.paylibs.utils.params.Params;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.CardReadViewModel;
import com.utsmm.kbz.ui.core_viewmodel.EmvTransactionProcessViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.ui.pinpad.PinPadViewModel;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class ProcessingCardFragment extends DataBindingFragment {
private static final String TAG = ProcessingCardFragment.class.getSimpleName();
private CardReadViewModel cardReadViewModel;
private SharedViewModel sharedViewModel;
private TransProcessViewModel transProcessViewModel;
private PinPadViewModel pinPadViewModel;
private EmvTransactionProcessViewModel emvTransactionViewModel;
private int routeId;
@Override
protected void initViewModel() {
cardReadViewModel = getFragmentScopeViewModel(CardReadViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
pinPadViewModel = getFragmentScopeViewModel(PinPadViewModel.class);
emvTransactionViewModel = getFragmentScopeViewModel(EmvTransactionProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_processing_card_screen, BR.cardReadViewModel, cardReadViewModel)
.addBindingParam(BR.sharedViewModel, sharedViewModel);
}
@Override
protected int currentId() {
return R.id.processingCardFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onResume() {
super.onResume();
resetEmvTransResult();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.title_processing_card));
}
private void resetEmvTransResult() {
emvTransactionViewModel.resetTransactionStatus();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
checkCardTransactionType();
}
private void checkCardTransactionType() {
switch (cardReadViewModel.getCardTransactionType()) {
case MPU: readMPUCard();
break;
case EMV: handlePreEmvProcess();
break;
case FALLBACK: readMAGStripe(true,true);
break;
case MAG: readMAGStripe(false,true);
break;
}
}
private void readMPUCard() {
cardReadViewModel.startReadXProcess(MPUXReadCard.getInstance(), new ReadCardResultX() {
@Override
public void onSuccess(CardDataX cardDataX) {
routeId = R.id.action_processingCardFragment_to_pinPadFragment;
transProcessViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
pinPadViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
TradeData tradeData = TransactionUtil.getInstance().initMPUTransaction(cardDataX, CardTypeX.IC);
transProcessViewModel.setTradeData(tradeData);
pinPadViewModel.setTradeData(tradeData);
if(sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_PARTIAL_VOID ) {
sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_function_not_supported));
routeId = R.id.action_processingCardFragment_to_errorFragment;
}
// else if(sharedViewModel.transactionsType.getValue() == TransactionsType.REFUND) {
// sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_card_not_supported));
// routeId = R.id.action_processingCardFragment_to_errorFragment;
//
// }
sharedViewModel.setCardDataExist(true);
if(sharedViewModel.getAmountExist().getValue() != null && !sharedViewModel.getAmountExist().getValue()) {
routeId = R.id.action_processingCardFragment_to_inputAmountFragment;
}
safeNavigateToRouteId();
}
@Override
public void onError(int code, String message) {
LogUtil.d(TAG,"Failure at "+code+" message: "+message);
// need to go back and ask card again!!!
showDeclineDialogAutoHide("FAILURE :"+message);
sharedViewModel.setCardDataExist(false);
safePopBackStack();
}
});
}
private void readMAGStripe(boolean isFallback,boolean isNeedPin) {
cardReadViewModel.startReadXProcess(MAGXReadCard.getInstance(), new ReadCardResultX() {
@Override
public void onSuccess(CardDataX cardDataX) {
sharedViewModel.isEmv.setValue(false);
if(isNeedPin) {
// pin required scenario
routeId = R.id.action_processingCardFragment_to_pinPadFragment;
transProcessViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
pinPadViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
/* need to check card scheme according to card number --!^--- check below function*/
TradeData tradeData = TransactionUtil.getInstance().initMagStripeTransaction(cardDataX,isFallback);
transProcessViewModel.setTradeData(tradeData);
pinPadViewModel.setTradeData(tradeData);
} else {
// pin not required scenario
routeId = R.id.action_processingCardFragment_to_processingFragment;
transProcessViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
TradeData tradeData = TransactionUtil.getInstance().initMagStripeTransaction(cardDataX,isFallback);
String processCode = sharedViewModel.processCode.getValue();
String amount = sharedViewModel.amount.getValue();
PayDetail payDetail = tradeData.getPayDetail();
payDetail.setAmount(POSUtil.getInstance().convertAmount(amount));
if (!TextUtils.equals(processCode,"")) {
payDetail.setProcessCode(processCode);
}
payDetail.setTransCVM(TransCVM.SIGNATURE);
transProcessViewModel.setTradeData(tradeData);
}
if(sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_PARTIAL_VOID ) {
// sharedViewModel.transMenu.postValue(null);
sharedViewModel.setTransMenu(null);
routeId = R.id.action_processingCardFragment_to_errorFragment;
}
// else if(sharedViewModel.transactionsType.getValue() == TransactionsType.REFUND) {
// routeId = R.id.action_processingCardFragment_to_errorFragment;
// }
sharedViewModel.setCardDataExist(true);
if(sharedViewModel.getTransMenu().getValue() != TransMenu.PRE_AUTH_FULL_VOID && sharedViewModel.getAmountExist().getValue() != null && !sharedViewModel.getAmountExist().getValue()) {
routeId = R.id.action_processingCardFragment_to_inputAmountFragment;
}
safeNavigateToRouteId();
}
@Override
public void onError(int code, String message) {
LogUtil.d(TAG,"Failure at "+code+" message: "+message);
// need to go back and ask card again!!!
showDeclineDialogAutoHide("FAILURE :"+message);
safePopBackStack();
}
});
}
private void handlePreEmvProcess() {
emvTransactionViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
if (SystemParamsOperation.getInstance().isEmvEnabled()) {
prepareEmvTransaction();
routeId = R.id.action_processingCardFragment_to_emvTransactionFragment;
} else {
routeId = R.id.action_processingCardFragment_to_errorFragment;
sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_please_enable_emv));
}
// if(sharedViewModel.transactionsType.getValue() == TransactionsType.REFUND) {
// sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_card_not_supported));
// routeId = R.id.action_processingCardFragment_to_errorFragment;
//
// }
safeNavigateToRouteId();
}
private boolean isNormalTransactionType() {
return (sharedViewModel.transactionsType.getValue() == TransactionsType.SALE || sharedViewModel.transactionsType.getValue() == TransactionsType.CASH_OUT || sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_SALE);
}
private void prepareEmvTransaction() {
sharedViewModel.isEmv.postValue(true);
cardReadViewModel.cardTypeData.observe(getViewLifecycleOwner(), cardType -> {
TradeData tradeData = Params.newTrade(false);
PayDetail payDetail = tradeData.getPayDetail();
payDetail.setCardType(cardType);
emvTransactionViewModel.setTradeData(tradeData);
});
}
}

View File

@ -0,0 +1,369 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.navigation.NavController;
import androidx.navigation.NavDestination;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.EmvTransactionProcessViewModel;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.ui.core_viewmodel.transactions.ProcessingTransaction;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class ProcessingFragment extends DataBindingFragment {
private static final String TAG = ProcessingFragment.class.getSimpleName();
private SharedViewModel sharedViewModel;
private TransProcessViewModel transProcessViewModel;
private EmvTransactionProcessViewModel emvTransactionProcessViewModel;
private int routeId;
private String ecrErrorMsg = "";
private final NavController.OnDestinationChangedListener listener = new NavController.OnDestinationChangedListener() {
@Override
public void onDestinationChanged(@NonNull NavController controller, @NonNull NavDestination destination, @Nullable Bundle arguments) {
if (destination.getId() == R.id.nav_main) {
emvTransactionProcessViewModel.onCancelEmvTransaction();
ecrActionCancel(ecrErrorMsg);
}
}
};
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
emvTransactionProcessViewModel = getFragmentScopeViewModel(EmvTransactionProcessViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_processing_screen, BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.emvTransViewModel,emvTransactionProcessViewModel)
.addBindingParam(BR.transViewModel,transProcessViewModel);
}
@Override
protected int currentId() {
return R.id.processingFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Added timer 3 minutes while connecting to server -- 30/01/2024
setUpTimer();
if(sharedViewModel.isEmv.getValue() != null && sharedViewModel.isEmv.getValue()) {
observeData(emvTransactionProcessViewModel);
} else {
observeData(transProcessViewModel);
}
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.title_processing));
if(isEmvTrans()) {
startTransactionProcess(emvTransactionProcessViewModel);
} else {
startTransactionProcess(transProcessViewModel);
}
sharedViewModel.loadingMsg(getResourceString(R.string.txt_sending));
// disableNavigationBar();
getNavController(Constants.NAV_HOST_ID).addOnDestinationChangedListener(listener);
}
private boolean isEmvTrans() {
return sharedViewModel.isEmv.getValue() != null && sharedViewModel.isEmv.getValue();
}
private void startTransactionProcess(ProcessingTransaction processingTransaction) {
if(SystemParamsOperation.getInstance().getDemoStatus()) {
processingTransaction.startDemoProcess();
} else {
processingTransaction.startOnlineProcess();
}
}
@Override
public void onPause() {
super.onPause();
updateData();
resetEmvResult();
// enableNavigationBar();
clearPayDetail();
getNavController(Constants.NAV_HOST_ID).removeOnDestinationChangedListener(listener);
}
private void resetEmvResult() {
emvTransactionProcessViewModel.resetTransactionStatus();
}
private void clearPayDetail() {
emvTransactionProcessViewModel.payDetailResult.setValue(null);
transProcessViewModel.payDetailResult.setValue(null);
}
private void setUpTimer(){
setupTimeout(Constants.PROCESSING_TIMEOUT, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
callMainScreen();
}
});
}
private void updateData(){
if(isEmvTrans()) {
LogUtil.d(TAG,"Updated sharedViewmodel payDetail for emv");
sharedViewModel.payDetail.setValue(emvTransactionProcessViewModel.payDetailResult.getValue());
} else {
LogUtil.d(TAG,"Updated sharedViewmodel payDetail for non emv");
sharedViewModel.payDetail.setValue(transProcessViewModel.payDetailResult.getValue());
}
// transProcessViewModel.payDetailResult.observe(getViewLifecycleOwner(), payDetail -> sharedViewModel.payDetail.postValue(payDetail));
}
private void callNextScreen(){
updateData();
if (requiresSignature()) {
routeId = R.id.action_processingFragment_to_signatureFragment;
} else {
routeId = R.id.action_processingFragment_to_transactionResultFragment;
}
// delayFunctionCall(this::safeNavigateToRouteId,500);
safeNavigateToRouteId();
}
private boolean requiresSignature() {
// Check if signature is required based on transaction details
PayDetail payDetail = sharedViewModel.payDetail.getValue();
if(isEmvTrans()) {
LogUtil.d(TAG,"Updated sharedViewmodel payDetail for emv");
payDetail = emvTransactionProcessViewModel.payDetailResult.getValue();
} else {
LogUtil.d(TAG,"Updated sharedViewmodel payDetail for non emv");
payDetail = transProcessViewModel.payDetailResult.getValue();
}
if (payDetail == null) {
LogUtil.d(TAG,"Paydetail is null");
return false;
}
LogUtil.d(TAG,"tradeAnswerCode: "+payDetail.getTradeAnswerCode());
// For now, let's check if it's a card transaction and successful
boolean isSuccessful = "00".equals(payDetail.getTradeAnswerCode());
// You can customize this logic based on your business requirements
return isSuccessful && !isEmvTrans(); // Require signature for successful non-EMV transactions
}
private void callMainScreen(){
routeId = R.id.action_processingFragment_to_nav_main;
safeNavigateToRouteId();
}
private void observeErrorMsg(){
transProcessViewModel.errorMessage.observe(getViewLifecycleOwner(), msg -> {
showDeclineDialog(msg);
ecrActionCancel(msg);
});
}
private void ecrActionCancel(String msg) {
if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg);
sharedViewModel.isEcrFinished.postValue(true);
if(isEmvTrans()) {
emvTransactionProcessViewModel.onCancelEmvTransaction();
}
}
}
private void navigateToError() {
routeId = R.id.action_processingFragment_to_errorFragment;
safeNavigateToRouteId();
}
private void navigateToSuccess() {
routeId = R.id.action_processingFragment_to_successFragment;
safeNavigateToRouteId();
}
private void observeData(ProcessingTransaction processingTransaction) {
processingTransaction.getTransStatus().observe(getViewLifecycleOwner(), transResultStatus -> {
LogUtil.d(TAG,"Transaction RESULT :"+transResultStatus);
switch (transResultStatus) {
case FAIL:
case SUCCESS:
case OFFLINE_SUCCESS:
LogUtil.d(TAG,"This was called!");
if(SystemParamsOperation.getInstance().getDemoStatus()) {
delayFunctionCall(()->{
// updateData();
sharedViewModel.dismissLoadingMsg();
callNextScreen();
},1500);
} else {
// updateData();
sharedViewModel.dismissLoadingMsg();
callNextScreen();
}
break;
case OFFLINE_FAILURE:
sharedViewModel.dismissLoadingMsg();
sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_offline_failure));
navigateToError();
break;
case REVERSAL_FAIL:
// updateData();
sharedViewModel.dismissLoadingMsg();
sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_reversal_failed));
navigateToError();
break;
case SECONDARY:
// sharedViewModel.dismissLoadingMsg();
sharedViewModel.loadingMsg(getResourceString(R.string.txt_sending_secondary));
break;
case REVERSAL_PREPARE:
sharedViewModel.dismissLoadingMsg();
sharedViewModel.loadingMsg(getResourceString(R.string.txt_prepare_reversal));
break;
case REVERSAL_PROCESS:
sharedViewModel.dismissLoadingMsg();
sharedViewModel.loadingMsg(getResourceString(R.string.txt_sending_reversal));
break;
case REVERSAL_SECONDARY:
sharedViewModel.dismissLoadingMsg();
sharedViewModel.loadingMsg(getResourceString(R.string.txt_sending_secondary_reversal));
break;
case REVERSAL_THIRD:
sharedViewModel.dismissLoadingMsg();
sharedViewModel.loadingMsg(getResourceString(R.string.txt_sending_third_reversal));
break;
case REVERSAL_SUCCESS:
// updateData();
sharedViewModel.dismissLoadingMsg();
ecrActionCancel(getResourceString(R.string.txt_reversal_success));
sharedViewModel.set_successFragmentMsg(getResourceString(R.string.txt_reversal_success));
navigateToSuccess();
// showSuccessDialog(getResourceString(R.string.txt_reversal_success));
// ecrActionCancel(getResourceString(R.string.txt_reversal_success));
// callMainScreen();
break;
case ERROR:
// updateData();
sharedViewModel.dismissLoadingMsg();
observeErrorMsg();
callMainScreen();
break;
default:
sharedViewModel.dismissLoadingMsg();
ecrActionCancel("Reason - "+transResultStatus);
if(isEmvTrans()) {
observeEmvErrorCode();
} else {
showDeclineDialog("Reason - "+transResultStatus);
callMainScreen();
}
break;
}
});
}
private void observeEmvErrorCode() {
emvTransactionProcessViewModel.errorCodeMsg.observe(getViewLifecycleOwner(), pair -> {
LogUtil.e(TAG,"ERROR CODE MSG :"+pair);
if(!TextUtils.equals(pair,"")) {
if(pair.contains(":")){
String code = pair.split(":")[0];
String msg = pair.split(":")[1];
if(TextUtils.equals(code,"-4100") || TextUtils.equals(code,"-4125")){
sharedViewModel.set_errorFragmentMsg("Card read failed!");
}else{
// showInfoDialog(code,msg);
sharedViewModel.set_errorFragmentMsg(code+"\n"+msg);
}
ecrErrorMsg = msg;
}else{
ecrErrorMsg = pair;
sharedViewModel.set_errorFragmentMsg(pair);
}
} else {
sharedViewModel.set_errorFragmentMsg("Emv process timeout!");
ecrErrorMsg = "Emv process timeout!";
}
navigateToError();
// navigateToMain();
});
}
}

View File

@ -0,0 +1,128 @@
package com.utsmm.kbz.ui.core_ui;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.github.gcacace.signaturepad.BR;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.ui.POSReceiptView;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class ReceiptFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
private POSReceiptView.ReceiptData currentReceiptData;
private POSReceiptView receiptView;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_receipt_screen, BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.menu_receipt));
}
@Override
protected int currentId() {
return R.id.receiptFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return R.id.action_receiptFragment_to_nav_main;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
receiptView = mBinding.getRoot().findViewById(R.id.receiptView);
generateReceipt();
}
private void generateReceipt() {
try {
// Create sample receipt data
currentReceiptData = createSampleReceiptData();
// Set the data to the receipt view
receiptView.setReceiptData(currentReceiptData);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getContext(), "Failed to generate receipt: " + e.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
private POSReceiptView.ReceiptData createSampleReceiptData() {
POSReceiptView.ReceiptData data = new POSReceiptView.ReceiptData();
PayDetail payDetail = sharedViewModel.payDetail.getValue();
if(payDetail == null) {
return data;
}
SystemParamsOperation systemParamsOperation = SystemParamsOperation.getInstance();
// Load sample bank logo
data.bankLogo = BitmapFactory.decodeResource(getResources(), R.drawable.logo_kbzbank);
// Set sample data
data.bankName = "YOUR BANK";
data.merchantName = systemParamsOperation.getMerchantName();
data.merchantAddress = systemParamsOperation.getMerchantAddress();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss", Locale.getDefault());
data.dateTime = sdf.format(new Date());
data.traceNumber = payDetail.getVoucherNo();
data.transactionType = payDetail.getTransType();
data.cardNumber = POSUtil.getInstance().getCardNumMasking(payDetail.getCardNo());
data.retrievalReferenceNumber = payDetail.getReferNo();
data.approvalNumber = payDetail.getApprovalCode();
data.amount = POSUtil.getInstance().getDecimalAmountSeparatorFormat(payDetail.getAmount());
data.currency = payDetail.getCurrency();
data.footerMessage = "Keep this receipt for your records";
data.responseCode = payDetail.getTradeAnswerCode();
return data;
}
public class ClickEvent {
public void onConfirm() {
safeNavigateToRouteId();
}
}
}

View File

@ -0,0 +1,174 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.view.View;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.github.gcacace.signaturepad.views.SignaturePad;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class SignatureFragment extends DataBindingFragment {
private static final String TAG = SignatureFragment.class.getSimpleName();
private SignaturePad mSignaturePad;
private RadioButton rbDigitalSignature;
private RadioButton rbManualSignature;
private SharedViewModel sharedViewModel;
private boolean isSigned = false;
private boolean isDigitalSignatureSelected = true;
private int routeId;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_signature_view, BR.vm,sharedViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
protected int currentId() {
return R.id.signatureFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mSignaturePad = binding.getRoot().findViewById(R.id.signature_pad);
rbDigitalSignature = binding.getRoot().findViewById(R.id.rbDigitalSignature);
rbManualSignature = binding.getRoot().findViewById(R.id.rbManualSignature);
setupSignaturePad();
setupSignatureOptions();
}
private void setupSignaturePad() {
mSignaturePad.setOnSignedListener(new SignaturePad.OnSignedListener() {
@Override
public void onStartSigning() {
isSigned = true;
}
@Override
public void onSigned() {
LogUtil.d(TAG,"ON Signed !");
isSigned = true;
}
@Override
public void onClear() {
isSigned = false;
LogUtil.d(TAG,"ON Clear !");
}
});
}
private void setupSignatureOptions() {
// Set up radio button listeners
rbDigitalSignature.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
rbManualSignature.setChecked(false);
isDigitalSignatureSelected = true;
mSignaturePad.setEnabled(true);
mSignaturePad.setAlpha(1.0f);
LogUtil.d(TAG, "Digital signature option selected");
}
});
rbManualSignature.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
rbDigitalSignature.setChecked(false);
isDigitalSignatureSelected = false;
mSignaturePad.setEnabled(false);
mSignaturePad.setAlpha(0.5f);
LogUtil.d(TAG, "Manual signature option selected");
}
});
// Set digital signature as default
rbDigitalSignature.setChecked(true);
isDigitalSignatureSelected = true;
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.signature_title));
}
private void callNextScreen(){
routeId = R.id.action_signatureFragment_to_transactionResultFragment;
safeNavigateToRouteId();
}
public class ClickEvent {
public void onClickConfirm() {
if (isDigitalSignatureSelected) {
// Handle digital signature
if (isSigned) {
sharedViewModel.signBitmap = mSignaturePad.getSignatureBitmap();
LogUtil.d(TAG, "Digital signature confirmed and stored");
callNextScreen();
} else {
showSingleInfoDialog("Please provide your signature on the screen!");
}
} else {
// Handle manual signature on paper
sharedViewModel.signBitmap = null; // No digital signature
LogUtil.d(TAG, "Manual signature on paper selected - no digital signature stored");
showSingleInfoDialog("Please sign on the printed receipt manually and proceed.");
callNextScreen();
}
}
public void onClickClear() {
if (isDigitalSignatureSelected) {
mSignaturePad.clear();
isSigned = false;
LogUtil.d(TAG, "Digital signature cleared");
} else {
// For manual signature, just show a message
showSingleInfoDialog("Manual signature option selected. No digital signature to clear.");
}
}
public void onClickDigitalOption() {
rbDigitalSignature.setChecked(true);
}
public void onClickManualOption() {
rbManualSignature.setChecked(true);
}
}
}

View File

@ -0,0 +1,52 @@
package com.utsmm.kbz.ui.core_ui;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
public class SuccessFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_success_screen, BR.sharedViewModel,sharedViewModel);
}
@Override
protected int currentId() {
return R.id.successFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return R.id.action_successFragment_to_nav_main;
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_success));
delayFunctionCall(this::navigateToMain,2000);
}
private void navigateToMain() {
safeNavigateToRouteId();
}
}

View File

@ -0,0 +1,124 @@
package com.utsmm.kbz.ui.core_ui;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.CardDetectCallback;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
public class TimeoutFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
private int resultTimeOut = 3;
private CountDownTimer countDownTimer;
private int routeId;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_error));
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_timeout_screen, BR.sharedViewModel,sharedViewModel);
}
@Override
protected int currentId() {
return R.id.timeoutFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
private void startResultTimeout() {
countDownTimer = new CountDownTimer(resultTimeOut * 1000, 1000) {
@SuppressLint("SetTextI18n")
@Override
public void onTick(long millisUntilFinished) {
}
@SuppressLint("SetTextI18n")
@Override
public void onFinish() {
isCardInside();
}
}.start();
}
private void ecrActionCancel(String msg) {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg);
sharedViewModel.isEcrFinished.postValue(true);
}
}
}
@Override
public void onPause() {
super.onPause();
if(countDownTimer != null){
countDownTimer.cancel();
}
}
private void isCardInside() {
isCardInserted(new CardDetectCallback() {
@Override
public void onComplete() {
delayFunctionCall(()->{
ecrActionCancel("Timeout!");
routeId = R.id.action_timeoutFragment_to_nav_main;
safeNavigateToRouteId();
});
}
});
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
startResultTimeout();
}
}

View File

@ -0,0 +1,61 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.library.baseAdapters.BR;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
/*
* This fragment was called after transaction result screen, So I won't delete it for awhile for future testing process
* */
public class TransactionDetailFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
private int routeId;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_transaction_detail, BR.sharedViewModel,sharedViewModel);
}
@Override
protected int currentId() {
return R.id.transactionDetailFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
sendMessageProcess(sharedViewModel.payDetail.getValue().sendBag);
}
private void sendMessageProcess(byte[] sendBytes){
sharedViewModel.sendMsg.setValue(ByteUtil.bytes2HexStr(sendBytes));
}
}

View File

@ -0,0 +1,412 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import com.google.gson.stream.MalformedJsonException;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.sirius.SiriusError;
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.DialogCallback;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.baselib.util.rx_helper.RxCallbackX;
import com.utsmyanmar.baselib.util.rx_helper.RxUtil;
import com.utsmyanmar.ecr.ECRHelper;
import com.utsmyanmar.ecr.ECRProcess;
import com.utsmyanmar.ecr.data.model.TransactionsResp;
import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.print.PaperRollStatusCallback;
import com.utsmyanmar.paylibs.print.PrintHelper;
import com.utsmyanmar.paylibs.utils.PrintStatus;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.config.data.model.TMSUpdate;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmm.kbz.util.tms.TMSUtil;
import java.io.IOException;
import javax.inject.Inject;
import retrofit2.HttpException;
import com.utsmyanmar.paylibs.utils.LogUtil;
// Temporarily disabled Hilt
// @AndroidEntryPoint
public class TransactionResultFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback {
private static final String TAG = TransactionResultFragment.class.getSimpleName();
private TransProcessViewModel transProcessViewModel;
private SharedViewModel sharedViewModel;
private static final int resultTimeOut = 1;
private int routeId;
private final RxUtil<SiriusResponse> siriusRxUtil = new RxUtil<>();
@Inject
EmvParamOperation emvParamOperation;
@Override
protected void initViewModel() {
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_trans_result_screen, BR.transViewModel, transProcessViewModel)
.addBindingParam(BR.sharedViewModel, sharedViewModel);
}
@Override
protected int currentId() {
return R.id.transactionResultFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onResume() {
super.onResume();
String resultStr = "";
if(sharedViewModel.payDetail.getValue() != null) {
resultStr = sharedViewModel.payDetail.getValue().getTradeAnswerCode();
}
int qrStatus = -100;
if(sharedViewModel.payDetail.getValue() != null) {
qrStatus = sharedViewModel.payDetail.getValue().getQrTransStatus();
}
if (resultStr.equals(Constant.ANSWER_CODE_ACCEPT) || resultStr.equals(Constant.ANSWER_CODE_APPROVED)) {
/* ISO 8583 RESPONSE */
if(sharedViewModel.payDetail.getValue().getTransactionType() != TransactionsType.SETTLEMENT.value) {
if(SystemParamsOperation.getInstance().isAlertSound()) {
startSound(getResourceString(R.string.txt_audio_thank_you));
}
}
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_trans_result));
} else if(qrStatus == 1 || qrStatus == -1 || qrStatus == 2 || qrStatus == 3 ) {
/* WAVE QR STATUS */
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_qr_pay));
} else {
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_error));
}
if(sharedViewModel.isEcr.getValue() != null){
if(sharedViewModel.isEcr.getValue()){
ecrAction();
}
}
}
private void startResultTimeout() {
setupTimeout(resultTimeOut, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
PayDetail payDetail = sharedViewModel.payDetail.getValue();
if (payDetail == null) {
navigateToMainScreen();
return;
}
SiriusRequest siriusReq = TMSUtil.getInstance().generateRequestParams(
getContext(),
payDetail.getTransType(),
String.valueOf(payDetail.getTransNum())
);
TransactionsType transactionType = sharedViewModel.transactionsType.getValue();
if (isNonApprovedTrade(payDetail) && isNonWavepayTransaction(transactionType)) {
startPrintProcess(false);
isCardInside();
} else if (transactionType == TransactionsType.SETTLEMENT) {
handleSettlementTransaction(siriusReq);
} else if (isWavePayNonSuccessTransaction(transactionType, payDetail)) {
startPrintProcess(false);
navigateToMainScreen();
} else if (isWavePaySuccessTransaction(transactionType, payDetail)) {
handleWavePaySuccessTransaction(payDetail, siriusReq);
} else {
handleDefaultTransaction(payDetail, siriusReq);
}
}
});
}
private boolean isNonApprovedTrade(PayDetail payDetail) {
return !payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_APPROVED) &&
!payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_ACCEPT);
}
private boolean isNonWavepayTransaction(TransactionsType transactionType) {
return transactionType != TransactionsType.MMQR &&
transactionType != TransactionsType.MMQR_INQUIRY_STATUS &&
transactionType != TransactionsType.MMQR_REFUND;
}
private boolean isWavePayNonSuccessTransaction(TransactionsType transactionType, PayDetail payDetail) {
return (transactionType == TransactionsType.MMQR && payDetail.getQrTransStatus() != 1) ||
(transactionType == TransactionsType.MMQR_INQUIRY_STATUS && payDetail.getQrTransStatus() != 1) ||
(transactionType == TransactionsType.MMQR_REFUND && payDetail.getQrTransStatus() != 1);
}
private boolean isWavePaySuccessTransaction(TransactionsType transactionType, PayDetail payDetail) {
return (transactionType == TransactionsType.MMQR || transactionType == TransactionsType.MMQR_REFUND) &&
payDetail.getQrTransStatus() == 1;
}
private void handleSettlementTransaction(SiriusRequest siriusReq) {
startPrintProcess(true);
downloadParameters(siriusReq, TMSUpdate.UPDATE);
showSuccessDialog(getResourceString(R.string.txt_configs_are_updated));
navigateToMainScreen();
}
private void handleWavePaySuccessTransaction(PayDetail payDetail, SiriusRequest siriusReq) {
SystemParamsOperation.getInstance().setLastSuccessTrnx(payDetail.getVoucherNo());
downloadParameters(siriusReq, TMSUpdate.CHECK);
navigateToPrintScreen();
}
private void handleDefaultTransaction(PayDetail payDetail, SiriusRequest siriusReq) {
SystemParamsOperation.getInstance().setLastSuccessTrnx(payDetail.getVoucherNo());
downloadParameters(siriusReq, TMSUpdate.CHECK);
navigateToPrintScreen();
}
private void downloadParameters(SiriusRequest siriusRequest,TMSUpdate tmsUpdate) {
siriusRxUtil.observableData(sharedViewModel.getParams(siriusRequest), new RxCallbackX<SiriusResponse>() {
@Override
public void onSuccess(SiriusResponse data) {
TMSUtil.getInstance().initParams(data, tmsUpdate,emvParamOperation);
}
@Override
public void onError(Throwable throwable) {
dismissLoadingDialog();
if(throwable.getClass() == MalformedJsonException.class) {
LogUtil.d(TAG,getResourceString(R.string.txt_terminal_is_not_configure));
} else if (throwable instanceof HttpException) {
HttpException error = (HttpException)throwable;
try {
SiriusError siriusError = new Gson().fromJson(error.response().errorBody().string(), SiriusError.class);
LogUtil.d(TAG,siriusError.getMessage());
} catch (IOException ex) {
ex.printStackTrace();
}
} else {
LogUtil.d(TAG,getResourceString(R.string.txt_failure)+throwable.getMessage());
}
throwable.printStackTrace();
}
@Override
public void onComplete() {
dismissLoadingDialog();
// emvParamOperation.loadAidRids();
// emvParamOperation.loadEmvTerminalParam();
}
});
}
private void isCardInside() {
isCardInserted(() -> delayFunctionCall(this::navigateToMainScreen));
}
private void navigateToMainScreen() {
routeId = R.id.action_transactionResultFragment_to_nav_main;
safeNavigateToRouteId();
}
private void navigateToPrintScreen() {
routeId = R.id.action_transactionResultFragment_to_printReceiptFragment;
// routeId = R.id.action_transactionResultFragment_to_receiptFragment;
safeNavigateToRouteId();
}
@Override
public void onViewCreated(@androidx.annotation.NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
sharedViewModel.setPrintStatus(PrintStatus.FIRST_PRINT);
sharedViewModel.printXStatus.setValue(null);
if (getActivity() instanceof AppCompatActivity) {
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
}
setupBackButtonPressDetection(this);
observePrintStatus();
startResultTimeout();
if(sharedViewModel.payDetail.getValue() != null)
LogUtil.d(TAG,"Result Code: "+sharedViewModel.payDetail.getValue().getTradeAnswerCode());
}
private void observePrintStatus() {
sharedViewModel.printXStatus.observe(getViewLifecycleOwner(), printStatus -> {
// LogUtil.d(TAG,"Print Status :"+printStatus);
if(printStatus == PrintStatus.EMPTY_PAPER_ROLL) {
cancelTimeout();
startPrintProcess(false);
} else if (printStatus == PrintStatus.DONE_PRINT) {
isCardInside();
}
});
}
private void startPrintProcess(boolean isSettlement) {
PrintHelper.getInstance().checkPaperRollStatus(new PaperRollStatusCallback() {
@Override
public void printerReady() {
if(isSettlement) {
sharedViewModel.startPrintProcessSettlement();
return;
}
sharedViewModel.startPrintProcess();
}
@Override
public void paperRollIsEmpty() {
cancelTimeout();
showPrinterAlertDialog(getResourceString(R.string.txt_paper_roll_not_ready), new DialogCallback() {
@Override
public void onClickCancel() {
dismissPrinterAlertDialog();
isCardInside();
}
@Override
public void onClickRetry() {
dismissPrinterAlertDialog();
startPrintProcess(isSettlement);
}
});
if(SystemParamsOperation.getInstance().isAlertSound()) {
startSound(getResourceString(R.string.txt_audio_printer_alert));
}
}
@Override
public void printNotComplete() {
}
@Override
public void printerTooHot() {
}
@Override
public void printerFailed() {
// alertPaperRoll(getResourceString(R.string.txt_lip_is_opening), getResourceString(R.string.txt_please_close_lip));
}
@Override
public void unknownStatusOccur(int code) {
// showDeclineDialog("Check Printer Status : "+code);
}
});
}
private void alertPaperRoll(String title, String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle(title)
.setMessage(message)
.setNegativeButton(getResourceString(R.string.txt_print_later), (dialog, which) -> {
dialog.dismiss();
})
.setPositiveButton(getResourceString(R.string.txt_retry_now), (dialog, which) -> {
sharedViewModel.startPrintProcess();
})
.setCancelable(false)
.create();
builder.show();
}
private String getECRResponseMessage() {
TransactionsResp resp = CoreUtils.getInstance(sharedViewModel).generateResponseMsg();
return ECRProcess.INSTANCE.generateECRResponse(resp);
}
private void ecrAction() {
LogUtil.d(TAG,"ECR Response :"+getECRResponseMessage());
ECRHelper.INSTANCE.send(getECRResponseMessage().getBytes());
ECRHelper.INSTANCE.setOnBindSuccess(() -> {
LogUtil.d(TAG, "Send Success!");
return null;
});
}
@Override
public void onBackPress() {
isCardInside();
}
}

View File

@ -0,0 +1,211 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.os.Handler;
import android.os.Looper;
import androidx.lifecycle.ViewModel;
import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum;
import com.utsmyanmar.checkxread.CheckXRead;
import com.utsmyanmar.checkxread.checkcard.CheckCardResultX;
import com.utsmyanmar.checkxread.model.CardDataX;
import com.utsmyanmar.checkxread.readcard.ReadCardResultX;
import com.utsmyanmar.checkxread.readcard.ReadCardX;
import com.utsmyanmar.checkxread.sdk.NexGoSDK;
//import com.utsmyanmar.mpulib.model.MPUCardData;
//import com.utsmyanmar.mpulib.readcard.CheckCardListener;
//import com.utsmyanmar.mpulib.readcard.ReadCardProcess;
//import com.utsmyanmar.mpulib.util.CardScheme;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmm.kbz.config.data.model.CardTransactionType;
import com.utsmm.kbz.util.enums.CardReadStatus;
import java.util.HashSet;
import javax.inject.Inject;
public class CardReadViewModel extends ViewModel {
private static final String TAG = CardReadViewModel.class.getSimpleName();
@Inject
public CardReadViewModel(){
}
private SingleLiveEvent<Boolean> flag = new SingleLiveEvent<>();
public SingleLiveEvent<String> errorCode = new SingleLiveEvent<>();
/*
* this was bind for UI / showing card information
* */
public SingleLiveEvent<CardDataX> cardData = new SingleLiveEvent<>();
// public SingleLiveEvent<CardScheme> cardSchemeData = new SingleLiveEvent<>();
public SingleLiveEvent<Integer> cardTypeData = new SingleLiveEvent<>();
public SingleLiveEvent<PayDetail> payDetail = new SingleLiveEvent<>();
public SingleLiveEvent<CardReadStatus> readStatus = new SingleLiveEvent<>();
public SingleLiveEvent<String> checkCardAlertMsg = new SingleLiveEvent<>();
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
private boolean oneTimeFlag = false;
private CardTransactionType cardTransactionType;
public void setCardTransactionType(CardTransactionType cardTransactionType) {
this.cardTransactionType = cardTransactionType;
}
public CardTransactionType getCardTransactionType() { return this.cardTransactionType; }
/**
* Check Card type whether it's MPU or EMV or MAG stripe card!!
* */
public void startCheckXProcess(int allType, int timeOut,CheckCardResultX cardResultX) {
CheckXRead.getInstance().startCheckXProcess(allType, timeOut,cardResultX);
}
public void startCheckXProcessNex(HashSet<CardSlotTypeEnum> allType, int timeOut, CheckCardResultX cardResultX) {
CheckXRead.getInstance().startCheckXProcessNex(allType, timeOut,cardResultX);
}
public void cancelCheckXProcess() {
CheckXRead.getInstance().cancelCheckXProcess();
}
public void startReadXProcess(ReadCardX readCardX,ReadCardResultX readCardResultX) {
CheckXRead.getInstance().startReadXProcess(readCardX,readCardResultX);
}
public void setCheckCardAlertMsg(String msg,boolean isAutoHide) {
checkCardAlertMsg.setValue(msg);
if(isAutoHide) {
Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(() -> checkCardAlertMsg.setValue(null), 5000);
}
}
public void resetUI() {
checkCardAlertMsg.setValue(null);
}
// public void initCardReadProcess(int allType, int timeOutInSec, ReadCardResult readCardResult) {
// ReadCardProcess.getInstance().startReadCard(allType,"",timeOutInSec,false).onStartReadCardProcess(new CheckCardListener() {
// @Override
// public void onCheckCardSuccess(int cardType, MPUCardData mpuCardData, CardScheme cardScheme) {
//
// cardData.postValue(mpuCardData);
// cardSchemeData.postValue(cardScheme);
// cardTypeData.postValue(cardType);
// PayDetail payDetailData = new PayDetail();
// payDetailData.setCardNo(mpuCardData.getPan());
// payDetailData.setEXPDate(mpuCardData.getExp());
// payDetailData.setAccountType(cardScheme.name());
// payDetailData.setCardType(cardType);
// payDetailData.setCardHolderName(mpuCardData.getCardHolderName());
// CardInfo cardInfo = new CardInfo();
// MAGCardInfo magCardInfo = new MAGCardInfo();
// LogUtil.d(TAG,"track 2 : "+mpuCardData.getTrack2());
// magCardInfo.setTrack2Cipher(mpuCardData.getTrack2());
// cardInfo.setMAGCardInfo(magCardInfo);
// payDetailData.setCardInfo(cardInfo);
//
// payDetail.postValue(payDetailData);
//
// mainThreadHandler.post(readCardResult::onSuccess);
//// readCardResult.onSuccess();
//
// }
//
// @Override
// public void onCheckCardFail(int code, String message) {
//
// if(code == -2801) {
// mainThreadHandler.post(readCardResult::onCommunicationError);
//// readCardResult.onCommunicationError();
// } else {
// mainThreadHandler.post(() -> readCardResult.onError(code,message));
//// readCardResult.onError(code,message);
// }
//
// }
// });
// }
//
// public SingleLiveEvent<CardReadStatus> startReadProcess(int allType,int timeOutInSec){
//
// ReadCardProcess.getInstance().startReadCard(allType,"",timeOutInSec,false).onStartReadCardProcess(new CheckCardListener() {
// @Override
// public void onCheckCardSuccess(int cardType, MPUCardData mpuCardData, CardScheme cardScheme) {
// flag.postValue(true);
// cardData.postValue(mpuCardData);
// cardSchemeData.postValue(cardScheme);
// cardTypeData.postValue(cardType);
// PayDetail payDetailData = new PayDetail();
// payDetailData.setCardNo(mpuCardData.getPan());
// payDetailData.setEXPDate(mpuCardData.getExp());
// payDetailData.setAccountType(cardScheme.name());
// payDetailData.setCardType(cardType);
// payDetailData.setCardHolderName(mpuCardData.getCardHolderName());
// CardInfo cardInfo = new CardInfo();
// MAGCardInfo magCardInfo = new MAGCardInfo();
// LogUtil.d(TAG,"track 2 : "+mpuCardData.getTrack2());
// magCardInfo.setTrack2Cipher(mpuCardData.getTrack2());
// cardInfo.setMAGCardInfo(magCardInfo);
// payDetailData.setCardInfo(cardInfo);
//
// payDetail.postValue(payDetailData);
//
// readStatus.postValue(CardReadStatus.SUCCESS);
//
//
// }
//
// @Override
// public void onCheckCardFail(int code, String message) {
//
// readStatus.postValue(CardReadStatus.FAIL);
// // this action just need to do once because there's too many reason to get fail
// if(!oneTimeFlag){
// errorCode.postValue(code+":"+message);
// flag.postValue(false);
// cardSchemeData.postValue(CardScheme.UNK);
// oneTimeFlag = true;
// }
//
// }
// });
//
// return readStatus;
// }
public void resetOneTimeFlag(){
oneTimeFlag = false;
}
public void cancelCheckCard(){
NexGoSDK.getInstance().cancelCheckCard();
}
// public void checkCard(){
// int allType = AidlConstants.CardType.NFC.getValue() | AidlConstants.CardType.IC.getValue() | AidlConstants.CardType.MAGNETIC.getValue();
// ReadCardProcess.getInstance().startReadCard(allType,"",60,false).onStartReadCardProcess(new CheckCardListener() {
// @Override
// public void onCheckCardSuccess(int cardType, MPUCardData mpuCardData, CardScheme cardScheme) {
// System.out.println("Success");
// }
//
// @Override
// public void onCheckCardFail(int code, String message) {
//
// System.out.println("Failed");
// }
// });
// }
}

View File

@ -0,0 +1,460 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import androidx.lifecycle.ViewModel;
import com.sunmi.pay.hardware.aidl.bean.CardInfo;
import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
import com.sunmi.pay.hardware.aidlv2.bean.EMVCandidateV2;
import com.sunmi.pay.hardware.aidlv2.bean.EMVTransDataV2;
import com.sunmi.pay.hardware.aidlv2.emv.EMVListenerV2;
import com.sunmi.pay.hardware.aidlv2.emv.EMVOptV2;
import com.sunmi.pay.hardware.aidlv2.pinpad.PinPadOptV2;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.utils.core_utils.KernelDataProcessUtil;
import com.utsmm.kbz.MyApplication;
import com.utsmm.kbz.util.enums.EmvReadStatus;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
/*
* Currently this class is not used
* */
@HiltViewModel
public class EmvReadCardViewModel extends ViewModel {
private static final String TAG = EmvReadCardViewModel.class.getSimpleName();
private final Repository repository;
public SingleLiveEvent<String> cardNum = new SingleLiveEvent<>();
public SingleLiveEvent<String> expDate = new SingleLiveEvent<>();
public SingleLiveEvent<EmvReadStatus> resultStatus = new SingleLiveEvent<>();
public SingleLiveEvent<List<EMVCandidateV2>> emvList = new SingleLiveEvent<>();
public SingleLiveEvent<Boolean> isButtonVisible = new SingleLiveEvent<>();
public SingleLiveEvent<String> emvCardType = new SingleLiveEvent<>();
public SingleLiveEvent<String> errorCode = new SingleLiveEvent<>();
private String mTag9F06Value;
public TradeData mTradeData;
public PayDetail mPayDetail;
private EMVOptV2 mEMVOptV2;
private PinPadOptV2 mPinPadOptV2;
private static final int CHECK_CARD_FAIL = 1;
private static final int CHECK_CARD_SUCCESS = 2;
private static final int CHECK_CARD_MAG = 3;
private static final int CHECK_CARD_NFC = 4;
private static final int CHECK_CARD_IC = 5;
private static final int EMV_APP_SELECT = 6;
private static final int EMV_CONFIRM_CARD_NO = 7;
private Looper mLooper = Looper.getMainLooper();
private final Handler mHandler = new Handler(mLooper) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case CHECK_CARD_FAIL:
String hint = (String) msg.obj;
resultStatus.postValue(EmvReadStatus.FAIL);
// checkCardFail(msg.arg1, hint);
break;
case EMV_APP_SELECT:
List<EMVCandidateV2> list = ( List<EMVCandidateV2> ) msg.obj;
emvList.postValue(list);
resultStatus.postValue(EmvReadStatus.SELECT_APP);
case CHECK_CARD_SUCCESS:
getCardInfo();
getF055Data();
terminateTrans();
resultStatus.postValue(EmvReadStatus.SUCCESS);
break;
case EMV_CONFIRM_CARD_NO:
getCardInfo();
getF055Data();
terminateTrans();
resultStatus.postValue(EmvReadStatus.SUCCESS);
try {
mEMVOptV2.importCardNoStatus(0);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case CHECK_CARD_MAG:
Bundle bundle = (Bundle) msg.obj;
// handleMagCard(bundle);
break;
case CHECK_CARD_NFC:
// handleNFCCard();
break;
case CHECK_CARD_IC:
// handleICCard();
break;
}
}
};
public void terminateTrans(){
try {
mEMVOptV2.abortTransactProcess();
} catch (RemoteException e) {
e.printStackTrace();
}
}
public void setEmvAppSelect(int position){
try {
mEMVOptV2.importAppSelect(position);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Inject
public EmvReadCardViewModel(Repository repository){
this.repository = repository;
}
public void setTradeData(TradeData tradeData){
this.mTradeData = tradeData;
mPayDetail = mTradeData.getPayDetail();
}
public TradeData getTradeData(){
return mTradeData;
}
public void startProcess(){
initView();
initEmvTlvData();
transactProcess();
}
private void initView(){
mEMVOptV2 = MyApplication.getInstance().mEMVOptV2;
mPinPadOptV2 = MyApplication.getInstance().mPinPadOptV2;
}
private void initEmvTlvData() {
try {
// set PayWave(Visa) tlv data
String[] tagsPayWave = {"DF8124", "DF8125", "DF8126"};
String[] valuesPayWave = {"999999999999", "999999999999", "000000000000"};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYWAVE, tagsPayWave, valuesPayWave);
// set JCB Wave tlv data
String[] tagsJCB = {"9F53", "DF8161"};
String[] valuesJCB = {"708000", "7F00"};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_JCB, tagsJCB, valuesJCB);
// set PayPass(MasterCard) tlv data
String[] tagsPayPass = {"DF8117", "DF8118", "DF8119", "DF811F", "DF811E", "DF812C",
"DF8123", "DF8124", "DF8125", "DF8126",
"DF811B", "DF811D", "DF8122", "DF8120", "DF8121"};
String[] valuesPayPass = {"E0", "F8", "F8", "E8", "00", "00",
"000000000000", "000000100000", "999999999999", "000000100000",
"30", "02", "0000000000", "000000000000", "000000000000"};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS, tagsPayPass, valuesPayPass);
// set AMEX(AmericanExpress) tlv data
String[] tagsAE = {"9F6D", "9F6E", "9F33", "9F35", "DF8168", "DF8167", "DF8169", "DF8170"};
String[] valuesAE = {"C0", "D8E00000", "E0E888", "22", "00", "00", "00", "60"};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_AE, tagsAE, valuesAE);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private void transactProcess() {
// LogUtil.e(TAG, "***************************************************************");
// LogUtil.e(TAG, "****************************Start Process**********************");
// LogUtil.e(TAG, "***************************************************************");
//
// LogUtil.e(TAG, "transactProcess");
try {
mEMVOptV2.initEmvProcess();
EMVTransDataV2 emvTransData = new EMVTransDataV2();
emvTransData.amount = "1000";
// if(mPayDetail.cardType == AidlConstantsV2.CardType.NFC.getValue()){
// emvTransData.flowType = AidlConstantsV2.EMV.FlowType.TYPE_NFC_SPEEDUP;
// }else{
// emvTransData.flowType = AidlConstantsV2.EMV.FlowType.TYPE_EMV_STANDARD;
// }
emvTransData.flowType = 2;
emvTransData.cardType = mPayDetail.cardType;
mEMVOptV2.transactProcess(emvTransData, mEMVListener);
} catch (Exception e) {
resultStatus.postValue(EmvReadStatus.FAIL);
e.printStackTrace();
}
}
private void initEmvProcess() {
try {
// Set normal TLV data
String[] tags = {"5F2A", "5F36"};
String[] values = {"0104", "00"};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tags, values);
} catch (RemoteException e) {
e.printStackTrace();
}
}
private EMVListenerV2 mEMVListener = new EMVListenerV2.Stub() {
@Override
public void onWaitAppSelect(List<EMVCandidateV2> appNameList, boolean isFirstSelect) throws RemoteException {
// LogUtil.e(TAG, "onWaitAppSelect isFirstSelect:" + isFirstSelect);
mHandler.obtainMessage(EMV_APP_SELECT, appNameList).sendToTarget();
}
@Override
public void onAppFinalSelect(String tag9F06Value) throws RemoteException {
// LogUtil.d(TAG, "tag9F06Value:" + tag9F06Value);
mTag9F06Value = tag9F06Value;
initEmvProcess();
/* if (tag9F06Value != null && tag9F06Value.length() > 0) {
boolean visa = tag9F06Value.startsWith("A000000003");
boolean master = tag9F06Value.startsWith("A000000004");
boolean unionPay = tag9F06Value.startsWith("A000000333");
boolean jcb = tag9F06Value.startsWith("A000000065");
if (visa) {
emvCardType.postValue("VISA");
// VISA - PayWave
mPayDetail.setAccountType("Visa");
LogUtil.d(TAG, "detect VISA card");
String[] tagsPayWave = {
// "DF8124", "DF8125", "DF8126"
"9F33"
};
String[] valuesPayWave = {
// "999999999999", "999999999999", "000000000000"
"002888"
};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tagsPayWave, valuesPayWave);
} else if (master) {
emvCardType.postValue("MASTER");
// MasterCard - PayPass
mPayDetail.setAccountType("Master");
LogUtil.d(TAG, "detect MasterCard card");
// String[] tagsPayPass = {
// "DF8118", "DF8119", "DF811F", "DF811E",
// "DF8123", "DF8124", "DF8125", "DF8126",
// "DF811B", "DF811D", "DF8122", "DF8120", "DF8121"
// };
// String[] valuesPayPass = {
// "28", "08", "08", "10",
// "000000010000", "000000030000", "000000050000", "000000001000",
// "00", "00", "0000000000", "0000000000", "0000000000"
// };
String[] tagsPayPass = {
"DF8117", "DF8118", "DF8119", "DF811F", "DF811E", "DF812C",
"DF8123", "DF8124", "DF8125", "DF8126",
"DF811B", "DF811D", "DF8122", "DF8120", "DF8121"
};
String[] valuesPayPass = {
"E0", "F8", "F8", "E8", "00", "00",
"999999999999", "000000001000", "000000001000", "000000001000",
"30", "02", "0000000000", "000000000000", "000000000000"
};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS, tagsPayPass, valuesPayPass);
} else if (unionPay) {
emvCardType.postValue("UnionPay");
mPayDetail.setAccountType("UPI");
// UnionPay
LogUtil.d(TAG, "detect UnionPay card");
String[] tagsPayPass = {
"DF8120", "DF8121", "DF8122"
};
String[] valuesPayPass = {
"D84000A800", "DC4004F800", "0100000000"
};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tagsPayPass, valuesPayPass);
} else if(jcb) {
emvCardType.postValue("JCB");
mPayDetail.setAccountType("JCB");
// UnionPay
LogUtil.d(TAG, "detect JCB card");
}
}
if (AidlConstants.CardType.IC.getValue() == mPayDetail.cardType) {
String[] tags = {
"9F33", "9F09", "DF81FF"
};
String[] values = {
"6060C8", "0111", "01"
// "0008C8", "0111", "01"
};
mEMVOptV2.setTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tags, values);
}*/
mEMVOptV2.importAppFinalSelectStatus(0);
}
@Override
public void onConfirmCardNo(String cardNo) {
// LogUtil.e(TAG, "onConfirmCardNo cardNo:" + cardNo);
mHandler.sendEmptyMessage(EMV_CONFIRM_CARD_NO);
}
@Override
public void onRequestShowPinPad(int type, int remainTime) throws RemoteException {
// LogUtil.e(TAG, "requestShowPinPad type:" + type + " remainTime:" + remainTime);
mHandler.sendEmptyMessage(CHECK_CARD_SUCCESS);
}
@Override
public void onRequestSignature() throws RemoteException {
// LogUtil.e(TAG, "signatureStatus");
mEMVOptV2.importSignatureStatus(0);
}
@Override
public void onCertVerify(int certType, String certInfo) throws RemoteException {
// LogUtil.e(TAG, "onCertVerify certType:" + certType + " certInfo:" + certInfo);
mEMVOptV2.importCertStatus(0);
}
@Override
public void onOnlineProc() throws RemoteException {
// LogUtil.e(TAG, "onProcessEnd");
mHandler.sendEmptyMessage(CHECK_CARD_SUCCESS);
}
@Override
public void onCardDataExchangeComplete() throws RemoteException {
// LogUtil.e(TAG, "onCardDataExchangeComplete");
}
@Override
public void onConfirmationCodeVerified() throws RemoteException {
// LogUtil.e(TAG, "onConfirmationCodeVerified");
}
@Override
public void onRequestDataExchange(String s) throws RemoteException {
}
@Override
public void onTermRiskManagement() throws RemoteException {
}
@Override
public void onPreFirstGenAC() throws RemoteException {
}
@Override
public void onTransResult(int code, String desc) throws RemoteException {
/*
* Temporary Error Message
* */
String errorMsg = "Card read failed!";
errorCode.postValue(code+":"+errorMsg);
if (code != 0) {
if( code == -50011) {
mHandler.sendEmptyMessage(CHECK_CARD_SUCCESS);
} else {
mHandler.obtainMessage(CHECK_CARD_FAIL, code, code, desc).sendToTarget();
}
} else {
mHandler.sendEmptyMessage(CHECK_CARD_SUCCESS);
}
// LogUtil.e(TAG, "onTransResult code:" + code + " desc:" + desc);
// LogUtil.e(TAG, "***************************************************************");
// LogUtil.e(TAG, "****************************End Process************************");
// LogUtil.e(TAG, "***************************************************************");
}
};
private void getCardInfo() {
String[] tagList = {"5A", "5F24", "57", "5F34", "9F6B"};
byte[] outData = new byte[1024];
try {
int len = mEMVOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tagList, outData);
if (len > 0) {
byte[] data = new byte[len];
System.arraycopy(outData, 0, data, 0, len);
CardInfo cardInfo = KernelDataProcessUtil.getCardInfo(mPayDetail.cardType, data);
mTradeData = KernelDataProcessUtil.fillTradeDataInfo(cardInfo, mTradeData);
//display card data in layout
cardNum.postValue(mPayDetail.getCardNo());
expDate.postValue(mPayDetail.getEXPDate());
} else {
// LogUtil.e(Constant.TAG, "The data length of the card information is negative = " + len);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getF055Data() {
/* For Yoma */
/*Jun 6 Added 9F2A*/
String[] tagList={
"9F2A","9F26","9F27","9F10","9F37","9F36","95","9A","9C","9F02","5F2A","5F34","82","9F1A", //field 55 tag
"9F03","9F33","4F","9F08","9F34","9F35","9F1E","9F53","84","9F09","9F41", //field55 tag
"9F5B","8A","9B","9F6E","9F7C","9F4C","50","9F12","DF01","9F63","5F20","9F0B","9F42"
};
byte[] outData = new byte[2048];
try {
int len = mEMVOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_NORMAL, tagList, outData);
if (len > 0) {
byte[] data = new byte[len];
System.arraycopy(outData, 0, data, 0, len);
mTradeData = KernelDataProcessUtil.readKernelData(data, mTradeData);
} else {
// LogUtil.e(Constant.TAG, "Get the data length of the 55 field as a negative number = " + len);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,596 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import com.google.gson.Gson;
import com.nexgo.common.ByteUtils;
import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.oaf.apiv3.emv.EmvDataSourceEnum;
import com.nexgo.oaf.apiv3.emv.EmvOnlineResultEntity;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.baselib.util.enums.EmvResultStatus;
import com.utsmyanmar.baselib.viewModel.EmvBaseViewModel;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.model.enums.TransCVM;
import com.utsmyanmar.paylibs.network.ISOSocket;
import com.utsmyanmar.paylibs.reversal.ReversalAction;
import com.utsmyanmar.paylibs.reversal.ReversalListener;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.transactions.TransactionsOperation;
import com.utsmyanmar.paylibs.transactions.TransactionsOperationListener;
import com.utsmyanmar.paylibs.utils.DemoUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionType;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.ui.core_viewmodel.transactions.ProcessingTransaction;
import com.utsmm.kbz.util.enums.TransResultStatus;
import com.utsmyanmar.paylibs.utils.LogUtil;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class EmvTransactionProcessViewModel extends EmvBaseViewModel implements ProcessingTransaction {
private final Repository repository;
private static final String TAG = EmvTransactionProcessViewModel.class.getSimpleName();
private SingleLiveEvent<TransResultStatus> transResult = new SingleLiveEvent<>();
private static final String TRY_SECONDARY = "TRY_SECONDARY";
private static final String PIN_PAD_FAILED = "Pin pad failed";
private static final String PIN_PAD_TIMEOUT = "Pin pad timeout!";
private static final String RC_APPROVED_V1 = "00";
private static final String RC_APPROVED_V2 = "000";
private static final String REVERSAL = "REVERSAL";
private EmvOnlineResultEntity emvOnlineResult = new EmvOnlineResultEntity();
@Inject
public EmvTransactionProcessViewModel(Repository repository,EmvParamOperation emvParamOperation) {
super(repository,emvParamOperation);
this.repository = repository;
}
@Override
protected void handleMsg(Message msg) {
switch (msg.what) {
case PIN_CLICK_NUMBER:
showPasswordView(msg.arg1);
break;
case PIN_CLICK_CONFIRM:
// increasedKSN();
if (emvHandler == null) {
LogUtil.e(TAG, "Cannot handle PIN confirm - emvHandler is null");
emvResultStatus.postValue(EmvResultStatus.ERROR);
errorCodeMsg.postValue("-1010:EMV Handler not available for PIN confirm");
break;
}
try {
if (mPayDetail.PINCipher != null && !mPayDetail.PINCipher.isEmpty()) {
emvHandler.onSetPinInputResponse(true, false);
} else if (isOfflinePinEntered) {
emvHandler.onSetPinInputResponse(true, false);
} else {
emvHandler.onSetPinInputResponse(false, true);
}
if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE || transType.getValue() == TransactionsType.PRE_AUTH_VOID || transType.getValue() == TransactionsType.REFUND) {
emvResultStatus.postValue(EmvResultStatus.ON_NEXT_SCREEN);
}
} catch (Exception e) {
LogUtil.e(TAG, "Exception during PIN confirm handling: " + e.getMessage());
e.printStackTrace();
emvResultStatus.postValue(EmvResultStatus.ERROR);
errorCodeMsg.postValue("-1011:PIN confirm exception: " + e.getMessage());
}
break;
case PIN_CLICK_CANCEL:
LogUtil.d(TAG, "ON CLICK CANCEL");
if (emvHandler == null) {
LogUtil.e(TAG, "Cannot handle PIN cancel - emvHandler is null");
emvResultStatus.postValue(EmvResultStatus.ERROR);
errorCodeMsg.postValue("-1012:EMV Handler not available for PIN cancel");
break;
}
try {
emvHandler.onSetPinInputResponse(false, false);
emvResultStatus.postValue(EmvResultStatus.PIN_PAD_CANCEL);
} catch (Exception e) {
LogUtil.e(TAG, "Exception during PIN cancel handling: " + e.getMessage());
e.printStackTrace();
emvResultStatus.postValue(EmvResultStatus.ERROR);
errorCodeMsg.postValue("-1013:PIN cancel exception: " + e.getMessage());
}
break;
case PIN_CLICK_CLEAR:
pinEnterCount = 0;
pinText.postValue("");
break;
case PIN_TIME_OUT:
handleTransactionFail(msg.arg1, PIN_PAD_TIMEOUT);
break;
case PIN_ERROR:
// increasedKSN();
// importPinInputStatus(3);
handleTransactionFail(msg.arg1, PIN_PAD_FAILED);
break;
case EMV_APP_SELECT:
String[] candiNames = (String[]) msg.obj;
candiList.postValue(candiNames);
emvResultStatus.postValue(EmvResultStatus.SELECT_APP);
break;
case EMV_SIGNATURE:
if(SystemParamsOperation.getInstance().getUpiTCEnabled()) {
if(mPayDetail.getAmount() == 31300 || mPayDetail.getAmount() == 31400 || mPayDetail.getAmount() == 31600 || mPayDetail.getAmount() == 31700 || mPayDetail.getAmount() == 8100000) {
// importSignatureStatus(0);
break;
}
if(mPayDetail.getAmount() < (SystemParamsOperation.getInstance().getJcbCvmLimit()*100)){
// importSignatureStatus(0);
break;
}
}
mPayDetail.setIsFreeSign(false);
mPayDetail.setTransCVM( TransCVM.SIGNATURE);
// importSignatureStatus(0);
break;
case EMV_SHOW_PIN_PAD:
LogUtil.d(TAG,"msg1 "+msg.arg1 + "- msg2 :"+msg.arg2);
startPinProcess(msg.arg1);
// emvHandler.onSetPinInputResponse(true,false);
// if(transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE || transType.getValue() == TransactionsType.PRE_AUTH_VOID || transType.getValue() == TransactionsType.REFUND ) {
// emvResultStatus.postValue(EmvResultStatus.ON_NEXT_SCREEN);
// }
break;
case EMV_ONLINE_PROCESS:
handleTransactionProcess();
break;
case EMV_ERROR:
handleTransactionFail(msg.arg1, msg.obj.toString());
break;
case EMV_TRY_AGAIN:
emvResultStatus.postValue(EmvResultStatus.TRY_AGAIN);
break;
case EMV_CONFIRM_CODE_VERIFY:
emvResultStatus.postValue(EmvResultStatus.CONFIRM_CODE_VERIFY);
break;
case EMV_SUCCESS_ONLINE:
transResult.postValue(TransResultStatus.SUCCESS);
break;
case EMV_FAILURE_ONLINE:
transResult.postValue(TransResultStatus.FAIL);
break;
case EMV_SUCCESS_OFFLINE:
transResult.postValue(TransResultStatus.OFFLINE_SUCCESS);
break;
case EMV_FAILURE_OFFLINE:
transResult.postValue(TransResultStatus.OFFLINE_FAILURE);
break;
}
}
public void onCancelEmvTransaction(){
LogUtil.e(TAG,"Terminate Transaction : "+ mProcessStep);
if (emvHandler == null) {
LogUtil.e(TAG, "Cannot cancel EMV transaction - emvHandler is null");
emvResultStatus.postValue(EmvResultStatus.ERROR);
errorCodeMsg.postValue("-1008:EMV Handler not available for cancellation");
return;
}
try {
if (mProcessStep == EMV_APP_SELECT) {
emvHandler.onSetSelAppResponse(-1);
} else if (mProcessStep == EMV_FINAL_APP_SELECT) {
emvHandler.onSetSelAppResponse(-1);
} else if (mProcessStep == EMV_CONFIRM_CARD_NO) {
emvHandler.onSetConfirmCardNoResponse(false);
} else if (mProcessStep == EMV_CERT_VERIFY) {
// importCertStatus(1);
} else if (mProcessStep == PIN_ERROR) {
emvHandler.onSetPinInputResponse(false, false);
} else if (mProcessStep == EMV_ONLINE_PROCESS) {
importOnlineProcess(SdkResult.Success, new EmvOnlineResultEntity());
} else if (mProcessStep == EMV_SIGNATURE) {
// importSignatureStatus(1);
} else if (mProcessStep == EMV_SHOW_PIN_PAD) {
emvHandler.onSetPinInputResponse(false, false);
}
} catch (Exception e) {
LogUtil.e(TAG, "Exception during EMV transaction cancellation: " + e.getMessage());
e.printStackTrace();
emvResultStatus.postValue(EmvResultStatus.ERROR);
errorCodeMsg.postValue("-1009:EMV cancellation exception: " + e.getMessage());
}
}
public void setPayDetail(PayDetail payDetail) {
mPayDetail = payDetail;
mTradeData = new TradeData();
mTradeData.setPayDetail(payDetail);
}
public PayDetail getPayDetail() {
return mPayDetail;
}
public void resetProcessStepCount() {
mProcessStep = 0;
}
@Override
public void resetTransactionStatus() {
emvResultStatus.clear();
transResult.clear();
}
@Override
public SingleLiveEvent<TransResultStatus> getTransStatus() {
return transResult;
}
private boolean isCardLessTrans() {
return transType.getValue() == TransactionsType.VOID || transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE_VOID || transType.getValue() == TransactionsType.PRE_AUTH_VOID || transType.getValue() == TransactionsType.REFUND;
}
@Override
public void startOnlineProcess() {
isReversal = false;
TransactionsOperation.getInstance().getStartOperation(mTradeData, transType.getValue()).checkOperation(new TransactionsOperationListener() {
@Override
public void onSuccess(TradeData tradeData) {
/*Jun 15 2022*/
PayDetail payDetailRes = tradeData.getPayDetail();
payDetailRes.setInvoiceNo(SystemParamsOperation.getInstance().getIncrementInvoiceNum());
LogUtil.d(TAG,"Transaction Operation Success: "+payDetailRes.getTradeAnswerCode());
LogUtil.d(TAG,"Transaction Type: "+payDetailRes.getTransactionType());
if (TextUtils.equals(payDetailRes.getTradeAnswerCode(), RC_APPROVED_V1) || TextUtils.equals(payDetailRes.getTradeAnswerCode(), RC_APPROVED_V2) ) {
if (transType.getValue() == TransactionsType.VOID) {
processVoidDB(payDetailRes);
} else if (transType.getValue() == TransactionsType.REFUND) {
processRefundDB(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_VOID) {
processPreVoidDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE) {
processPreCompDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE_VOID) {
processPreCompVoidDb(payDetailRes);
} else {
insertDB(payDetailRes);
}
payDetailResult.setValue(payDetailRes);
if(isCardLessTrans()) {
transResult.setValue(TransResultStatus.SUCCESS);
}
} else {
payDetailResult.setValue(payDetailRes);
if(isCardLessTrans()) {
transResult.setValue(TransResultStatus.FAIL);
}
/*
* @Note
* changed import status 2 to 0 at March 20, 2023
*/
// importOnlineProcessStatus(0);
}
}
@Override
public void onReversal(TradeData tradeData) {
LogUtil.d(TAG,"<<<< On Reversal >>>>");
isReversal = true;
transResult.postValue(TransResultStatus.REVERSAL_PREPARE);
int reversalDelay = 15000;
if (SystemParamsOperation.getInstance().getReversalDelay() != null) {
if (!TextUtils.equals(SystemParamsOperation.getInstance().getReversalDelay(), "")) {
reversalDelay = Integer.parseInt(SystemParamsOperation.getInstance().getReversalDelay() + "000");
}
}
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(() -> {
PayDetail payDetailReversal = tradeData.getPayDetail();
if (payDetailReversal.getTransactionType() == TransactionType.SALE || payDetailReversal.getTransactionType() == TransactionType.VOID || payDetailReversal.getTransactionType() == TransactionType.REFUND || payDetailReversal.getTransactionType() == TransactionType.PRE_SALE || payDetailReversal.getTransactionType() == TransactionType.CASH_ADVANCE || payDetailReversal.getTransactionType() == TransactionType.PRE_SALE_CANCEL || payDetailReversal.getTransactionType() == TransactionType.PRE_SALE_COMPLETE || payDetailReversal.getTransactionType() == TransactionType.PRE_SALE_COMPLETE_VOID) {
emvResultStatus.postValue(EmvResultStatus.REVERSAL_PROCESS);
transResult.postValue(TransResultStatus.REVERSAL_PROCESS);
callReversal(tradeData);
} else {
emvResultStatus.postValue(EmvResultStatus.REVERSAL_FAIL);
transResult.postValue(TransResultStatus.REVERSAL_FAIL);
}
}, reversalDelay);
}
@Override
public void onError(String message) {
LogUtil.e(TAG, "<<<< On Error >>>>");
LogUtil.e(TAG, "error message:" + message);
if (TextUtils.equals(message, TRY_SECONDARY)) {
emvResultStatus.postValue(EmvResultStatus.SECONDARY);
transResult.postValue(TransResultStatus.SECONDARY);
startOnlineProcess();
} else {
importOnlineProcess(SdkResult.Fail,emvOnlineResult);
setNetWorkErrorDesc(message);
errorCodeMsg.setValue(message);
emvResultStatus.postValue(EmvResultStatus.NETWORK_ERROR);
transResult.postValue(TransResultStatus.NETWORK_ERROR);
}
}
});
}
@Override
public void startDemoProcess() {
SystemParamsOperation.getInstance().getIncrementInvoiceNum();
PayDetail payDetailRes;
if (transType.getValue() == TransactionsType.VOID) {
payDetailRes = DemoUtil.getInstance().builtDemoVoid(mPayDetail);
processVoidDB(payDetailRes);
} else if (transType.getValue() == TransactionsType.REFUND) {
payDetailRes = DemoUtil.getInstance().builtDemoRefund(mPayDetail);
processRefundDB(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_VOID) {
payDetailRes = DemoUtil.getInstance().builtDemoPreAuthVoid(mPayDetail);
processPreVoidDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE) {
payDetailRes = DemoUtil.getInstance().builtDemoPreAuthComp(mPayDetail);
processPreCompDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE_VOID) {
payDetailRes = DemoUtil.getInstance().builtDemoPreAuthCompVoid(mPayDetail);
processPreCompVoidDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.CASH_OUT){
payDetailRes = DemoUtil.getInstance().builtDemoCashAdvance(mPayDetail, emvCardType.getValue());
repository.insertPayDetail(payDetailRes);
} else if (transType.getValue() == TransactionsType.SALE){
payDetailRes = DemoUtil.getInstance().builtDemoSale(mPayDetail, emvCardType.getValue());
repository.insertPayDetail(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_SALE) {
payDetailRes = DemoUtil.getInstance().builtDemoPreAuthSale(mPayDetail, emvCardType.getValue());
repository.insertPayDetail(payDetailRes);
} else if (transType.getValue() == TransactionsType.TIP_ADJUSTMENT) {
payDetailRes = DemoUtil.getInstance().builtDemoTipAdjustment(mPayDetail);
repository.insertPayDetail(payDetailRes);
}else {
payDetailRes = DemoUtil.getInstance().builtDemoSale(mPayDetail, emvCardType.getValue());
}
payDetailResult.setValue(payDetailRes);
transResult.setValue(TransResultStatus.SUCCESS);
importOnlineProcess(SdkResult.Success,new EmvOnlineResultEntity());
}
@Override
public void insertDB(PayDetail payResult) {
payResult.setPINCipher("");
repository.insertPayDetail(payResult);
}
@Override
public void processVoidDB(PayDetail payResult) {
mPayDetail.setIsCanceled(true);
updatePayDetail(mPayDetail);
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
@Override
public void processPreVoidDb(PayDetail payResult) {
mPayDetail.setIsCanceled(true);
updatePayDetail(mPayDetail);
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
@Override
public void processPreCompDb(PayDetail payResult) {
// mPayDetail.setIsSettle(true);
// mPayDetail.setIsCanceled(true);
// updatePayDetail(mPayDetail);
// repository.insertPayDetail(updateCurrentDateAndTime(payResult));
if(oldTransPayDetail.getAmount() == payResult.getAmount()) {
oldTransPayDetail.setIsCanceled(true);
updatePayDetail(oldTransPayDetail);
} else {
oldTransPayDetail.setIsCanceled(false);
updatePayDetail(oldTransPayDetail);
}
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
@Override
public void processPreCompVoidDb(PayDetail payResult) {
mPayDetail.setIsCanceled(true);
updatePayDetail(mPayDetail);
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
@Override
public void processRefundDB(PayDetail payResult) {
mPayDetail.setReturnGood(true);
updatePayDetail(mPayDetail);
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
/*
* Need to await from host response , SDK called is a half in milliseconds faster than network called.
* if timeout setting is changed in terminal below code won't be work anymore... need to find out for other solutions.
* */
private void handleTransactionFail(int code, String description) {
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(()-> {
LogUtil.d(TAG,"On handleTransactionFail ::");
if(isReversal) {
transResult.setValue(TransResultStatus.REVERSAL_PREPARE);
} else {
emvResultStatus.postValue(EmvResultStatus.ERROR);
transResult.setValue(TransResultStatus.FAIL);
errorCodeMsg.postValue(code + ":" + description);
}
},500);
}
/*Online Process*/
private void handleTransactionProcess() {
String cardNo = mPayDetail.getCardNo();
if (cardNo == null || TextUtils.equals(cardNo, "")) {
getCardInfo();
}
getPayWaveData();
getF055Data();
if(transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE || transType.getValue() == TransactionsType.PRE_AUTH_VOID || transType.getValue() == TransactionsType.REFUND ) {
emvResultStatus.postValue(EmvResultStatus.ON_NEXT_SCREEN);
} else {
emvResultStatus.postValue(EmvResultStatus.SUCCESS);
}
}
private void handleTransactionProcessNex() {
Log.d("nexgo", "onOnlineProc");
Log.d("nexgo", "getEmvContactlessMode:" );
Log.d("nexgo", "getcardinfo:" + new Gson().toJson(emvHandler.getEmvCardDataInfo()));
Log.d("nexgo", "getEmvCvmResult:" + emvHandler.getEmvCvmResult());
Log.d("nexgo", "getSignNeed--" + emvHandler.getSignNeed());
byte[] tlv_5A = emvHandler.getTlv(new byte[]{(byte) 0x5A}, EmvDataSourceEnum.FROM_KERNEL);
Log.d("nexgo", "tlv_5A--" + ByteUtils.byteArray2HexString(tlv_5A));
byte[] tlv_95 = emvHandler.getTlv(new byte[]{(byte) 0x95}, EmvDataSourceEnum.FROM_KERNEL);
Log.d("nexgo", "tlv_95--" + ByteUtils.byteArray2HexString(tlv_95));
byte[] tlv_84 = emvHandler.getTlv(new byte[]{(byte) 0x84}, EmvDataSourceEnum.FROM_KERNEL);
Log.d("nexgo", "tlv_84--" + ByteUtils.byteArray2HexString(tlv_84));
byte[] tlv_50 = emvHandler.getTlv(new byte[]{(byte) 0x50}, EmvDataSourceEnum.FROM_KERNEL);
Log.d("nexgo", "tlv_50--" + ByteUtils.byteArray2HexString(tlv_50));
if(transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE || transType.getValue() == TransactionsType.PRE_AUTH_VOID || transType.getValue() == TransactionsType.REFUND ) {
emvResultStatus.postValue(EmvResultStatus.ON_NEXT_SCREEN);
} else {
emvResultStatus.postValue(EmvResultStatus.SUCCESS);
}
}
protected void callReversal(TradeData tradeData) {
ReversalAction.getInstance().setData(tradeData).enqueue().startReversal(new ReversalListener() {
@Override
public void onSuccessReversal() {
importOnlineProcess(SdkResult.Fail,emvOnlineResult);
emvResultStatus.postValue(EmvResultStatus.REVERSAL_SUCCESS);
transResult.postValue(TransResultStatus.REVERSAL_SUCCESS);
}
@Override
public void onNetworkFail(String msg) {
importOnlineProcess(SdkResult.Fail,emvOnlineResult);
}
@Override
public void onFailReversal(String msg) {
importOnlineProcess(SdkResult.Fail,emvOnlineResult);
if (!isSecondCall) {
if (!TextUtils.equals(msg, REVERSAL)) {
emvResultStatus.postValue(EmvResultStatus.REVERSAL_SECONDARY);
transResult.postValue(TransResultStatus.REVERSAL_SECONDARY);
ISOSocket.getInstance().switchIp();
isSecondCall = true;
callReversal(tradeData);
} else {
mPayDetail.setNeedReversal(true);
mPayDetail.setTransactionType(TransactionType.REVERSAL);
mPayDetail.setTransType(REVERSAL);
mPayDetail.setPID(null);
// insert db
repository.insertPayDetail(mPayDetail);
emvResultStatus.postValue(EmvResultStatus.REVERSAL_FAIL);
transResult.postValue(TransResultStatus.REVERSAL_FAIL);
isSecondCall = false;
}
} else {
mPayDetail.setNeedReversal(true);
mPayDetail.setTransactionType(TransactionType.REVERSAL);
mPayDetail.setTransType(REVERSAL);
mPayDetail.setPID(null);
// insert db
repository.insertPayDetail(mPayDetail);
emvResultStatus.postValue(EmvResultStatus.REVERSAL_FAIL);
transResult.postValue(TransResultStatus.REVERSAL_FAIL);
isSecondCall = false;
}
}
});
}
}

View File

@ -0,0 +1,138 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.text.TextUtils;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.ui.NumberKeyboard;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import java.text.DecimalFormat;
import java.util.Objects;
public class InputAmountViewModel extends ViewModel {
private static final String TAG = InputAmountViewModel.class.getSimpleName();
public MutableLiveData<String> inputAmountView = new MutableLiveData<>();
public SingleLiveEvent<String> invalidAmountMsg = new SingleLiveEvent<>();
public SingleLiveEvent<String> availableAmount = new SingleLiveEvent<>();
public InputAmountViewModel() {
inputAmountView.setValue("0");
}
private int countDecimalDigits(double number) {
String numberStr = Double.toString(number);
int decimalIndex = numberStr.indexOf('.');
return decimalIndex >= 0 ? numberStr.length() - decimalIndex - 1 : 0;
}
public NumberKeyboard.KeyClickCallback onKeyClick() {
return new NumberKeyboard.KeyClickCallback() {
@Override
public void onNumClick(int keyNum) {
if (inputAmountView.getValue().length() == 15) {
return;
}
if (TextUtils.equals(inputAmountView.getValue(), "0")) {
inputAmountView.setValue(keyNum + "");
} else if (inputAmountView.getValue().contains(".")) {
StringBuilder inputAmount = new StringBuilder();
inputAmount.append(inputAmountView.getValue());
int dotIndex = inputAmount.indexOf(".");
if(inputAmount.substring(dotIndex).length() > 0 && inputAmount.substring(dotIndex+1).length() == 2) {
return;
}
if (inputAmountView.getValue().contains(",")) {
inputAmountView.setValue(inputAmountView.getValue().replace(",", ""));
}
double amt = Double.parseDouble(inputAmountView.getValue());
if (countDecimalDigits(amt) < 2) {
inputAmountView.setValue(inputAmountView.getValue() + keyNum);
}
} else {
if (inputAmountView.getValue().contains(",")) {
inputAmountView.setValue(inputAmountView.getValue().replace(",", ""));
}
inputAmountView.setValue(inputAmountView.getValue() + keyNum);
double amt = Double.parseDouble(inputAmountView.getValue());
DecimalFormat formatter = new DecimalFormat("#,###");
inputAmountView.setValue(formatter.format(amt));
}
}
@Override
public void onDelClick() {
if (Objects.requireNonNull(inputAmountView.getValue()).contains(".")) {
return;
}
if (inputAmountView.getValue().length() == 15) {
return;
}
if (TextUtils.equals(inputAmountView.getValue(), "0")) {
inputAmountView.setValue("0.");
} else {
inputAmountView.setValue(inputAmountView.getValue() + ".");
}
}
@Override
public void onCleanClick() {
if (inputAmountView.getValue() != null) {
if (inputAmountView.getValue().contains(".")) {
StringBuilder inputAmount = new StringBuilder();
inputAmount.append(inputAmountView.getValue());
inputAmount.deleteCharAt(inputAmount.length() - 1);
inputAmountView.setValue(inputAmount.toString());
} else if (!inputAmountView.getValue().equals("0")) {
StringBuilder inputAmount = new StringBuilder();
inputAmount.append(inputAmountView.getValue());
if (inputAmount.length() > 4) {
if(inputAmount.toString().contains(",")) {
int commaIndex = inputAmount.indexOf(",");
inputAmount.deleteCharAt(commaIndex);
} else {
inputAmount.deleteCharAt(inputAmount.length() - 1);
}
inputAmountView.setValue(inputAmount.toString());
// inputAmount.deleteCharAt(inputAmount.toString().length() - 4);
// if (inputAmount.charAt(inputAmount.toString().length() - 4) == ',') {
// inputAmount.deleteCharAt(inputAmount.toString().length() - 4);
// }
// inputAmountView.setValue(inputAmount.toString());
} else if(inputAmount.length() == 1) {
inputAmountView.setValue("0");
} else {
StringBuilder currentAmount = new StringBuilder();
currentAmount.append(inputAmountView.getValue());
currentAmount.deleteCharAt(currentAmount.length() - 1);
inputAmountView.setValue(currentAmount.toString());
}
}
}
}
};
}
}

View File

@ -0,0 +1,60 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.text.TextUtils;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.ui.NumberKeyboard;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
public class InputApprovalViewModel extends ViewModel {
public SingleLiveEvent<String> inputApprovalView = new SingleLiveEvent<>();
public SingleLiveEvent<String> txtApproval = new SingleLiveEvent<>();
public InputApprovalViewModel(){
inputApprovalView.setValue("-");
}
public NumberKeyboard.KeyClickCallback onKeyClick(){
return new NumberKeyboard.KeyClickCallback() {
@Override
public void onNumClick(int keyNum) {
// if(inputApprovalView.getValue().length() == 12){
// return;
// }
if (TextUtils.equals(inputApprovalView.getValue(),"-")){
inputApprovalView.setValue(keyNum + "");
} else {
inputApprovalView.setValue(inputApprovalView.getValue().replace("-","") + keyNum + "");
}
}
@Override
public void onDelClick() {
System.out.println("onDel");
}
@Override
public void onCleanClick() {
if (inputApprovalView.getValue() != null) {
if (!inputApprovalView.getValue().equals("-")) {
StringBuilder inputCardNo = new StringBuilder();
inputCardNo.append(inputApprovalView.getValue());
if (inputCardNo.length() > 1) {
inputCardNo.deleteCharAt(inputCardNo.toString().length()-1);
inputApprovalView.setValue(inputCardNo.toString());
} else {
inputApprovalView.setValue("-");
}
}
}
}
};
}
}

View File

@ -0,0 +1,59 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.text.TextUtils;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.ui.NumberKeyboard;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
public class InputCardNoViewModel extends ViewModel {
public SingleLiveEvent<String> inputCardView = new SingleLiveEvent<>();
public InputCardNoViewModel(){
inputCardView.setValue("-");
}
public NumberKeyboard.KeyClickCallback onKeyClick(){
return new NumberKeyboard.KeyClickCallback() {
@Override
public void onNumClick(int keyNum) {
if(inputCardView.getValue().length() == 16){
return;
}
if (TextUtils.equals(inputCardView.getValue(),"-")){
inputCardView.setValue(keyNum + "");
} else {
inputCardView.setValue(inputCardView.getValue().replace("-","") + keyNum + "");
}
}
@Override
public void onDelClick() {
System.out.println("onDel");
}
@Override
public void onCleanClick() {
if (inputCardView.getValue() != null) {
if (!inputCardView.getValue().equals("-")) {
StringBuilder inputCardNo = new StringBuilder();
inputCardNo.append(inputCardView.getValue());
if (inputCardNo.length() > 1) {
inputCardNo.deleteCharAt(inputCardNo.toString().length()-1);
inputCardView.setValue(inputCardNo.toString());
} else {
inputCardView.setValue("-");
}
}
}
}
};
}
}

View File

@ -0,0 +1,120 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.text.TextUtils;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.ui.NumberKeyboard;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.util.enums.InputPasswordType;
public class InputPasswordViewModel extends ViewModel {
private static final String TAG = InputPasswordViewModel.class.getSimpleName();
public SingleLiveEvent<String> passwordInput = new SingleLiveEvent<>();
public MutableLiveData<String> maskedPassword = new MutableLiveData<>();
private StringBuilder inputSB = new StringBuilder();
private static final int PASSWORD_LENGTH = 6;
public SingleLiveEvent<Boolean> checkValid = new SingleLiveEvent<>();
public SingleLiveEvent<InputPasswordType> passwordType = new SingleLiveEvent<>();
public InputPasswordViewModel() {
}
public NumberKeyboard.KeyClickCallback onKeyClick() {
return new NumberKeyboard.KeyClickCallback() {
@Override
public void onNumClick(int keyNum) {
addText(keyNum + "");
}
@Override
public void onDelClick() {
}
@Override
public void onCleanClick() {
delLast();
}
};
}
public void clearInput() {
if (inputSB.length() > 0) {
inputSB.delete(0, inputSB.length());
}
}
private void addText(String text) {
if (inputSB.length() == PASSWORD_LENGTH) {
return;
}
inputSB.append(text);
maskedPassword.setValue(convertMaskedChar(inputSB.length()));
passwordInput.setValue(inputSB.toString());
}
private String convertMaskedChar(int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
sb.append("*");
}
return sb.toString();
}
private void delLast() {
if (inputSB.length() == 0)
return;
inputSB.deleteCharAt(inputSB.length() - 1);
maskedPassword.setValue(convertMaskedChar(inputSB.length()));
passwordInput.setValue(inputSB.toString());
}
public boolean onClickEnter() {
inputSB.setLength(0);
String password = "";
if (passwordType.getValue() == InputPasswordType.SETTLEMENT) {
password = SystemParamsOperation.getInstance().getSettlementPassword();
if (TextUtils.equals(password, "") || password == null) {
password = "123456";
}
} else if (passwordType.getValue() == InputPasswordType.SYSTEM) {
password = SystemParamsOperation.getInstance().getSystemPassword();
if (TextUtils.equals(password, "") || password == null) {
password = "111111";
}
} else if (passwordType.getValue() == InputPasswordType.SETTING) {
password = SystemParamsOperation.getInstance().getSettingPassword();
if (TextUtils.equals(password, "") || password == null) {
password = "222222";
}
}
if (TextUtils.equals(passwordInput.getValue(), password)) {
checkValid.setValue(true);
return true;
} else {
checkValid.setValue(false);
return false;
}
}
}

View File

@ -0,0 +1,84 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.text.TextUtils;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.baselib.ui.NumberKeyboard;
import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.utils.LogUtil;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class InputRRNViewModel extends ViewModel {
public SingleLiveEvent<String> inputRRNView = new SingleLiveEvent<>();
public SingleLiveEvent<String> txtRRN = new SingleLiveEvent<>();
private final Repository repository;
@Inject
public InputRRNViewModel(Repository repository){
inputRRNView.setValue("");
this.repository = repository;
}
public LiveData<PayDetail> searchPayDetail(String rrn) {
return repository.searchPayDetail(rrn);
}
public LiveData<PayDetail> searchPayDetail(String cardNo,String rrn) {
return repository.searchPayDetail(cardNo,rrn);
}
public NumberKeyboard.KeyClickCallback onKeyClick(){
return new NumberKeyboard.KeyClickCallback() {
@Override
public void onNumClick(int keyNum) {
LogUtil.d(Constant.TAG,"key click"+keyNum);
if(inputRRNView.getValue().length() == 12){
return;
}
if (TextUtils.equals(inputRRNView.getValue(),"-")){
inputRRNView.setValue(keyNum + "");
} else {
inputRRNView.setValue(inputRRNView.getValue().replace("-","") + keyNum + "");
}
}
@Override
public void onDelClick() {
System.out.println("onDel");
}
@Override
public void onCleanClick() {
if (inputRRNView.getValue() != null) {
if (!inputRRNView.getValue().equals("-")) {
StringBuilder inputCardNo = new StringBuilder();
inputCardNo.append(inputRRNView.getValue());
if (inputCardNo.length() > 1) {
inputCardNo.deleteCharAt(inputCardNo.toString().length()-1);
inputRRNView.setValue(inputCardNo.toString());
} else {
inputRRNView.setValue("-");
}
}
}
}
};
}
}

View File

@ -0,0 +1,61 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.text.TextUtils;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.ui.NumberKeyboard;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
public class InputTraceViewModel extends ViewModel {
public SingleLiveEvent<String> inputTraceView = new SingleLiveEvent<>();
public MutableLiveData<String> invoiceNo = new MutableLiveData<>("");
public InputTraceViewModel(){
inputTraceView.setValue("");
}
public NumberKeyboard.KeyClickCallback onKeyClick(){
return new NumberKeyboard.KeyClickCallback() {
@Override
public void onNumClick(int keyNum) {
if(invoiceNo.getValue().length() >= 6){
return;
}
if (TextUtils.equals(invoiceNo.getValue(),"")){
invoiceNo.setValue(keyNum + "");
} else {
invoiceNo.setValue(invoiceNo.getValue() + keyNum + "");
}
}
@Override
public void onDelClick() {
System.out.println("onDel");
}
@Override
public void onCleanClick() {
if (invoiceNo.getValue() != null) {
if (!invoiceNo.getValue().equals("")) {
StringBuilder inputCardNo = new StringBuilder();
inputCardNo.append(invoiceNo.getValue());
if (inputCardNo.length() > 0) {
inputCardNo.deleteCharAt(inputCardNo.toString().length()-1);
invoiceNo.setValue(inputCardNo.toString());
} else {
invoiceNo.setValue("");
}
}
}
}
};
}
}

View File

@ -0,0 +1,14 @@
package com.utsmm.kbz.ui.core_viewmodel;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
public class InputTransIdViewModel extends ViewModel {
public SingleLiveEvent<String> txtTransId = new SingleLiveEvent<>();
public InputTransIdViewModel(){
}
}

View File

@ -0,0 +1,409 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.graphics.Bitmap;
import dagger.hilt.android.lifecycle.HiltViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.ecr.data.TransType;
import com.utsmyanmar.ecr.data.model.Transactions;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
import com.utsmyanmar.paylibs.print.printx.PrintXStatus;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.utils.PrintStatus;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.util.enums.AccountType;
import com.utsmm.kbz.util.enums.SettlementType;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.enums.HostType;
import java.util.List;
import io.reactivex.rxjava3.core.Observable;
import com.utsmyanmar.paylibs.utils.LogUtil;
import javax.inject.Inject;
@HiltViewModel
public class SharedViewModel extends ViewModel {
private static final String TAG = SharedViewModel.class.getSimpleName();
private final Repository repository;
public SingleLiveEvent<TransactionsType> transactionsType = new SingleLiveEvent<>();
public SingleLiveEvent<SettlementType> settlementType = new SingleLiveEvent<>();
public SingleLiveEvent<AccountType> accountType = new SingleLiveEvent<>();
public SingleLiveEvent<String> amount = new SingleLiveEvent<>();
public SingleLiveEvent<Long> totalAmount = new SingleLiveEvent<>();
// it is to use as manual entry
public SingleLiveEvent<String> cardNo = new SingleLiveEvent<>();
public SingleLiveEvent<String> processCode = new SingleLiveEvent<>();
public SingleLiveEvent<PayDetail> payDetail = new SingleLiveEvent<>();
public SingleLiveEvent<PrintStatus> printStatus = new SingleLiveEvent<>();
public SingleLiveEvent<String> merchantName = new SingleLiveEvent<>();
public SingleLiveEvent<String> transactionName = new SingleLiveEvent<>();
/*Apr 28 2022*/
public SingleLiveEvent<List<PayDetail>> payDetailList = new SingleLiveEvent<>();
/*May 16 2022*/
public SingleLiveEvent<Boolean> isEcr = new SingleLiveEvent<>();
public SingleLiveEvent<String> traceNo = new SingleLiveEvent<>();
public SingleLiveEvent<String> rrNNo = new SingleLiveEvent<>();
public SingleLiveEvent<String> approvalCode = new SingleLiveEvent<>();
/*May 31 2022*/
public SingleLiveEvent<Boolean> isEcrFinished = new SingleLiveEvent<>();
/*Jun 3 2022*/
public SingleLiveEvent<Boolean> isEmv = new SingleLiveEvent<>();
/*Jun 22 2022*/
public SingleLiveEvent<String> sendMsg = new SingleLiveEvent<>();
public SingleLiveEvent<String> qrData = new SingleLiveEvent<>();
public SingleLiveEvent<String> qrRefNum = new SingleLiveEvent<>();
public SingleLiveEvent<TransType> ecrCMD = new SingleLiveEvent<>();
// for settlement and review batch
public final SingleLiveEvent<TransMenu> _transMenu = new SingleLiveEvent<>();
public MutableLiveData<Integer> twoBtnLayout = new MutableLiveData<>(0);
public MutableLiveData<Integer> oneBtnLayout = new MutableLiveData<>(8);
public MutableLiveData<Integer> reprintBtnLayout = new MutableLiveData<>(8);
public SingleLiveEvent<Boolean> isReprint = new SingleLiveEvent<>();
public Bitmap signBitmap;
public SingleLiveEvent<HostType> hostType = new SingleLiveEvent<>();
public MutableLiveData<Integer> printReceiptButtons = new MutableLiveData<>(0);
public SingleLiveEvent<String> printReceiptMsg = new SingleLiveEvent<>();
public SingleLiveEvent<String> reprintTransTypeMsg = new SingleLiveEvent<>();
public SingleLiveEvent<Transactions> ecrTrans = new SingleLiveEvent<>();
public MutableLiveData<Boolean> _manualEntryStatus = new MutableLiveData<>();
public MutableLiveData<Boolean> fullVoidPreauthStatus = new MutableLiveData<>();
public MutableLiveData<Boolean> partialVoidPreauthStatus = new MutableLiveData<>();
/*
* separated PrintStatus as another variable to observe error stage.
* */
public SingleLiveEvent<PrintStatus> printXStatus = new SingleLiveEvent<>();
private final SingleLiveEvent<String> _errorFragmentMsg = new SingleLiveEvent<>();
private final SingleLiveEvent<String> _successFragmentMsg = new SingleLiveEvent<>();
private final SingleLiveEvent<String> _currencyText = new SingleLiveEvent<>();
public MutableLiveData<Integer> tapCardStatus = new MutableLiveData<>(1);
public MutableLiveData<Integer> tapDeviceStatus = new MutableLiveData<>(1);
public MutableLiveData<Integer> insertCardStatus = new MutableLiveData<>(1);
public MutableLiveData<Integer> swipeCardStatus = new MutableLiveData<>(0);
public MutableLiveData<String> countDownTxt = new MutableLiveData<>();
public MutableLiveData<Integer> mmqrLoading = new MutableLiveData<>();
public MutableLiveData<Integer> isMMPay = new MutableLiveData<>();
public MutableLiveData<Integer> isWavePay = new MutableLiveData<>();
public SingleLiveEvent<String> mockData = new SingleLiveEvent<>();
public MutableLiveData<Integer> qrPayVisibility = new MutableLiveData<>();
public MutableLiveData<Integer> loadingView = new MutableLiveData<>(8);
public SingleLiveEvent<String> loadingMsg = new SingleLiveEvent<>();
private SingleLiveEvent<Boolean> isFallback = new SingleLiveEvent<>();
private SingleLiveEvent<Boolean> _isCardDataExist = new SingleLiveEvent<>();
private SingleLiveEvent<Boolean> _isAmountExist = new SingleLiveEvent<>();
private PayDetail mPayDetail = new PayDetail();
// Updated constructor for Hilt ViewModel
@Inject
public SharedViewModel(Repository repository) {
this.repository = repository;
setPrintStatus(PrintStatus.FIRST_PRINT);
isReprint.setValue(false);
cardNo.setValue("");
}
public void setEmvTrans(boolean status) {
isEmv.setValue(status);
}
public SingleLiveEvent<Boolean> isEmvTrans() { return isEmv;}
private PayDetail getPayDetail() {
return mPayDetail;
}
private void setPayDetail(PayDetail payDetail) {
this.mPayDetail = payDetail;
}
public void setVisibilityPrintReceiptButtons(int value) {
printReceiptButtons.postValue(value);
}
public void postPrintReceiptMsg(String msg) { this.printReceiptMsg.postValue(msg);}
public void setPrintStatus(PrintStatus printStatus) { this.printStatus.setValue(printStatus); }
public void postPrintStatus(PrintStatus printStatus) { this.printStatus.postValue(printStatus); }
public SingleLiveEvent<PrintStatus> getPrintStatus() { return this.printStatus; }
public void setIsFallback(boolean status) { isFallback.setValue(status);}
public SingleLiveEvent<Boolean> getIsFallback() { return isFallback;}
public void setCardDataExist(boolean exist) { _isCardDataExist.setValue(exist);}
public SingleLiveEvent<Boolean> getCardDataExist() { return _isCardDataExist; }
public void setAmountExist(boolean exist) { _isAmountExist.setValue(exist);}
public SingleLiveEvent<Boolean> getAmountExist() { return _isAmountExist; }
public MutableLiveData<Boolean> getManualEntryStatus() { return _manualEntryStatus;}
public void setManualEntryStatus(boolean status) {
_manualEntryStatus.setValue(status);
}
public SingleLiveEvent<String> getErrorFragmentMsg() {
return _errorFragmentMsg;
}
public void set_errorFragmentMsg(String msg) {
this._errorFragmentMsg.setValue(msg);
}
public SingleLiveEvent<String> getSuccessFragmentMsg() {
return _successFragmentMsg;
}
public void set_currencyText(String msg) { this._currencyText.setValue(msg);}
public SingleLiveEvent<String> get_currencyText() { return _currencyText; }
public void set_successFragmentMsg(String msg) { this._successFragmentMsg.setValue(msg);}
public SingleLiveEvent<TransMenu> getTransMenu() {
return _transMenu;
}
public void setTransMenu(TransMenu transMenu) {
this._transMenu.setValue(transMenu);
}
public void loadingMsg(String msg) {
loadingView.setValue(0);
loadingMsg.setValue(msg);
}
public void dismissLoadingMsg() {
loadingView.setValue(8);
loadingMsg.setValue("");
}
public Observable<SiriusResponse> getParams(SiriusRequest siriusRequest) {
return repository.getParams(siriusRequest);
}
private void printReceipt(boolean isMerchantCopy) {
PrintXReceipt.getInstance().printSmileReceipt(payDetail.getValue(), isMerchantCopy, new PrintXStatus() {
@Override
public void onSuccess() {
if(isMerchantCopy) {
if(!SystemParamsOperation.getInstance().getDemoStatus()) {
if(SystemParamsOperation.getInstance().getPrintISOStatus()) {
PrintXReceipt.getInstance().printSmileISoReceipt(payDetail.getValue());
}
}
postPrintStatus(PrintStatus.FIRST_PRINT_DONE);
} else {
setPrintStatus(PrintStatus.SECOND_PRINT_DONE);
}
}
@Override
public void onFailure() {
LogUtil.d(TAG,"Print Status Result Failure!");
printXStatus.postValue(PrintStatus.EMPTY_PAPER_ROLL);
printReceiptButtons.postValue(0);
}
});
}
public void startPrintReceipt(boolean isFirstPrint) {
/*
* First Print is Merchant Copy..
* */
if(payDetail.getValue() != null) {
setPayDetail(payDetail.getValue());
}
LogUtil.d(TAG,"PayDetail trade Answer Code :"+getPayDetail().getTradeAnswerCode());
LogUtil.d(TAG,"PayDetail trade Answer Code :"+payDetail.getValue().getTradeAnswerCode());
PrintXReceipt.getInstance().printSmileReceipt(getPayDetail(), isFirstPrint, new PrintXStatus() {
@Override
public void onSuccess() {
if(isFirstPrint) {
if(!SystemParamsOperation.getInstance().getDemoStatus()) {
if(SystemParamsOperation.getInstance().getPrintISOStatus()) {
PrintXReceipt.getInstance().printSmileISoReceipt(getPayDetail());
}
}
postPrintStatus(PrintStatus.FIRST_PRINT_DONE);
if(isEcr.getValue() != null &&
isEcr.getValue() &&
SystemParamsOperation.getInstance().isAutoPrintCustomerCopy()) {
printReceiptButtons.postValue(8);
} else {
printReceiptButtons.postValue(0);
}
} else {
postPrintStatus(PrintStatus.SECOND_PRINT_DONE);
}
}
@Override
public void onFailure() {
LogUtil.d(TAG,"Print Status Result Failure!");
if (isFirstPrint) {
setPrintStatus(PrintStatus.EMPTY_PAPER_ROLL_FIRST);
} else {
setPrintStatus(PrintStatus.EMPTY_PAPER_ROLL_SECOND);
}
printReceiptButtons.postValue(0);
}
});
}
@SuppressWarnings("ConstantConditions")
public void startPrintProcess() {
LogUtil.d(TAG,"Print status :"+getPrintStatus().getValue());
switch (getPrintStatus().getValue()) {
case FIRST_PRINT:
printReceipt(true);
printReceiptMsg.postValue("Printing Receipt for Merchant");
printReceiptButtons.postValue(8);
break;
case SECOND_PRINT:
printReceipt(false);
printReceiptMsg.postValue("Printing Receipt for Customer");
break;
case NOT_PRINT:
// LogUtil.d(TAG, "Customer declined to print receipt");
break;
}
}
public void startPrintProcessSettlement() {
if(payDetail.getValue() == null) return;
PrintXReceipt.getInstance().printSmileSettlementReport(payDetail.getValue(), new PrintXStatus() {
@Override
public void onSuccess() {
}
@Override
public void onFailure() {
}
});
/*POS */
// PrintReceipt.getInstance().printSettlementReceiptPOS(settleData.getSaleCount(), settleData.getSaleAmount(), settleData.getRefundCount(), settleData.getRefundAmount(), settleData.getPreAuthCount(), settleData.getPreAuthAmount(), true);
}
public LiveData<List<PayDetail>> getLastThreeTransactions() {
return repository.getLastThreeTransactions();
}
public LiveData<PayDetail> getReversalTransaction(String voucherNo) {
return repository.getReversalTransaction(voucherNo);
}
public void updatePayDetail(PayDetail payDetail){
repository.updatePayDetail(payDetail);
}
public void insertPayDetail(PayDetail payDetail) { repository.insertPayDetail(payDetail); }
public void enableCardStatusIcon(boolean tapCard,boolean tapDevice,boolean insertCard, boolean swipeCard) {
tapCardStatus.setValue(tapCard ? 1 : 0);
tapDeviceStatus.setValue(tapDevice ? 1 : 0);
insertCardStatus.setValue(insertCard ? 1 : 0);
swipeCardStatus.setValue(swipeCard ? 1 : 0);
}
}

View File

@ -0,0 +1,82 @@
package com.utsmm.kbz.ui.core_viewmodel;
import androidx.lifecycle.ViewModel;
import dagger.hilt.android.lifecycle.HiltViewModel;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.baselib.repo.TMSRepository;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmm.kbz.util.enums.TMSDownloadStatus;
import javax.inject.Inject;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.Observable;
@HiltViewModel
public class TMSProcessViewModel extends ViewModel {
private final EmvParamOperation emvParamOperation;
private final TMSRepository tmsRepository;
private final Repository repository;
private SingleLiveEvent<TMSDownloadStatus> tmsDownloadStatus = new SingleLiveEvent<>();
private SingleLiveEvent<String> tmsDownloadMsg = new SingleLiveEvent<>();
private SingleLiveEvent<Boolean> isCalled = new SingleLiveEvent<>();
@Inject
public TMSProcessViewModel(EmvParamOperation emvParamOperation,TMSRepository tmsRepository,Repository repository) {
this.emvParamOperation = emvParamOperation;
this.tmsRepository = tmsRepository;
this.repository = repository;
}
public SingleLiveEvent<String> getTmsDownloadMsg() {
return tmsDownloadMsg;
}
public void setTmsDownloadMsg(String tmsDownloadMsg) {
this.tmsDownloadMsg.setValue(tmsDownloadMsg);
}
public SingleLiveEvent<Boolean> getIsCalled() {
return isCalled;
}
public void setIsCalled(boolean status) {
isCalled.setValue(status);
}
public SingleLiveEvent<TMSDownloadStatus> getTmsDownloadStatus() {
return tmsDownloadStatus;
}
public void setTmsDownloadStatus(TMSDownloadStatus tmsDownloadStatus) {
this.tmsDownloadStatus.setValue(tmsDownloadStatus);
}
public Observable<SiriusResponse> getParams(SiriusRequest siriusRequest) {
return tmsRepository.getParams(siriusRequest);
}
public Maybe<PayDetail> getLastTransactionRx() {
return repository.getLastTransactionRx();
}
public void loadEmvParameters() {
emvParamOperation.loadAidRids();
emvParamOperation.loadEmvTerminalParam();
}
public EmvParamOperation getEmvParamOperation() {
return emvParamOperation;
}
}

View File

@ -0,0 +1,424 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import androidx.databinding.BindingAdapter;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.network.ISOSocket;
import com.utsmyanmar.paylibs.reversal.ReversalAction;
import com.utsmyanmar.paylibs.reversal.ReversalListener;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.system.SystemDateTime;
import com.utsmyanmar.paylibs.transactions.TransactionsOperation;
import com.utsmyanmar.paylibs.transactions.TransactionsOperationListener;
import com.utsmyanmar.paylibs.utils.DemoUtil;
import com.utsmyanmar.paylibs.utils.PrintStatus;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionType;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.R;
import com.utsmm.kbz.ui.core_viewmodel.transactions.ProcessingTransaction;
import com.utsmm.kbz.util.enums.TransResultStatus;
import com.utsmyanmar.paylibs.utils.LogUtil;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class TransProcessViewModel extends ViewModel implements ProcessingTransaction {
private static final String TAG = TransProcessViewModel.class.getSimpleName();
private String pan;
private TradeData tradeData;
public PayDetail payDetail;
private static final String RC_APPROVED_V1 = "00";
private static final String RC_APPROVED_V2 = "000";
private static final String TRY_SECONDARY = "TRY_SECONDARY";
private static final String REVERSAL = "REVERSAL";
private boolean isSecondCall = false;
private boolean isThirdCall = false;
/* PIN CHANGE ISSUE RETRY PIN MISMATCH*/
private SingleLiveEvent<TransResultStatus> transResultStatus = new SingleLiveEvent<>();
public SingleLiveEvent<TransactionsType> transType = new SingleLiveEvent<>();
public SingleLiveEvent<PrintStatus> printStatus = new SingleLiveEvent<>();
public SingleLiveEvent<PayDetail> payDetailResult = new SingleLiveEvent<>();
public SingleLiveEvent<String> errorMessage = new SingleLiveEvent<>();
private final Repository repository;
private PayDetail oldTransPayDetail;
@Inject
public TransProcessViewModel(Repository repository) {
printStatus.setValue(PrintStatus.FIRST_PRINT);
this.repository = repository;
}
public void updatePayDetail(PayDetail payDetail) {
repository.updatePayDetail(payDetail);
}
private void deletePayDetail(PayDetail payDetail) {
repository.deletePayDetail(payDetail);
}
@BindingAdapter("layoutMarginTop")
public static void setLayoutMarginTop(View view, float dimen) {
ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
layoutParams.topMargin = (int) dimen;
view.setLayoutParams(layoutParams);
}
public void setTradeData(TradeData tradeData) {
this.tradeData = tradeData;
payDetail = tradeData.getPayDetail();
pan = payDetail.getCardNo();
}
public TradeData getTradeData() {
return tradeData;
}
public void setPayDetail(PayDetail payDetail) {
this.payDetail = payDetail;
tradeData = new TradeData();
tradeData.setPayDetail(payDetail);
}
public void setOldTransPayDetail(PayDetail payDetail) {
this.oldTransPayDetail = payDetail;
}
public PayDetail getPayDetail() {
return payDetail;
}
@Override
public void resetTransactionStatus() {
transResultStatus = new SingleLiveEvent<>();
}
@Override
public SingleLiveEvent<TransResultStatus> getTransStatus() {
return transResultStatus;
}
@Override
public void startOnlineProcess() {
TransactionsOperation.getInstance().getStartOperation(tradeData, transType.getValue()).checkOperation(new TransactionsOperationListener() {
@Override
public void onSuccess(TradeData TradeData) {
PayDetail payDetailRes = TradeData.getPayDetail();
LogUtil.d(TAG,"Transaction Operation Success: "+payDetailRes.getTradeAnswerCode());
if (TextUtils.equals(payDetailRes.getTradeAnswerCode(),RC_APPROVED_V1) || TextUtils.equals(payDetailRes.getTradeAnswerCode(),RC_APPROVED_V2)) {
payDetailRes.setInvoiceNo(SystemParamsOperation.getInstance().getIncrementInvoiceNum());
LogUtil.d(TAG,"MPU Transaction type :"+transType.getValue());
if (transType.getValue() == TransactionsType.VOID) {
// dbUpdateForVoid(payDetailRes);
processVoidDB(payDetailRes);
} else if (transType.getValue() == TransactionsType.REFUND) {
// dbUpdateForRefund(payDetailRes);
processRefundDB(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_VOID) {
// dbUpdateForPreVoid(payDetailRes);
processPreVoidDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE) {
// dbUpdateForPreComp(payDetailRes);
processPreCompDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE_VOID) {
// dbUpdateForPreCompVoid(payDetailRes);
processPreCompVoidDb(payDetailRes);
} else {
// insertPayDetail(payDetailRes);
insertDB(payDetailRes);
}
payDetailResult.postValue(payDetailRes);
transResultStatus.postValue(TransResultStatus.SUCCESS);
} else {
payDetailResult.postValue(payDetailRes);
transResultStatus.postValue(TransResultStatus.FAIL);
}
}
@Override
public void onReversal(TradeData TradeData) {
transResultStatus.postValue(TransResultStatus.REVERSAL_PREPARE);
int reversalDelay = 15000;
if (SystemParamsOperation.getInstance().getReversalDelay() != null) {
if (!TextUtils.equals(SystemParamsOperation.getInstance().getReversalDelay(), "")) {
reversalDelay = Integer.parseInt(SystemParamsOperation.getInstance().getReversalDelay() + "000");
}
}
//call reversal
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
//Do something after 100ms
PayDetail payDetailReversal = TradeData.getPayDetail();
if (payDetailReversal.getTransactionType() == TransactionType.SALE || payDetailReversal.getTransactionType() == TransactionType.VOID || payDetailReversal.getTransactionType() == TransactionType.REFUND || payDetailReversal.getTransactionType() == TransactionType.PRE_SALE || payDetailReversal.getTransactionType() == TransactionType.CASH_ADVANCE || payDetailReversal.getTransactionType() == TransactionType.PRE_SALE_CANCEL || payDetailReversal.getTransactionType() == TransactionType.PRE_SALE_COMPLETE || payDetailReversal.getTransactionType() == TransactionType.PRE_SALE_COMPLETE_VOID) {
transResultStatus.postValue(TransResultStatus.REVERSAL_PROCESS);
callReversal(TradeData);
} else {
transResultStatus.postValue(TransResultStatus.REVERSAL_FAIL);
}
}
}, reversalDelay);
}
@Override
public void onError(String message) {
if (TextUtils.equals(message, TRY_SECONDARY)) {
transResultStatus.postValue(TransResultStatus.SECONDARY);
startOnlineProcess();
} else {
errorMessage.postValue(message);
transResultStatus.postValue(TransResultStatus.ERROR);
}
}
});
}
@Override
public void startDemoProcess() {
SystemParamsOperation.getInstance().getIncrementInvoiceNum();
PayDetail payDetailRes;
if (transType.getValue() == TransactionsType.VOID) {
payDetailRes = DemoUtil.getInstance().builtDemoVoid(payDetail);
processVoidDB(payDetailRes);
} else if (transType.getValue() == TransactionsType.REFUND) {
payDetailRes = DemoUtil.getInstance().builtDemoRefund(payDetail);
processRefundDB(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_VOID) {
payDetailRes = DemoUtil.getInstance().builtDemoPreAuthVoid(payDetail);
processPreVoidDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE) {
payDetailRes = DemoUtil.getInstance().builtDemoPreAuthComp(payDetail);
processPreCompDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE_VOID) {
payDetailRes = DemoUtil.getInstance().builtDemoPreAuthCompVoid(payDetail);
processPreCompVoidDb(payDetailRes);
} else if (transType.getValue() == TransactionsType.CASH_OUT){
payDetailRes = DemoUtil.getInstance().builtDemoCashAdvance(payDetail, "MPU");
insertPayDetail(payDetailRes);
} else if (transType.getValue() == TransactionsType.SALE){
payDetailRes = DemoUtil.getInstance().builtDemoSale(payDetail, "MPU");
insertPayDetail(payDetailRes);
} else if (transType.getValue() == TransactionsType.PRE_AUTH_SALE) {
payDetailRes = DemoUtil.getInstance().builtDemoPreAuthSale(payDetail, "MPU");
insertPayDetail(payDetailRes);
} else if (transType.getValue() == TransactionsType.TIP_ADJUSTMENT) {
payDetailRes = DemoUtil.getInstance().builtDemoTipAdjustment(payDetail);
insertPayDetail(payDetailRes);
}else {
payDetailRes = DemoUtil.getInstance().builtDemoSale(payDetail, "MPU");
}
payDetailResult.postValue(payDetailRes);
transResultStatus.postValue(TransResultStatus.SUCCESS);
}
@Override
public void insertDB(PayDetail payResult) {
payDetail.setPINCipher("");
repository.insertPayDetail(payDetail);
}
@Override
public void processVoidDB(PayDetail payResult) {
payDetail.setIsCanceled(true);
updatePayDetail(payDetail);
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
@Override
public void processPreVoidDb(PayDetail payResult) {
oldTransPayDetail.setIsCanceled(true);
updatePayDetail(oldTransPayDetail);
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
@Override
public void processPreCompDb(PayDetail payResult) {
if(oldTransPayDetail.getAmount() == payResult.getAmount()) {
oldTransPayDetail.setIsCanceled(true);
updatePayDetail(oldTransPayDetail);
} else {
oldTransPayDetail.setIsCanceled(false);
updatePayDetail(oldTransPayDetail);
}
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
@Override
public void processPreCompVoidDb(PayDetail payResult) {
payDetail.setIsCanceled(true);
updatePayDetail(payDetail);
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
@Override
public void processRefundDB(PayDetail payResult) {
if(oldTransPayDetail != null) {
oldTransPayDetail.setReturnGood(true);
oldTransPayDetail.setIsCanceled(true);
updatePayDetail(oldTransPayDetail);
}
repository.insertPayDetail(updateCurrentDateAndTime(payResult));
}
private void insertPayDetail(PayDetail payDetail) {
payDetail.setPINCipher("");
repository.insertPayDetail(payDetail);
}
private PayDetail updateCurrentDateAndTime(PayDetail payDetail) {
String strDate = SystemDateTime.getMMDD();
String strTime = SystemDateTime.getHHmmss();
payDetail.setTradeDate(strDate);
payDetail.setTradeTime(strTime);
return payDetail;
}
/* Didn't setup reversal Need to check codes 25 March 21*/
private void callReversal(TradeData tradeData) {
/* added Sep 1 , 2023
* cuz getting error at inserting to db
* Unique PID
* */
payDetail = tradeData.getPayDetail();
ReversalAction.getInstance().setData(tradeData).enqueue().startReversal(new ReversalListener() {
@Override
public void onSuccessReversal() {
transResultStatus.postValue(TransResultStatus.REVERSAL_SUCCESS);
repository.insertPayDetail(payDetail);
}
@Override
public void onNetworkFail(String msg) {
LogUtil.d(TAG,"Reversal Action :"+msg);
SystemParamsOperation.getInstance().setSecondHostEnable(true);
if (SystemParamsOperation.getInstance().isSecondHostEnabled()) {
if (!isSecondCall) {
transResultStatus.postValue(TransResultStatus.REVERSAL_SECONDARY);
ISOSocket.getInstance().switchIp();
isSecondCall = true;
callReversal(tradeData);
} else if(!isThirdCall) {
isThirdCall = true;
transResultStatus.postValue(TransResultStatus.REVERSAL_THIRD);
callReversal(tradeData);
} else {
transResultStatus.postValue(TransResultStatus.REVERSAL_FAIL);
isSecondCall = false;
}
} else {
transResultStatus.postValue(TransResultStatus.REVERSAL_FAIL);
}
payDetail.setNeedReversal(true);
repository.insertPayDetail(payDetail);
}
@Override
public void onFailReversal(String msg) {
LogUtil.d(TAG,"On Fail Reversal :"+msg);
isSecondCall = false;
isThirdCall = false;
transResultStatus.postValue(TransResultStatus.REVERSAL_FAIL);
payDetail.setNeedReversal(true);
repository.insertPayDetail(payDetail);
// 8-March-2024
payDetail.setTradeAnswerCode("");
payDetailResult.setValue(payDetail);
}
});
}
}

View File

@ -0,0 +1,24 @@
package com.utsmm.kbz.ui.core_viewmodel.transactions;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmm.kbz.util.enums.TransResultStatus;
public interface ProcessingTransaction {
void resetTransactionStatus();
SingleLiveEvent<TransResultStatus> getTransStatus();
void startOnlineProcess();
void startDemoProcess();
void insertDB(PayDetail payResult);
void processVoidDB(PayDetail payResult);
void processPreVoidDb(PayDetail payResult);
void processPreCompDb(PayDetail payResult);
void processPreCompVoidDb(PayDetail payResult);
void processRefundDB(PayDetail payResult);
}

View File

@ -0,0 +1,89 @@
package com.utsmm.kbz.ui.dashboard;
import com.utsmyanmar.baselib.fragment.DataBindingBottomSheetFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.MainViewModel;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
public class DashboardPreAuthBottomSheet extends DataBindingBottomSheetFragment {
private MainViewModel mainViewModel;
private SharedViewModel sharedViewModel;
private static final int hostId = Constants.NAV_HOST_ID;
private int routeId;
private static final int currentId = R.id.dashboardPreAuthBottomSheet;
@Override
protected void initViewModel() {
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_dashboard_bottom_sheet_pre_auth, BR.mainViewModel,mainViewModel)
.addBindingParam(BR.shareViewModel,sharedViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
public class ClickEvent {
public void onClickBackButton() {
// routeId = R.id.action_dashboardPreAuthBottomSheet_to_dashboardBottomSheet;
// safeRouteTo(currentId,routeId,hostId);
}
public void onClickPreAuthCancel() {
routeId = R.id.action_dashboardPreAuthBottomSheet_to_dashboardPreAuthCancelBottomSheet;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickPreAuth() {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_SALE);
routeId = R.id.action_dashboardPreAuthBottomSheet_to_inputAmountFragment;
safeRouteTo(currentId,routeId,hostId);
}
}
public void onClickPreAuthComp() {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_COMPLETE);
routeId = R.id.action_dashboardPreAuthBottomSheet_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
}
public void onClickPreAuthCompCancel() {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_COMPLETE_VOID);
routeId = R.id.action_dashboardPreAuthBottomSheet_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
}
}
}

View File

@ -0,0 +1,95 @@
package com.utsmm.kbz.ui.dashboard;
import com.utsmyanmar.baselib.fragment.DataBindingBottomSheetFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.MainViewModel;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
public class DashboardPreAuthCancelBottomSheet extends DataBindingBottomSheetFragment {
private MainViewModel mainViewModel;
private SharedViewModel sharedViewModel;
private int currentId = R.id.dashboardPreAuthCancelBottomSheet;
private int routeId;
private int hostId = Constants.NAV_HOST_ID;
@Override
protected void initViewModel() {
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_dashboard_bottom_sheet_pre_auth_cancel,BR.mainViewModel,mainViewModel )
.addBindingParam(BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
public void onResume() {
super.onResume();
sharedViewModel.fullVoidPreauthStatus.setValue(SystemParamsOperation.getInstance().getFullVoidPreauthStatus());
sharedViewModel.partialVoidPreauthStatus.setValue(SystemParamsOperation.getInstance().getPartialVoidPreauthStatus());
}
public class ClickEvent {
public void onClickBack() {
routeId = R.id.action_dashboardPreAuthCancelBottomSheet_to_dashboardPreAuthBottomSheet;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickFullPreAuthVoid() {
if(sharedViewModel.fullVoidPreauthStatus.getValue() != null && !sharedViewModel.fullVoidPreauthStatus.getValue()) {
return;
}
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_VOID);
sharedViewModel.setTransMenu(TransMenu.PRE_AUTH_FULL_VOID);
sharedViewModel.amount.postValue(null);
routeId = R.id.action_dashboardPreAuthCancelBottomSheet_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
}
public void onClickPartialPreAuthVoid() {
if(sharedViewModel.partialVoidPreauthStatus.getValue() != null && !sharedViewModel.partialVoidPreauthStatus.getValue()) {
return;
}
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_VOID);
sharedViewModel.setTransMenu(TransMenu.PRE_AUTH_PARTIAL_VOID);
sharedViewModel.amount.postValue(null);
routeId = R.id.action_dashboardPreAuthCancelBottomSheet_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
}
}
}

View File

@ -0,0 +1,217 @@
package com.utsmm.kbz.ui.dashboard;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmm.kbz.util.enums.SettlementType;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.MainViewModel;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.config.data.model.Features;
import com.utsmm.kbz.ui.adapters.MainAdapter;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.util.tms.TMSUtil;
import java.util.ArrayList;
public class DashboardTransFragment extends DataBindingFragment {
private MainViewModel mainViewModel;
private SharedViewModel sharedViewModel;
private ArrayList<Features> featuresList = new ArrayList<>();
MainAdapter mainAdapter;
private static final int hostId = Constants.NAV_HOST_ID;
private int routeId;
private static final int currentId = R.id.dashboardTransFragment;
@Override
protected int currentId() {
return R.id.dashboardTransFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
protected void initViewModel() {
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon("Transactions");
initData();
}
private void initData() {
TMSUtil.getInstance().checkFeaturesList(requireActivity(),featuresList);
mainAdapter.notifyDataSetChanged();
}
@Override
protected DataBindingConfig getDataBindingConfig() {
mainAdapter = new MainAdapter(featuresList, item -> {
switch (item.getFeaturesType()) {
case VOID:
new DashboardTransFragment.ClickEvent().onClickVoid();
break;
case SETTLEMENT:
new DashboardTransFragment.ClickEvent().onClickSettlement();
break;
case REFUND:
new DashboardTransFragment.ClickEvent().onClickRefund();
break;
case PRE_AUTH_SALE:
new DashboardTransFragment.ClickEvent().onClickPreAuth();
break;
case PRE_AUTH_VOID:
new DashboardTransFragment.ClickEvent().onClickPreAuthCancel();
break;
case PRE_AUTH_COMPLETE:
new DashboardTransFragment.ClickEvent().onClickPreAuthComp();
break;
case PRE_AUTH_COMPLETE_VOID:
new DashboardTransFragment.ClickEvent().onClickPreAuthCompCancel();
break;
case CASH_ADVANCE:
new DashboardTransFragment.ClickEvent().onClickCashAdvance();
break;
case HISTORY:
new DashboardTransFragment.ClickEvent().onClickHistory();
break;
}
});
// RecyclerView recyclerView = ((DashboardTransBottomSheet) mBinding).getRoot().findViewById(R.id.recyclerViewFeatures);
return new DataBindingConfig(R.layout.fragment_dashboard_trans_screen, BR.vm,mainViewModel)
.addBindingParam(BR.shareViewModel,sharedViewModel)
.addBindingParam(BR.adapter, mainAdapter)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
public class ClickEvent {
public void onClickVoid () {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.VOID);
// sharedViewModel.transMenu.postValue(TransMenu.TRANSACTIONS);
sharedViewModel.setTransMenu(TransMenu.TRANSACTIONS);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
}
public void onClickSettlement() {
sharedViewModel.settlementType.setValue(SettlementType.NORMAL);
sharedViewModel.transactionsType.setValue(TransactionsType.SETTLEMENT);
sharedViewModel.setTransMenu(TransMenu.SETTLEMENT);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickRefund() {
sharedViewModel.transactionsType.setValue(TransactionsType.REFUND);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickPreAuth () {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_SALE);
routeId = R.id.action_dashboardTransFragment_to_inputAmountFragment;
safeRouteTo(currentId,routeId,hostId);
}
}
public void onClickPreAuthCancel () {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_VOID);
sharedViewModel.setTransMenu(TransMenu.PRE_AUTH_FULL_VOID);
sharedViewModel.amount.postValue(null);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickPreAuthComp () {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_COMPLETE);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickPreAuthCompCancel () {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_COMPLETE_VOID);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickCashAdvance() {
sharedViewModel.transactionsType.setValue(TransactionsType.CASH_OUT);
routeId = R.id.action_dashboardTransFragment_to_inputAmountFragment;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickHistory() {
routeId = R.id.action_dashboardTransFragment_to_manageFunctionFragment;
safeRouteTo(currentId,routeId,hostId);
}
}
}

View File

@ -0,0 +1,170 @@
package com.utsmm.kbz.ui.disabled;
import androidx.databinding.library.baseAdapters.BR;
import androidx.lifecycle.Observer;
import com.google.gson.stream.MalformedJsonException;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
//import com.utsmyanmar.samlsirius.LogOutCallback;
//import com.utsmyanmar.samlsirius.SiriusLifeCycleObserver;
import com.utsmm.kbz.MainViewModel;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.config.data.model.TMSUpdate;
import com.utsmm.kbz.util.tms.TMSUtil;
import dagger.hilt.android.AndroidEntryPoint;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
import javax.inject.Inject;
@AndroidEntryPoint
public class DisabledTerminalFragment extends DataBindingFragment {
private static final String TAG = DisabledTerminalFragment.class.getSimpleName();
private MainViewModel mainViewModel;
private int routeId = R.id.action_disabledTerminalFragment_to_nav_main;
@Inject
public EmvParamOperation emvParamOperation;
@Override
protected void initViewModel() {
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
}
@Override
public void onStart() {
super.onStart();
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon(getString(R.string.menu_disabled));
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_disable_terminal, BR.mainViewModel,mainViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@Override
protected int currentId() {
return R.id.disabledTerminalFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
private void getLastTrans() {
LogUtil.d(TAG,"This function was called!!!");
mainViewModel.getLastTransaction().observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
if(payDetail != null) {
downloadParams(payDetail.getTransType(),String.valueOf(payDetail.getTransNum()));
} else {
String lastTransName = SystemParamsOperation.getInstance().getLastTransName();
String lastTransTime = SystemParamsOperation.getInstance().getLastTransTime();
if(lastTransTime != null && !lastTransTime.isEmpty() && lastTransName != null && !lastTransName.isEmpty()) {
downloadParams(SystemParamsOperation.getInstance().getLastTransName(),SystemParamsOperation.getInstance().getLastTransTime());
} else {
long transTime = System.currentTimeMillis();
String transTimeInString = String.valueOf(transTime).substring(0,10);
downloadParams("...",transTimeInString);
}
}
}
});
}
private void downloadParams(String lastTransName,String lastTransTime) {
showLoadingDialog("Downloading...");
SiriusRequest siriusReq = TMSUtil.getInstance().generateRequestParams(getContext(),lastTransName,lastTransTime);
mainViewModel.getParams(siriusReq).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new io.reactivex.rxjava3.core.Observer<SiriusResponse>() {
@Override
public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {
LogUtil.d(TAG,"On Subscribe!");
}
@Override
public void onNext(@io.reactivex.rxjava3.annotations.NonNull SiriusResponse siriusResponse) {
TMSUtil.getInstance().initParams(siriusResponse, TMSUpdate.CHECK,emvParamOperation);
}
@Override
public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
dismissLoadingDialog();
if(e.getClass() == MalformedJsonException.class) {
showDeclineDialog("Terminal is not configured!");
} else {
showDeclineDialog("Failure!\n"+e.getMessage());
}
e.printStackTrace();
}
@Override
public void onComplete() {
dismissLoadingDialog();
mainViewModel.settlementStatus.setValue(SystemParamsOperation.getInstance().getSettlementStatus());
checkDisableStatus();
LogUtil.d(TAG,"On Complete!");
}
});
}
private void checkDisableStatus(){
if(SystemParamsOperation.getInstance().isActive()){
safeNavigateToRouteId();
} else {
showDeclineDialog("Terminal is still disabled!");
}
}
private void downloadTask() {
getLastTrans();
}
public class ClickEvent {
public void onRetry() {
downloadTask();
}
public void onExit() {
requireActivity().finishAffinity();
}
}
}

View File

@ -0,0 +1,358 @@
package com.utsmm.kbz.ui.kpay;
import android.os.Handler;
import android.os.Looper;
import dagger.hilt.android.lifecycle.HiltViewModel;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Flowable;
import io.reactivex.rxjava3.core.Maybe;
import io.reactivex.rxjava3.core.Observable;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.kizzy.xpay.util.Sign;
import com.utsmyanmar.baselib.network.model.DemoQRRequest;
import com.utsmyanmar.baselib.network.model.DemoQRResponse;
import com.utsmyanmar.baselib.network.model.DemoQRReturnRequest;
import com.utsmyanmar.baselib.network.model.DemoQRReturnResponse;
import com.utsmyanmar.baselib.network.model.DemoQRStatusRequest;
import com.utsmyanmar.baselib.network.model.DemoQRStatusResponse;
import com.utsmyanmar.baselib.network.model.KPayQRQueryRequest;
import com.utsmyanmar.baselib.network.model.KPayQRRequest;
import com.utsmyanmar.baselib.network.model.KPayQRResponse;
import com.utsmyanmar.baselib.network.model.KPayRefund;
import com.utsmyanmar.baselib.network.model.MMQRReturnRequest;
import com.utsmyanmar.baselib.network.model.MMQRReturnResponse;
import com.utsmyanmar.baselib.network.model.WaveAccessTokenResponse;
import com.utsmyanmar.baselib.network.model.WaveQRRequest;
import com.utsmyanmar.baselib.network.model.WaveQRResponse;
import com.utsmyanmar.baselib.network.model.WaveTokenResponse;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.baselib.util.TerminalUtil;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
@HiltViewModel
public class KPayViewModel extends ViewModel {
private static final String TAG = KPayViewModel.class.getSimpleName();
private final Repository repository;
private final String appKey = "UTSMMuat@2025";
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private final Handler mainHandler = new Handler(Looper.getMainLooper());
// Characters for generating random nonce_str
private static final String NONCE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final int NONCE_LENGTH = 32;
private final SecureRandom secureRandom = new SecureRandom();
private String generateRandomTwoChars() {
// You can reuse the existing character set and SecureRandom instance
StringBuilder randomChars = new StringBuilder(3);
for (int i = 0; i < 3; i++) {
randomChars.append(NONCE_CHARS.charAt(secureRandom.nextInt(NONCE_CHARS.length())));
}
return randomChars.toString();
}
/**
* Generates a random nonce string of specified length using alphanumeric characters
*
* @return Random nonce string (32 characters)
*/
private String generateNonceStr() {
StringBuilder nonce = new StringBuilder(NONCE_LENGTH);
for (int i = 0; i < NONCE_LENGTH; i++) {
nonce.append(NONCE_CHARS.charAt(secureRandom.nextInt(NONCE_CHARS.length())));
}
return nonce.toString();
}
/**
* Creates a KPay refund request with proper signing, nonce, and biz_content.
*
* @param refundOrderId The refund order id (unique per refund transaction)
* @param origOrderId The original merchant order id to refund
* @param mid The merchant id
* @param refundAmount Refund amount
* @param reason Refund reason (optional)
* @return KPayRefund.RefundRequest object ready for API submission
*/
public KPayRefund.RefundRequest createRefundRequest(
String refundOrderId,
String origOrderId,
String mid,
String refundAmount,
String reason
) {
String serialNum = TerminalUtil.getInstance().getSerialNo();
String nonceStr = generateNonceStr();
String time = String.valueOf(System.currentTimeMillis());
// Compose biz_content map for signature calculation
Map<String, Object> bizContent = new HashMap<>();
bizContent.put("refund_request_no", refundOrderId);
bizContent.put("merch_order_id", origOrderId);
bizContent.put("merch_code", mid);
bizContent.put("appid", "kp9b0794b349ae85b00c51e0677484c7");
if(!refundAmount.equals("0")) {
bizContent.put("refund_amount", refundAmount);
}
bizContent.put("refund_reason", reason);
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("timestamp", time);
requestMap.put("nonce_str", nonceStr);
requestMap.put("method", "kbz.payment.refund");
requestMap.put("sign_type", "SHA256");
requestMap.put("version", "1.0");
requestMap.put("biz_content", bizContent);
LogUtil.d(TAG,"request map :"+requestMap.toString());
String sign = Sign.INSTANCE.generateSign(requestMap, appKey);
if(!refundAmount.equals("0")) {
bizContent.put("refund_amount", refundAmount);
KPayRefund.RefundRequest.RequestBody.BizContent biz =
new KPayRefund.RefundRequest.RequestBody.BizContent(
"kp9b0794b349ae85b00c51e0677484c7",
mid,
origOrderId,
refundAmount, // This can be null for original refunds
refundOrderId,
reason
);
KPayRefund.RefundRequest.RequestBody body =
new KPayRefund.RefundRequest.RequestBody(
time,
nonceStr,
"kbz.payment.refund",
"SHA256",
sign,
"1.0",
biz
);
return new KPayRefund.RefundRequest(body);
} else {
KPayRefund.RefundRequest.RequestBody.BizContent biz =
new KPayRefund.RefundRequest.RequestBody.BizContent(
"kp9b0794b349ae85b00c51e0677484c7",
mid,
origOrderId,
refundOrderId,
reason
);
KPayRefund.RefundRequest.RequestBody body =
new KPayRefund.RefundRequest.RequestBody(
time,
nonceStr,
"kbz.payment.refund",
"SHA256",
sign,
"1.0",
biz
);
return new KPayRefund.RefundRequest(body);
}
}
public KPayQRRequest.QrRequest createQR(String amount,String mid) {
return createQR(amount, String.valueOf(System.currentTimeMillis()),mid);
}
public KPayQRRequest.QrRequest createQR(String amount, String time,String mid) {
String merchOrderId = "NEX"+SystemParamsOperation.getInstance().getCurrentSerialNum()+generateRandomTwoChars();
String serialNum = TerminalUtil.getInstance().getSerialNo();
String nonceStr = generateNonceStr(); // Generate random nonce_str
Map<String, Object> bizContent = new HashMap<>();
bizContent.put("merch_order_id", merchOrderId);
bizContent.put("merch_code", mid);
bizContent.put("appid", "kp9b0794b349ae85b00c51e0677484c7");
bizContent.put("trade_type", "PAY_BY_QRCODE");
bizContent.put("total_amount", amount);
bizContent.put("title", "testing");
// bizContent.put("operator_id", serialNum);
bizContent.put("timeout_express", "100m");
bizContent.put("trans_currency", "MMK");
bizContent.put("callback_info", "callback");
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("timestamp", time);
requestMap.put("notify_url", "http://test.com/payment/notify");
requestMap.put("nonce_str", nonceStr); // Use random nonce_str
requestMap.put("sign_type", "SHA256");
requestMap.put("method", "kbz.payment.precreate");
requestMap.put("version", "1.0");
requestMap.put("biz_content", bizContent);
String sign = Sign.INSTANCE.generateSign(requestMap, appKey);
KPayQRRequest.QrRequest.RequestBody.BizContent biz = new KPayQRRequest.QrRequest.RequestBody.BizContent(
"kp9b0794b349ae85b00c51e0677484c7",
mid,
merchOrderId,
"PAY_BY_QRCODE",
"testing",
amount,
"MMK",
"100m",
"callback"
);
KPayQRRequest.QrRequest.RequestBody body = new KPayQRRequest.QrRequest.RequestBody(
time,
"http://test.com/payment/notify",
nonceStr, // Use random nonce_str
"kbz.payment.precreate",
"SHA256",
sign,
"1.0",
biz
);
KPayQRRequest.QrRequest qrRequest = new KPayQRRequest.QrRequest(body);
return qrRequest;
}
public KPayQRQueryRequest.QRQueryRequest getQrStatus(String merchOrderId, String mid) {
String currentTime = String.valueOf(System.currentTimeMillis());
String nonceStr = generateNonceStr(); // Generate random nonce_str
Map<String, Object> bizContentMap = new HashMap<>();
bizContentMap.put("merch_order_id", merchOrderId);
bizContentMap.put("merch_code", mid);
bizContentMap.put("appid", "kp9b0794b349ae85b00c51e0677484c7");
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("timestamp", currentTime);
requestMap.put("nonce_str", nonceStr); // Use random nonce_str
requestMap.put("method", "kbz.payment.queryorder");
requestMap.put("version", "3.0");
requestMap.put("biz_content", bizContentMap);
String sign = Sign.INSTANCE.generateSign(requestMap, appKey);
KPayQRQueryRequest.QRQueryRequest.Request.BizContent bizContent = new KPayQRQueryRequest.QRQueryRequest.Request.BizContent(
"kp9b0794b349ae85b00c51e0677484c7",
mid,
merchOrderId
);
KPayQRQueryRequest.QRQueryRequest.Request requestBody = new KPayQRQueryRequest.QRQueryRequest.Request(
currentTime,
nonceStr, // Use random nonce_str
"kbz.payment.queryorder",
"SHA256",
sign,
"3.0",
bizContent
);
KPayQRQueryRequest.QRQueryRequest request = new KPayQRQueryRequest.QRQueryRequest(requestBody);
return request;
}
@Inject
public KPayViewModel(Repository repository) {
this.repository = repository;
}
private TradeData tradeData;
private PayDetail payDetail;
public void setTradeData(TradeData tradeData){
this.tradeData = tradeData;
}
public TradeData getTradeData() {
return tradeData;
}
public void setPayDetail(PayDetail payDetail) {
this.payDetail = payDetail;
}
public PayDetail getPayDetail() { return payDetail; }
public SingleLiveEvent<String> invalidAmountMsg = new SingleLiveEvent<>();
public MutableLiveData<Integer> isScanned = new MutableLiveData<>(0);
public Flowable<PayDetail> searchPayDetailByRefNum(String refNum) {
return repository.searchPayDetailByRefNum(refNum);
}
public Maybe<PayDetail> searchPayByRefNum(String refNum) {
return repository.searchPayByRefNum(refNum);
}
public Completable updateUnfinishedQrTrans(String appName,String transId,String refNum) {
return repository.updateUnFinishedQRTrans(appName,transId,refNum);
}
public void insertPayDetail(PayDetail payDetail) {
repository.insertPayDetail(payDetail);
}
public Completable insertPay(PayDetail payDetail) {
return repository.insertPay(payDetail);
}
public Observable<KPayQRResponse.QrResponse> generateQR(KPayQRRequest.QrRequest request) {
return repository.qrGenerate(request);
}
public Observable<DemoQRResponse> generateQRDemo(DemoQRRequest demoQRRequest) {
return repository.demoQRGenerate(demoQRRequest);
}
public Observable<KPayQRQueryRequest.QRQueryResponse> checkStatus(KPayQRQueryRequest.QRQueryRequest request) {
return repository.qrStatusCheck(request);
}
public Observable<DemoQRStatusResponse> demoQrCheckStatus(DemoQRStatusRequest demoStatusRequest) {
return repository.demoQRCheckStatus(demoStatusRequest);
}
public Observable<KPayRefund.RefundResponse> kPayRefund(KPayRefund.RefundRequest refundRequest) {
return repository.kPayRefund(refundRequest);
}
}

View File

@ -0,0 +1,269 @@
package com.utsmm.kbz.ui.kpay;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.github.gcacace.signaturepad.BR;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.DemoQRRequest;
import com.utsmyanmar.baselib.network.model.KPayQRRequest;
import com.utsmyanmar.baselib.network.model.WaveQRRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.ecr.ECRHelper;
import com.utsmyanmar.ecr.ECRProcess;
import com.utsmyanmar.ecr.data.model.TransactionsResp;
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 com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.util.Locale;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class QRConnectingFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback {
private static final String TAG = QRConnectingFragment.class.getSimpleName();
private SharedViewModel sharedViewModel;
private KPayViewModel KPayViewModel;
CompositeDisposable authDisposable = new CompositeDisposable();
CompositeDisposable generateQRDisposable = new CompositeDisposable();
private String terminalId = "";
private String merchantId = "";
private TradeData tradeData;
private PayDetail payDetail;
private String refLabel;
private int routeId;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
KPayViewModel = getFragmentScopeViewModel(KPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_qr_connecting, BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.kPayViewModel, KPayViewModel);
}
@Override
protected int currentId() {
return R.id.QRConnectingFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_empty));
delayFunctionCall(this::requestAuth);
}
@Override
public void onDestroyView() {
super.onDestroyView();
authDisposable.dispose();
generateQRDisposable.dispose();
}
private void initSetup() {
terminalId = TransactionUtil.getInstance().getQRTerminalId();
merchantId = TransactionUtil.getInstance().getQRMerchantId();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initData();
}
private void initData() {
payDetail = TransactionUtil.getInstance().initWalletTransaction(TransactionsType.MMQR);
String amount = sharedViewModel.amount.getValue();
payDetail.setAmount(POSUtil.getInstance().convertAmount(amount));
}
private void checkMMQR(boolean isMmQR) {
if(isMmQR) {
LogUtil.d(TAG,"<<<< MMQR Merchant >>>>");
sharedViewModel.isMMPay.setValue(0);
sharedViewModel.isWavePay.setValue(8);
} else {
LogUtil.d(TAG,"<<<< NON-MMQR Merchant >>>>");
sharedViewModel.isMMPay.setValue(8);
sharedViewModel.isWavePay.setValue(0);
}
}
private void requestAuth() {
initSetup();
generateQR();
}
private void generateQR() {
// String amount = String.format(Locale.getDefault(), "%.2f", payDetail.getAmount()/100.0);
String amount = String.format(Locale.getDefault(), "%d", (int)(payDetail.getAmount()/100.0));
KPayQRRequest.QrRequest kPayQRRequest = KPayViewModel.createQR(amount, merchantId);
Disposable qrDi = KPayViewModel.generateQR(kPayQRRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> {
if(response.getResponse().getQrCode() != null && !response.getResponse().getQrCode().isEmpty()) {
LogUtil.d(TAG,response.getResponse().getQrCode());
if(response.getResponse().getQrCode() == null || response.getResponse().getQrCode().isEmpty()) {
endAction();
}
refLabel = response.getResponse().getMerchOrderId();
sharedViewModel.qrData.setValue(response.getResponse().getQrCode());
sharedViewModel.qrRefNum.setValue(refLabel);
LogUtil.d(TAG,"Ref Label :"+refLabel);
payDetail.setPayQRCode(response.getResponse().getQrCode());
payDetail.setQrReferNo(refLabel);
payDetail.setQrTransStatus(2);
payDetail.setReferNo(refLabel);
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
delayFunctionCall(this::ecrAction);
}
}
KPayViewModel.setPayDetail(payDetail);
// waveViewModel.setTradeData(tradeData);
delayFunctionCall(()->{
routeId = R.id.action_QRConnectingFragment_to_QRTransactionFragment;
safeNavigateToRouteId();
});
} else {
dismissLoadingDialog();
// showDeclineDialog("Failed to generate QR!\n"+response.getMessage());
endAction();
}
},
Throwable -> {
Throwable.printStackTrace();
dismissLoadingDialog();
// showDeclineDialog("Failed to generate QR!\nMessage - "+Throwable.getMessage());
endAction();
},
() -> {
LogUtil.d(TAG,"On Complete!");
}
);
generateQRDisposable.add(qrDi);
}
private void endAction() {
showDeclineDialog("Failed to generate QR!\n Communication Error! ");
ecrActionCancel(getResourceString(R.string.txt_qr_generate_failed));
navigateToMain();
}
private void ecrAction() {
LogUtil.d(TAG,"ECR Response :"+getECRResponseMessage());
ECRHelper.INSTANCE.send(getECRResponseMessage().getBytes());
ECRHelper.INSTANCE.setOnBindSuccess(() -> {
LogUtil.d(TAG, "Send Success!");
return null;
});
}
private void navigateToMain() {
routeId = R.id.action_QRConnectingFragment_to_nav_main;
safeNavigateToRouteId();
}
private void finishECR() {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans));
sharedViewModel.isEcrFinished.postValue(true);
}
private void ecrActionCancel(String msg) {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg);
sharedViewModel.isEcrFinished.postValue(true);
}
}
}
private String getECRResponseMessage() {
sharedViewModel.payDetail.setValue(payDetail);
TransactionsResp resp = CoreUtils.getInstance(sharedViewModel).generateResponseMsg();
return ECRProcess.INSTANCE.generateECRResponse(resp);
}
@Override
public void onBackPress() {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
finishECR();
}
}
popBackStack();
}
}

View File

@ -0,0 +1,114 @@
package com.utsmm.kbz.ui.kpay;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.github.gcacace.signaturepad.BR;
import com.nexgo.oaf.apiv3.SdkResult;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.DialogCallback;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.print.PrintHelper;
import com.utsmyanmar.paylibs.utils.PrintStatus;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
public class QRInquiryResultFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
private static final int resultTimeOut = 1;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_qr_inquiry_result, BR.sharedViewModel,sharedViewModel);
}
@Override
protected int currentId() {
return R.id.QRInquiryResultFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return R.id.action_QRInquiryResultFragment_to_nav_main;
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_qr_pay));
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
sharedViewModel.setPrintStatus(PrintStatus.FIRST_PRINT);
startPrintProcess();
setupTimeout(resultTimeOut, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
}
@Override
public void onFinish() {
navigateToMainScreen();
}
});
}
private void isCardInside() {
isCardInserted(() -> delayFunctionCall(this::navigateToMainScreen));
}
private void navigateToMainScreen() {
safeNavigateToRouteId();
}
private void startPrintProcess() {
if (PrintHelper.getInstance().paperRollStatus() == SdkResult.Printer_PaperLack) {
cancelTimeout();
showPrinterAlertDialog(getResourceString(R.string.txt_paper_roll_not_ready), new DialogCallback() {
@Override
public void onClickCancel() {
dismissPrinterAlertDialog();
isCardInside();
}
@Override
public void onClickRetry() {
dismissPrinterAlertDialog();
startPrintProcess();
}
});
if(SystemParamsOperation.getInstance().isAlertSound()) {
startSound(getResourceString(R.string.txt_audio_printer_alert));
}
} else if (PrintHelper.getInstance().paperRollStatus() == SdkResult.Success) {
sharedViewModel.startPrintProcess();
}
}
}

View File

@ -0,0 +1,331 @@
package com.utsmm.kbz.ui.kpay;
import android.os.Bundle;
import android.text.InputFilter;
import android.view.View;
import android.widget.EditText;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.KPayRefund;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.system.SystemDateTime;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.util.DecimalDigitsInputFilter;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmm.kbz.util.ecr.CoreUtils;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class QRRefundFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
private KPayViewModel KPayViewModel;
private int routeId;
private TradeData tradeData;
private PayDetail payDetail;
// UI Elements
private RadioGroup radioGroupRefundType;
private RadioButton radioOriginal, radioPartial;
private EditText etReferenceNo, etOriginalAmount, etRefundAmount, etRefundReason;
private LinearLayout originalAmountLayout, refundAmountLayout;
private boolean isPartialRefund = false;
CompositeDisposable refundDisposable = new CompositeDisposable();
CompositeDisposable retrieveUpdateDisposable = new CompositeDisposable();
private static final String TAG = QRRefundFragment.class.getSimpleName();
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
KPayViewModel = getFragmentScopeViewModel(KPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_qr_refund_screen, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.kPayViewModel, KPayViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.QRRefundFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon("KPay Refund");
KPayViewModel.invalidAmountMsg.setValue("");
}
@Override
public void onDestroyView() {
super.onDestroyView();
refundDisposable.dispose();
retrieveUpdateDisposable.dispose();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initViews();
initData();
setupRadioGroupListener();
}
private void initViews() {
radioGroupRefundType = mBinding.getRoot().findViewById(R.id.radio_group_refund_type);
radioOriginal = mBinding.getRoot().findViewById(R.id.radio_original);
radioPartial = mBinding.getRoot().findViewById(R.id.radio_partial);
etReferenceNo = mBinding.getRoot().findViewById(R.id.et_reference_no);
etOriginalAmount = mBinding.getRoot().findViewById(R.id.et_original_amount);
etRefundAmount = mBinding.getRoot().findViewById(R.id.et_refund_amount);
etRefundReason = mBinding.getRoot().findViewById(R.id.et_refund_reason);
originalAmountLayout = mBinding.getRoot().findViewById(R.id.original_amount_layout);
refundAmountLayout = mBinding.getRoot().findViewById(R.id.refund_amount_layout);
// Set input filters for amount fields
etOriginalAmount.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(11, 2)});
etRefundAmount.setFilters(new InputFilter[]{new DecimalDigitsInputFilter(11, 2)});
}
private void initData() {
payDetail = TransactionUtil.getInstance().initWalletTransaction(TransactionsType.MMQR_REFUND);
payDetail.setInvoiceNo(SystemParamsOperation.getInstance().getIncrementInvoiceNum());
}
private void setupRadioGroupListener() {
radioGroupRefundType.setOnCheckedChangeListener((group, checkedId) -> {
if (checkedId == R.id.radio_partial) {
// Show both amount fields for partial refund
isPartialRefund = true;
originalAmountLayout.setVisibility(View.VISIBLE);
refundAmountLayout.setVisibility(View.VISIBLE);
} else {
// Hide amount fields for original refund
isPartialRefund = false;
originalAmountLayout.setVisibility(View.GONE);
refundAmountLayout.setVisibility(View.GONE);
}
});
}
private void processKPayRefund(String referenceNo, String refundAmount, String originalAmount, String reason) {
String merchantId = TransactionUtil.getInstance().getQRMerchantId();
// Generate unique refund request ID
String refundRequestId = referenceNo + "R";
showLoadingDialog("Processing refund...");
// Create KPay refund request
KPayRefund.RefundRequest refundRequest = KPayViewModel.createRefundRequest(
refundRequestId,
referenceNo,
merchantId,
refundAmount,
reason != null ? reason : "Refund request"
);
Disposable refundDi = KPayViewModel.kPayRefund(refundRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> {
dismissLoadingDialog();
handleRefundResponse(response, referenceNo);
},
throwable -> {
dismissLoadingDialog();
LogUtil.e(TAG, "Refund error: " + throwable.getMessage());
showDeclineDialog("Refund failed!\nCommunication Error!");
ecrActionCancel("Refund failed");
navigateToMain();
},
() -> LogUtil.d(TAG, "Refund request completed")
);
refundDisposable.add(refundDi);
}
private void handleRefundResponse(KPayRefund.RefundResponse response, String referenceNo) {
if (response != null && response.getResponse() != null && "REFUND_SUCCESS".equalsIgnoreCase(response.getResponse().getRefundStatus())) {
LogUtil.d(TAG, "Refund successful!");
String refundAmount = response.getResponse().getRefundAmount();
String dateTime = SystemDateTime.getTodayDateFormat() + " " + SystemDateTime.getTodayTimeFormat();
payDetail.setAmount(refundAmount == null ? 0 : POSUtil.getInstance().convertAmount(refundAmount));
payDetail.setOriginalTransDate(dateTime);
payDetail.setQrTransStatus(1);
payDetail.setQrReferNo(referenceNo);
payDetail.setReferNo(referenceNo);
payDetail.setIsCanceled(true);
retrievedUpdatePayDetail(referenceNo);
} else {
LogUtil.d(TAG, "Refund failed!");
payDetail.setQrTransStatus(-1);
payDetail.setQrReferNo(referenceNo);
payDetail.setReferNo(referenceNo);
String errorMsg = "Refund failed";
if (response != null && response.getResponse() != null && response.getResponse().getMsg() != null) {
errorMsg = response.getResponse().getMsg();
}
payDetail.setTradeResultDes(errorMsg);
sharedViewModel.payDetail.setValue(payDetail);
navigateToNext();
}
}
private void retrievedUpdatePayDetail(String refNum) {
LogUtil.d(TAG, "Trying to update Database!");
retrieveUpdateDisposable.add(KPayViewModel.searchPayByRefNum(refNum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(oldPay -> {
LogUtil.d(TAG, "Inside the subscribe!");
if (oldPay != null) {
oldPay.setIsCanceled(true);
payDetail.setQrTransId(oldPay.getQrTransId());
payDetail.setCustomerMobile(oldPay.getCustomerMobile());
sharedViewModel.updatePayDetail(oldPay);
}
updateData();
navigateToNext();
},
onError -> {
LogUtil.d(TAG, "On error Unable to retrieve PayDetail");
updateData();
navigateToNext();
},
() -> {
LogUtil.d(TAG, "No data found! navigating to Result Page!");
updateData();
navigateToNext();
}
));
}
private void updateData() {
KPayViewModel.insertPayDetail(payDetail);
sharedViewModel.payDetail.postValue(payDetail);
}
private void navigateToMain() {
routeId = R.id.action_QRRefundFragment_to_nav_main;
safeNavigateToRouteId();
}
private void navigateToNext() {
routeId = R.id.action_QRRefundFragment_to_transactionResultFragment;
safeNavigateToRouteId();
}
private void ecrActionCancel(String msg) {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg);
sharedViewModel.isEcrFinished.postValue(true);
}
}
}
public class ClickEvent {
public void onCancel() {
safePopBackStack();
}
public void onConfirm() {
KPayViewModel.invalidAmountMsg.setValue("");
String referenceNo = etReferenceNo.getText().toString().trim();
String refundReason = etRefundReason.getText().toString().trim();
// Validate reference number
if (referenceNo.isEmpty()) {
KPayViewModel.invalidAmountMsg.setValue("Enter reference number");
return;
}
if (isPartialRefund) {
// Partial refund validation
String originalAmountStr = etOriginalAmount.getText().toString().trim();
String refundAmountStr = etRefundAmount.getText().toString().trim();
if (originalAmountStr.isEmpty()) {
KPayViewModel.invalidAmountMsg.setValue("Enter original amount");
return;
}
if (refundAmountStr.isEmpty()) {
KPayViewModel.invalidAmountMsg.setValue("Enter refund amount");
return;
}
double originalAmount = Double.parseDouble(originalAmountStr);
double refundAmount = Double.parseDouble(refundAmountStr);
if (originalAmount <= 0) {
KPayViewModel.invalidAmountMsg.setValue("Enter valid original amount");
return;
}
if (refundAmount <= 0) {
KPayViewModel.invalidAmountMsg.setValue("Enter valid refund amount");
return;
}
if (refundAmount > originalAmount) {
KPayViewModel.invalidAmountMsg.setValue("Refund amount cannot exceed original amount");
return;
}
processKPayRefund(referenceNo, refundAmountStr, originalAmountStr, refundReason);
} else {
// Original amount refund - no amount validation needed
processKPayRefund(referenceNo, "0", String.valueOf( etOriginalAmount.getText().toString().trim()), refundReason);
}
}
}
}

View File

@ -0,0 +1,421 @@
package com.utsmm.kbz.ui.kpay;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.DemoQRStatusRequest;
import com.utsmyanmar.baselib.network.model.KPayQRQueryRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.ecr.ECRHelper;
import com.utsmyanmar.ecr.ECRProcess;
import com.utsmyanmar.ecr.data.model.TransactionsResp;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.R;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class QRTransactionFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback {
private static final String TAG = QRTransactionFragment.class.getSimpleName();
private SharedViewModel sharedViewModel;
private KPayViewModel kPayViewModel;
private String refLabel;
CompositeDisposable retrieveUpdateDisposable = new CompositeDisposable();
CompositeDisposable setUpTimerDisposable = new CompositeDisposable();
private PayDetail payDetail;
String terminalId = "";
String merchantId = "";
private int intervalInSec = 15;
private int totalCount = 4;
private int count = 0;
// @Inject
// QRUtils qrUtils;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
kPayViewModel = getFragmentScopeViewModel(KPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_qr_transaction, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.kPayViewModel, kPayViewModel);
}
@Override
protected int currentId() {
return R.id.QRTransactionFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return R.id.action_QRTransactionFragment_to_transactionResultFragment;
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getResourceString(R.string.title_qr_scan));
// disableNavigationBar();
count = 0;
sharedViewModel.mmqrLoading.setValue(8);
}
@Override
public void onPause() {
super.onPause();
// enableNavigationBar();
sharedViewModel.mmqrLoading.setValue(8);
}
private void initSetup() {
// terminalId = SystemParamsOperation.getInstance().getSecHostTerminalId();
// merchantId = SystemParamsOperation.getInstance().getSecHostMerchantId();
terminalId = TransactionUtil.getInstance().getQRTerminalId();
merchantId = TransactionUtil.getInstance().getQRMerchantId();
refLabel = sharedViewModel.qrRefNum.getValue();
// tradeData = waveViewModel.getTradeData();
// payDetail = tradeData.getPayDetail();
payDetail = kPayViewModel.getPayDetail();
payDetail.setInvoiceNo(SystemParamsOperation.getInstance().getIncrementInvoiceNum());
sharedViewModel.insertPayDetail(payDetail);
}
private void calculateIntervalAndCount() {
String data = SystemParamsOperation.getInstance().getWaveIntervalTime();
if (data == null) {
data = "15-60";
}
Pattern pattern = Pattern.compile("^(\\d+)-(\\d+)$"); // Match digits-hyphen-digits
Matcher matcher = pattern.matcher(data);
if (matcher.matches()) {
int interval = Integer.parseInt(Objects.requireNonNull(matcher.group(1)));
int waitingTime = Integer.parseInt(Objects.requireNonNull(matcher.group(2)));
intervalInSec = interval;
totalCount = waitingTime / interval;
} else {
LogUtil.d(TAG, "Invalid input format. Expected format: digits-digits");
}
}
private void finishECR() {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getResourceString(R.string.txt_cancel_trans));
sharedViewModel.isEcrFinished.postValue(true);
}
private void ecrActionCancel(String msg) {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
sharedViewModel.isEcr.postValue(false);
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(msg);
sharedViewModel.isEcrFinished.postValue(true);
}
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initSetup();
calculateIntervalAndCount();
setUpTimeout();
setUpCountDown();
}
private void setUpCountDown() {
setupTimeout(10, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
sharedViewModel.countDownTxt.setValue((trickTime / 1000)+"");
}
@Override
public void onFinish() {
sharedViewModel.countDownTxt.setValue("Connecting to host");
sharedViewModel.mmqrLoading.setValue(0);
// disableNavigationBar();
setToolBarTitleWithoutBackIcon(getResourceString(R.string.title_qr_scan));
}
});
}
private void setUpTimeout() {
setUpTimer();
}
@Override
public void onDestroyView() {
super.onDestroyView();
setUpTimerDisposable.dispose();
retrieveUpdateDisposable.dispose();
// qrUtils.disposeStatusCheck();
}
private void setUpStatusCheck() {
// qrUtils.startStatusCheck(refLabel, merchantId, new QRUtils.QRStatusCheckCallback() {
// @Override
// public void onSuccess(MMQRStatusResponse response) {
// payDetail.setCustomerMobile(response.getScannerChannel());
// payDetail.setQrReferNo(refLabel);
// payDetail.setQrTransId(response.getTransactionID());
// payDetail.setReferNo(refLabel);
// payDetail.setApprovalCode(response.getTransactionID());
// payDetail.setQrTransStatus(1);
//
// retrievedUpdatePayDetail(refLabel, payDetail,false);
// }
//
// @Override
// public void onFailure(String trnxId) {
//
// payDetail.setQrReferNo(refLabel);
// payDetail.setQrTransId(trnxId);
// payDetail.setReferNo(refLabel);
// payDetail.setApprovalCode(trnxId);
// payDetail.setQrTransStatus(-1);
//
// retrievedUpdatePayDetail(refLabel, payDetail,true);
// }
//
// @Override
// public void onReachRetryCount() {
// payDetail.setQrTransStatus(2);
// delayFunctionCall(() -> {
// sharedViewModel.payDetail.postValue(payDetail);
//
// safeRouteTo(currentId, routeId, hostId);
// });
// }
//
// @Override
// public void onNetworkError() {
// payDetail.setQrTransStatus(3);
// retrievedUpdatePayDetail(refLabel, payDetail,false);
// }
// });
}
private boolean checkResult(KPayQRQueryRequest.QRQueryResponse response) {
return response.getResponse().getResult().equals("SUCCESS");
}
@SuppressLint("CheckResult")
private void setUpTimer() {
Disposable setUpDi = Observable.interval(intervalInSec, TimeUnit.SECONDS) // Emit an item every 10 seconds
.take(totalCount) // Take only 3 emissions
.flatMap(tick -> {
// Make the API call here using Retrofit
// WaveStatusRequest request = new WaveStatusRequest(refLabel, merchantId);
// DemoQRStatusRequest request = new DemoQRStatusRequest(refLabel, merchantId);
KPayQRQueryRequest.QRQueryRequest request = kPayViewModel.getQrStatus(refLabel,merchantId);
return kPayViewModel.checkStatus(request)
.takeUntil(response -> response.checkResponse() == true);
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(response -> {
LogUtil.d(TAG, "response status:" + response.getResponse().getResult());
// LogUtil.d(TAG, "response trans id:" + response.get());
// LogUtil.d(TAG, "response ref id:" + response.getReferenceId());
// LogUtil.d(TAG, "response trans date time:" + response.getTransactionDateTime());
count++;
try {
if (response.getResponse().getTradeStatus().equals("PAY_SUCCESS") && response.getResponse().getResult().equals("SUCCESS")) {
/*
* trans is success !*/
// String transStatus = response.getTransactionStatus();
// String transTime = response.getResponse().;
payDetail.setCustomerMobile("KBZ PAY");
payDetail.setQrReferNo(refLabel);
payDetail.setQrTransId(response.getResponse().getMmOrderId());
payDetail.setReferNo(refLabel);
payDetail.setApprovalCode(response.getResponse().getMmOrderId());
payDetail.setQrTransStatus(1);
payDetail.setOriginalTransDate(response.getResponse().getPaySuccessTime());
retrievedUpdatePayDetail(refLabel, payDetail,false);
return;
}
if (count == totalCount) {
if(payDetail.getQrTransStatus() != -1) {
payDetail.setQrTransStatus(2);
}
sharedViewModel.payDetail.postValue(payDetail);
safeNavigateToRouteId();
}
} catch (Exception e) {
LogUtil.d(TAG, "On Exception::");
e.printStackTrace();
if (count == totalCount) {
if(payDetail.getQrTransStatus() != -1) {
payDetail.setQrTransStatus(2);
}
sharedViewModel.payDetail.postValue(payDetail);
safeNavigateToRouteId();
}
}
}, Throwable -> {
LogUtil.d(TAG, "On Throwable::");
Throwable.printStackTrace();
count++;
if (count == totalCount) {
if(payDetail.getQrTransStatus() != -1) {
payDetail.setQrTransStatus(3);
}
retrievedUpdatePayDetail(refLabel, payDetail,false);
return;
}
setUpTimer();
});
setUpTimerDisposable.add(setUpDi);
}
private void retrievedUpdatePayDetail(String refNum, PayDetail payDetail,boolean isNeedRetry) {
retrieveUpdateDisposable.add(kPayViewModel.searchPayDetailByRefNum(refNum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(oldPay -> {
if (oldPay != null)
payDetail.setPID(oldPay.getPID());
sharedViewModel.updatePayDetail(payDetail);
sharedViewModel.payDetail.postValue(payDetail);
if(isNeedRetry) {
retrieveUpdateDisposable.dispose();
return;
}
safeNavigateToRouteId();
},
Throwable -> Log.e(TAG, "Unable to retrieve PayDetail", Throwable)));
}
@Override
public void onBackPress() {
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
finishECR();
}
}
// nav main or pop back?
popBackStack();
}
private String getECRResponseMessage() {
sharedViewModel.payDetail.setValue(payDetail);
TransactionsResp resp = CoreUtils.getInstance(sharedViewModel).generateResponseMsg();
return ECRProcess.INSTANCE.generateECRResponse(resp);
}
private void ecrAction() {
LogUtil.d(TAG, "ECR Response :" + getECRResponseMessage());
ECRHelper.INSTANCE.send(getECRResponseMessage().getBytes());
ECRHelper.INSTANCE.setOnBindSuccess(() -> {
LogUtil.d(TAG, "Send Success!");
return null;
});
}
}

View File

@ -0,0 +1,145 @@
package com.utsmm.kbz.ui.kpay;
import com.utsmyanmar.baselib.network.model.MMQRStatusResponse;
import com.utsmyanmar.baselib.network.model.WaveStatusRequest;
import com.utsmyanmar.baselib.repo.Repository;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class QRUtils {
private static final String TAG = QRUtils.class.getSimpleName();
private final Repository repository;
private int intervalInSec = 15;
private int totalCount = 4;
private int count = 0;
private boolean isFailure = false;
CompositeDisposable setUpTimerDisposable = new CompositeDisposable();
// private static QRUtils instance;
//
// public static QRUtils getInstance() {
// if(instance == null) {
// instance = new QRUtils();
// }
// return instance;
// }
@Inject
public QRUtils(Repository repository) {
this.repository = repository;
isFailure = false;
}
interface QRStatusCheckCallback {
void onSuccess(MMQRStatusResponse response);
void onFailure(String trnxId);
void onReachRetryCount();
void onNetworkError();
}
public void disposeStatusCheck() {
setUpTimerDisposable.dispose();
}
// public void startStatusCheck(String refLabel,String merchantId,QRStatusCheckCallback callback) {
// Disposable setUpDi = Observable.interval(intervalInSec, TimeUnit.SECONDS) // Emit an item every 10 seconds
// .take(totalCount) // Take only 3 emissions
// .flatMap(tick -> {
// // Make the API call here using Retrofit
// WaveStatusRequest request = new WaveStatusRequest(refLabel, merchantId);
// return repository.checkStatus(request)
// .takeUntil(response -> response.checkResponse() == true);
// })
// .subscribe(response -> {
//
// LogUtil.d(TAG, "response status:" + response.getTransactionStatus());
// LogUtil.d(TAG, "response trans id:" + response.getTransactionID());
// LogUtil.d(TAG, "response ref id:" + response.getReferenceId());
// LogUtil.d(TAG, "response trans date time:" + response.getTransactionDateTime());
//
// count++;
//
// try {
//
// if (response.getTransactionStatus().equals("payment credit success") && response.getTransactionID() != null) {
// /*
// * trans is success !*/
// String transStatus = response.getTransactionStatus();
// String transTime = response.getTransactionDateTime();
//
// callback.onSuccess(response);
//
// return;
// } else if(response.getTransactionStatus().equals("payment credit failure") && response.getTransactionID() != null) {
// String transStatus = response.getTransactionStatus();
// String transTime = response.getTransactionDateTime();
//
// isFailure = true;
//
// callback.onFailure(response.getTransactionID());
//
//// return;
// }
//
//
// if (count == totalCount) {
// if(!isFailure) {
// callback.onReachRetryCount();
// }
//
// }
//
// } catch (Exception e) {
// LogUtil.d(TAG, "On Exception::");
// e.printStackTrace();
// if (count == totalCount) {
//
// if(!isFailure) {
// callback.onReachRetryCount();
// }
//
// }
// }
//
// }, Throwable -> {
// LogUtil.d(TAG, "On Throwable::");
// Throwable.printStackTrace();
//
// count++;
//
// if (count == totalCount) {
//
// if(!isFailure) {
// callback.onNetworkError();
// }
//
// return;
// }
//
// startStatusCheck(refLabel,merchantId,callback);
//
// });
//
// setUpTimerDisposable.add(setUpDi);
// }
}

View File

@ -0,0 +1,167 @@
package com.utsmm.kbz.ui.kpay;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.sunmi.pay.hardware.aidlv2.bean.EMVCandidateV2;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.ui.ListDialog;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.Constant;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.MainViewModel;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
public class TestFragment extends DataBindingFragment {
private static final String TAG = TestFragment.class.getSimpleName();
private SharedViewModel sharedViewModel;
private MainViewModel mainViewModel;
private KPayViewModel KPayViewModel;
CompositeDisposable retrieveUpdateDisposable = new CompositeDisposable();
private ListDialog mListDialog;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
mainViewModel = getFragmentScopeViewModel(MainViewModel.class);
KPayViewModel = getFragmentScopeViewModel(KPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_test, BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.mainViewModel,mainViewModel);
}
@Override
protected int currentId() {
return R.id.nav_test;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return 0;
}
private String[] getCandidateNames(List<EMVCandidateV2> candiList) {
if (candiList == null || candiList.size() == 0) return new String[0];
String[] result = new String[candiList.size()];
for (int i = 0; i < candiList.size(); i++) {
EMVCandidateV2 candi = candiList.get(i);
String name = candi.appPreName;
name = TextUtils.isEmpty(name) ? candi.appLabel : name;
name = TextUtils.isEmpty(name) ? candi.appName : name;
name = TextUtils.isEmpty(name) ? "" : name;
result[i] = name;
LogUtil.e(Constant.TAG, "EMVCandidateV2: " + name);
}
return result;
}
private void showCandiListDialog(String[] list) {
if (mListDialog == null) {
mListDialog = new ListDialog(requireContext());
mListDialog.setTitleText(R.string.index_select_app);
mListDialog.setCancelable(true);
mListDialog.setCanceledOnTouchOutside(true);
}
List<String> tempList = new ArrayList<>(Arrays.asList(list));
mListDialog.setData(tempList);
mListDialog.setOnItemClickListener(
position -> LogUtil.d(TAG,"Selected : "+position)
);
try {
mListDialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
String[] candidateList = {"Credit","Debit","Qursa"};
showCandiListDialog(candidateList);
// retrievedUpdatePayDetail("100000018432");
// String sitData = "00020101021226500015com.mmqrpay.www01157100010100125910208100136975204701153031045406500.005802MM5909MYA HOTEL6006Hlaing62280108YU239850051210000001759564180002MY0108မြဟိုတယ်63045D6B";
//
// String uatData = "00020101021226500015com.mmqrpay.www01152235110100044800208100202575204541153031045406400.005802MM5911Pae Po Shop6008Thanlyin62280108YU239850051210000000781064260002MY0105ပဲပို0207သန်လျင်6304ECC7";
//
// String sitData2 = "00020101021226500015com.mmqrpay.www01152235110100046460208100214695204565153031045406900.005802MM5907Novotel6009Sanchaung62280108YU239850051210000000850864340002MY0109နိုဗိုတယ်0211စမ်းချောင်း630422D7";
//
// String sitData3 = "00020101021226500015com.mmqrpay.www01152235110100046460208100214695204565153031045406900.005802MM5907Novotel6009Sanchaung62280108YU239850051210000000850864340002MY0109နိုဗိုတယ်0211စမ်းချောင်း630422D7533";
// String sitData4 = "00020101021226500015com.mmqrpay.www01152235110100046460208100214695204565153031045406900.005802MM5907Novotel6009Sanchaung62280108YU239850051210000000850864340002MY0109နိုဗိုတယ်0211စမ်းချောင်း630422D75331D";
// String sitData5 = "00020101021226500015com.mmqrpay.www01152235110100046460208100214695204565153031045406900.005802MM5907Novotel6009Sanchaung62280108YU239850051210000000850864340002MY0109နိုဗိုတယ်0211စမ်းချောင်း630422D75331DDD$$$$@@#$";
//
// String test = "00020101021226500015com.mmqrpay.www01152235110100046460208100214695204565153031045406900";
// mainViewModel.qrData.setValue(sitData2);
//
// int width = 220;
// int height = 220;
// String data = "https://google.com";
// Bitmap logo = QRCodeGenerator.getBitmapFromVectorDrawable(imageView.getContext(),R.drawable.iv_wave_violet);
// if(logo != null) {
// LogUtil.d(TAG,"logo is not null!!");
// } else {
// LogUtil.d(TAG,"logo is null!!");
// }
int size = getResources().getDimensionPixelSize(R.dimen.qr_code_size);
// Bitmap qrCodeBitmap = QRCodeGenerator.generateQRCode(data, size, logo);
//
// imageView.setImageBitmap(qrCodeBitmap);
}
private void retrievedUpdatePayDetail(String refNum) {
LogUtil.d(TAG,"Trying to update Database!");
retrieveUpdateDisposable.add(KPayViewModel.searchPayByRefNum(refNum)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(oldPay -> {
LogUtil.d(TAG,"Inside the subscribe!");
if (oldPay != null) {
LogUtil.d(TAG,"Pay Detail not null");
}
LogUtil.d(TAG,"End of line reached..");
},
onError -> {
LogUtil.d(TAG,"On error Unable to retrieve PayDetail");
},() -> {
LogUtil.d(TAG, "Data not found, onComplete triggered.");
}));
}
}

Some files were not shown because too many files have changed in this diff Show More