Compare commits

..

205 Commits

Author SHA1 Message Date
MooN
eed5980cfa change printer_disabled to printer_enabled bez of user confusing 2026-02-04 11:21:49 +06:30
MooN
8482e4145d Re-imp for auto print after transaction 2026-02-04 10:59:05 +06:30
MooN
cb5177fa38 material lib for time picker 2026-02-03 22:32:03 +06:30
MooN
02629279cb button fix 2026-02-03 22:31:42 +06:30
MooN
caf656be60 timePicker added 2026-02-03 22:21:15 +06:30
MooN
7346bae086 mpu receipt fixed 2026-01-29 14:49:21 +06:30
MooN
77d1050021 Update RefundCertificateManager.java 2026-01-29 13:39:59 +06:30
MooN
f6067f8de6 host config address fix 2026-01-29 13:29:50 +06:30
MooN
3c77d4d9c7 changed to local server 2026-01-29 10:48:34 +06:30
MooN
37b1538e1c Merge branch 'refund_fix' into auto_print_disable 2026-01-28 16:22:23 +06:30
MooN
95ec5993b5 Update SettlementTransactionFragment.java 2026-01-28 11:08:44 +06:30
MooN
d89ce9771f fix 2026-01-26 15:11:29 +06:30
MooN
850bc21a9f disable / enable void in home screen 2026-01-26 12:19:19 +06:30
MooN
2c98727f2e Transactions buttons show / hide with config 2026-01-26 12:01:58 +06:30
MooN
fc8349ad2d re-unbind visible on hostConfig 2026-01-26 10:43:27 +06:30
MooN
0ddd5f269c Update BaseXPrint.java 2026-01-26 10:42:53 +06:30
MooN
d9b9c7cc80 Update network_security_config.xml 2026-01-26 10:42:52 +06:30
MooN
e6878a3d27 printer disable function 2026-01-26 10:42:49 +06:30
MooN
40c4ba2d25 Update NetworkModule.java 2026-01-26 10:42:48 +06:30
MooN
547c04e0ca re-unbind visible on hostConfig 2026-01-23 12:10:20 +06:30
MooN
4b10de477d uat url changed 2026-01-23 11:27:17 +06:30
MooN
f33f3463a8 Update BaseXPrint.java 2026-01-23 10:54:39 +06:30
MooN
133593a4d7 Update network_security_config.xml 2026-01-23 10:28:53 +06:30
MooN
2fedb6cee2 printer disable function 2026-01-23 10:28:10 +06:30
MooN
84f0620481 Update NetworkModule.java 2026-01-22 20:04:27 +06:30
MooN
b2a92f8cf8 changed to local server 2026-01-22 13:47:44 +06:30
67fc55800a Fixed Bin List issues 2026-01-21 19:33:57 +07:00
8e93e61eb5 fixed crashing on contactless 2026-01-20 15:31:25 +07:00
16b89ec19e fixed crashing on co-badge card. 2026-01-20 14:51:17 +07:00
4d30d0134c added bin list and its features 2026-01-19 23:46:55 +07:00
e4f706f24f Merge remote-tracking branch 'origin/merge_latest_SIT' into merge_latest_SIT 2026-01-18 23:05:46 +07:00
c2ec55e27f removed cvv at manual entry/ fixed settlement 0 transaction 2026-01-18 23:05:37 +07:00
MooN
bfba551b65 re-changed to local server 2026-01-18 11:21:03 +06:30
MooN
22ddf9284c Merge branch 'production_1.0' into merge_latest_SIT 2026-01-18 11:14:06 +06:30
MooN
36f5d521cd Update ReprintAnyTransactionFragment.java 2026-01-16 01:48:54 +06:30
MooN
3a14c574a8 Create release_key.jks 2026-01-16 01:28:59 +06:30
MooN
c495a29b06 temp card settlement fix 2026-01-16 01:28:47 +06:30
MooN
ce32ed2327 INV NO to TRACE NO 2026-01-15 23:57:31 +06:30
MooN
0ad0bc17b7 keyboard auto hide and search by trace no fix 2026-01-15 23:57:04 +06:30
MooN
fe97613f9b inv num to trc num in qr 2026-01-15 23:56:26 +06:30
MooN
e4ea98f6e6 Update .gitignore 2026-01-15 20:11:06 +06:30
MooN
042fe6307e log clean 2026-01-15 20:11:00 +06:30
MooN
98c94ec2d3 refund url 2026-01-14 11:45:03 +06:30
MooN
58118a2fb5 production ready 2026-01-13 23:34:12 +06:30
c9dd1b93f7 optimized refund 2026-01-13 14:57:32 +06:30
MooN
5b749073d0 update rules for printer crash 2026-01-13 11:09:55 +06:30
398a0d7986 optimized proguard rules 2026-01-12 23:14:22 +07:00
MooN
89466f8209 latest 2026-01-12 22:10:15 +06:30
720b3ddccb optimized refund 2026-01-12 14:47:20 +07:00
MooN
b4ecd40b46 uat url changed 2026-01-11 19:25:11 +06:30
MooN
0f7b57e516 Update .gitignore 2026-01-11 19:23:35 +06:30
13617eead1 fixed DE55 length 2026-01-10 16:16:43 +07:00
25ba7022da changed 9F41 len 03 to 04 2026-01-10 13:05:53 +07:00
280d8f154d removed extra 1 byte for DE55 2026-01-10 12:21:57 +07:00
ca9a4a0485 removed 9F53 tag 2026-01-10 11:28:05 +07:00
452f0beb97 fixed ISO packet format for DE55 2026-01-09 17:35:37 +07:00
MooN
6bb3ab45c1 grand total in qr settlement 2026-01-09 16:01:14 +06:30
MooN
f071f03dd2 receipt design change 2026-01-09 15:58:43 +06:30
MooN
654e7ddc7e receipt design change 2026-01-09 15:56:13 +06:30
MooN
3e342a71ca Update build.gradle 2026-01-09 15:38:52 +06:30
MooN
c5fb59473f Update QRRefundDetailFragment.java 2026-01-09 15:22:56 +06:30
17ff039cec need to check conflict at print functions 2026-01-09 15:44:19 +07:00
37a3fb27bc Merge remote-tracking branch 'origin/merge_latest_SIT' into merge_latest_SIT
# Conflicts:
#	paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/BaseXPrint.java
2026-01-09 15:05:14 +07:00
bf3159361a card settlement/ manual entry optimized 2026-01-09 15:02:31 +07:00
MooN
0faaf36fde alert fix for refund 2026-01-08 16:18:39 +06:30
MooN
ccebba6ba7 added Grand total in Settlement 2026-01-08 12:47:07 +06:30
MooN
00bd4c417e refund fail amount wrong fixed 2026-01-06 17:45:54 +06:30
MooN
adbd0724af SIM INTERNET FIX 2026-01-05 20:46:37 +06:30
MooN
48581e1291 receipt design change 2026-01-05 20:46:18 +06:30
MooN
8cb901d522 font change 2025-12-31 15:30:19 +06:30
MooN
8cac361ce0 some fix for detail report 2025-12-30 13:08:03 +06:30
MooN
bd13d50848 Merge branch 'merge_latest_SIT' of https://hub.utsmyanmar.com/Kyaw_Min_Khant/KBZ-POS into merge_latest_SIT 2025-12-30 10:46:50 +06:30
MooN
1f1eaca712 date time in detail report 2025-12-30 10:46:47 +06:30
14fe578bce Added QR Last Settlement - final 2025-12-30 03:09:33 +07:00
MooN
4c77b376f0 address fix 2025-12-29 11:10:06 +06:30
MooN
6a4ee61066 Update EReceiptUtil.java 2025-12-29 02:31:40 +06:30
MooN
7276f8c572 settlement QR setup 2025-12-29 02:19:58 +06:30
MooN
c6c5dd39e4 Update RefundCertificateManager.java 2025-12-29 01:25:40 +06:30
MooN
cd7cfa2a7d refund cached certificate fixed 2025-12-29 01:03:47 +06:30
MooN
062533662f update refund certificate download logic 2025-12-28 13:42:24 +06:30
e1dacaadcb QR auto settlement completed (pls adjust for E-Receipt both in manual & auto) AutoSettleService/QRSettlementTransactionFragment 2025-12-27 02:30:29 +07:00
1e1f749148 QR auto settlement completed (pls adjust for E-Receipt both in manual & auto) AutoSettleService/QRSettlementTransactionFragment 2025-12-27 02:29:29 +07:00
9a7f4a5245 Merge remote-tracking branch 'origin/merge_latest_SIT' into merge_latest_SIT 2025-12-25 17:37:28 +07:00
bcbe16e201 QR Auto Settlement draft version,still need to optimize it 2025-12-25 17:37:20 +07:00
MooN
1eb0a550fe update for QRSettlement slip design and hide navi 2025-12-24 20:30:31 +06:30
MooN
6c596cb061 disabled navigation 2025-12-24 15:46:35 +06:30
MooN
5163ce2840 Merge branch 'merge_latest_SIT' of https://hub.utsmyanmar.com/Kyaw_Min_Khant/KBZ-POS into merge_latest_SIT 2025-12-24 15:17:20 +06:30
MooN
29073c0ef8 address 3 added 2025-12-24 15:17:15 +06:30
122c526cc9 disable home button and removed exit button from navigation menu 2025-12-24 15:10:33 +07:00
MooN
9e8315050a Update fragment_host_config.xml 2025-12-23 23:24:57 +06:30
MooN
83af914911 fix for refund decimal in summary and detail reports 2025-12-23 23:03:15 +06:30
MooN
bbabe9b824 physical receipt fix decimal for print summery 2025-12-23 21:31:54 +06:30
MooN
063805e77a fix detail report decimal 2025-12-23 20:06:27 +06:30
MooN
34b2fe8189 e-receipt fix for qr settlement 2025-12-23 12:05:46 +06:30
c96d68ff2f QR Settlement is optimized and History was also resolved 2025-12-23 01:39:47 +07:00
MooN
ee037a1101 hide time picker 2025-12-22 22:54:28 +06:30
MooN
aa34f8e65e Update TMSSetupsImpl.java 2025-12-22 16:24:59 +06:30
MooN
28b17a28be qr_decimal_fix 2025-12-22 16:07:35 +06:30
MooN
aa1cf12d93 print terminal config print method refactor 2025-12-21 20:40:10 +06:30
MooN
e864630aaf modified the physical receipt 2025-12-21 11:10:37 +06:30
MooN
05eed5776d added payment id 2025-12-18 12:09:13 +06:30
MooN
d843415366 update for operator_id 2025-12-18 11:51:35 +06:30
MooN
691ccff49f file re-download fix 2025-12-17 23:14:43 +06:30
MooN
666325ed82 e-receipt new fields 2025-12-17 22:55:44 +06:30
MooN
5799072d9f Update HostConfigFragment.java 2025-12-17 15:03:39 +06:30
MooN
015fe3524d fix for receipt 2025-12-17 13:59:05 +06:30
MooN
4984a726e9 hide history in see more 2025-12-17 02:27:46 +06:30
MooN
9a4d8e279a close order 2025-12-17 00:58:47 +06:30
MooN
5ce14a31ca fix incorrect value in QR refund 2025-12-17 00:54:46 +06:30
MooN
cca1b6ded6 SiriusTerminal added
added new reponse for SiriusTerminal
2025-12-16 23:10:16 +06:30
7d8f9f5af2 QR settlement added crash handling 2025-12-16 00:31:22 +07:00
c46b8793a1 QR settlement fixed 2025-12-16 00:05:05 +07:00
3eb67d92d9 modified commented code block 2025-12-15 23:15:37 +07:00
83d7f44561 Merge remote-tracking branch 'origin/merge_latest_SIT' into merge_latest_SIT
# Conflicts:
#	paylibs/src/main/java/com/utsmyanmar/paylibs/print/printx/BaseXPrint.java
2025-12-15 23:13:14 +07:00
4e26b2ec4d fixed QR Settlement & History 2025-12-15 23:12:51 +07:00
MooN
4ce7a9355c shrinking physical receipt 2025-12-15 22:35:22 +06:30
MooN
c697d6c3f9 auto print disabled
currently auto print disabled for QR
2025-12-15 15:49:12 +06:30
MooN
53a9d8ba1b added change log 2025-12-12 14:14:48 +06:30
MooN
e6e6f68360 Update TMSSetupsImpl.java
update Null safety for shortCode
2025-12-12 14:14:27 +06:30
MooN
d5bef92cff slip font change 2025-12-12 02:07:31 +06:30
MooN
a47137f624 qr close order api
qr close order api  called on back press of generated qr
2025-12-12 01:01:42 +06:30
MooN
299c8fc892 dynamic refund certi 2025-12-11 23:43:27 +06:30
f2e797a0dc fixed for shortCode 2025-12-11 16:59:17 +07:00
52ee779e18 decimal hide is fixed 2025-12-11 15:11:14 +07:00
a071c53823 no 7 and 8 fixed 2025-12-11 13:21:46 +07:00
d76b48d4ca fixed amount screen issues 2025-12-11 12:22:24 +07:00
MooN
ff9450a50c refund crash fixed 2025-12-11 04:38:57 +06:30
MooN
7452443a45 add expire time on QR 2025-12-11 03:02:40 +06:30
7d894116dd Merge remote-tracking branch 'origin/merge_latest_SIT' into merge_latest_SIT 2025-12-10 15:20:04 +07:00
0804f7b762 dynamic tpdu 2025-12-10 15:19:50 +07:00
MooN
a1c0f55472 Merge branch 'merge_latest_SIT' of https://hub.utsmyanmar.com/Kyaw_Min_Khant/KBZ-POS into merge_latest_SIT 2025-12-10 14:48:44 +06:30
MooN
71e0e24b3c disable demo mode 2025-12-10 14:47:25 +06:30
014bdc18e3 implemented ubuntu_mono font for all receipts 2025-12-10 05:13:26 +07:00
MooN
97014377a8 Merge branch 'merge_latest_SIT' of https://hub.utsmyanmar.com/Kyaw_Min_Khant/KBZ-POS into merge_latest_SIT 2025-12-09 16:07:37 +06:30
MooN
424678e0ca update button hide/show on qr refund 2025-12-09 16:07:21 +06:30
b92f9bfe4e QR settlement completed 2025-12-09 05:58:09 +07:00
MooN
d42ee5d2f7 Merge branch 'merge_latest_SIT' of https://hub.utsmyanmar.com/Kyaw_Min_Khant/KBZ-POS into merge_latest_SIT 2025-12-08 22:04:42 +06:30
MooN
3fe711cc2f multi variant 2025-12-08 11:44:23 +06:30
f91ae09be7 QR settlement need to adjust slip design. 2025-12-07 05:49:17 +07:00
MooN
eebe9ac2c6 released 2025-12-05 13:56:22 +06:30
MooN
d3a8bf6ab5 release mode 2025-12-04 12:10:30 +06:30
MooN
311f7a7e1e nexdkey-lib fix 2025-12-04 10:53:25 +06:30
MooN
2204e99463 Merge branch 'merge-latest' into fix_ 2025-12-04 10:44:38 +06:30
8200cefb96 fixed xml not included 2025-12-04 11:13:42 +07:00
MooN
c18704f031 Merge branch 'merge-latest' into fix_ 2025-12-04 10:37:09 +06:30
MooN
eed7dd4680 host config view 2025-12-04 10:32:31 +06:30
1a7e86077c fixed nexgo-sdklkey lib not included 2025-12-04 08:10:41 +07:00
MooN
20417eb811 settings buttons disable 2025-12-03 21:45:07 +06:30
MooN
0d796ab20f qr_partial_enable/disable fixed 2025-12-03 20:59:39 +06:30
8b211ca530 changed static key index to config index at sign on 2025-12-03 05:06:03 +07:00
6bf49b3f19 e-receipt settlement/popup retry dialog when paper roll is empty/key inject implemented 2025-12-03 04:56:57 +07:00
MooN
4d5124fc64 qr e-receipt push fix 2025-12-03 00:01:11 +06:30
MooN
6b1c6ef4b5 dashboard fixed 2025-12-02 23:47:30 +06:30
MooN
a6db8970af Merge branch 'merge-latest' into fix_ 2025-12-02 14:13:45 +06:30
2f4db87441 e signature is now printing on paper 2025-12-02 05:10:22 +07:00
MooN
315d37ca31 fix bugs from excel 1 2025-12-02 01:01:39 +06:30
MooN
ff68ee6a1f qr fixes 2025-12-01 15:58:06 +06:30
aa37e14ea4 integrated E-Receipt for card transactions and
fixed some other issues
2025-12-01 05:46:01 +07:00
MooN
a0ffff71c4 qr decimal fix 2025-11-28 09:43:25 +06:30
MooN
2441ba5141 e-receipt for qr fixed 2025-11-27 19:18:49 +06:30
MooN
90c9a48197 Merge branch 'merge-latest' into geo_fench 2025-11-26 10:13:16 +06:30
1ac8c14b09 updated some codes 2025-11-25 17:12:42 +07:00
MooN
af45ed4b43 + 1 version 2025-11-25 13:40:47 +06:30
MooN
799f03dbcd update for Mid length 2025-11-25 13:40:35 +06:30
44f4e1ea94 updated process code 2025-11-24 16:00:12 +07:00
MooN
c619166ea8 fix - sec ip empty 2025-11-24 08:46:49 +06:30
49b929ab27 switched BPC host 2025-11-23 20:19:00 +07:00
MooN
ab4801d687 version fix 2025-11-23 18:45:49 +06:30
MooN
d8befb7f2a Update fragment_qr_refund_detail.xml 2025-11-23 17:16:52 +06:30
MooN
3d2b316e99 Merge remote-tracking branch 'origin/mpu_latest' into latest 2025-11-23 15:56:10 +06:30
MooN
8bf4d6da22 decimal fix
decimal fix
2025-11-23 15:55:48 +06:30
MooN
adfa73070f Update fragment_qr_refund_detail.xml
disable partial refund
2025-11-23 15:45:34 +06:30
MooN
a449a366e0 Update QRTransactionFragment.java 2025-11-23 15:24:26 +06:30
MooN
5d450e0a48 qr-e-receipt 2025-11-23 01:35:04 +06:30
ced683e302 mpu certi final 2025-11-21 14:34:06 +07:00
MooN
1811fefec1 disable printing on qr_pay_failed 2025-11-20 15:50:29 +06:30
MooN
b484f69cb3 mmqr_interval
mmqr interval connection with TMS
2025-11-20 15:49:55 +06:30
MooN
8cd56777cc color testing 2025-11-19 15:58:02 +06:30
MooN
53f6414f70 Merge branch 'new_dashboard' into merge_with_mpu 2025-11-19 15:48:01 +06:30
MooN
bb60828767 Merge remote-tracking branch 'origin/mpu' into merge_with_mpu 2025-11-19 15:42:49 +06:30
MooN
749abb1455 square btn changed 2025-11-19 12:13:17 +06:30
a8624195b0 mpu certi ready 2025-11-19 02:07:54 +07:00
MooN
65eb17e3b9 new dashboard design 2025-11-18 22:05:34 +06:30
2f9f06ce87 mpu certi almost ready 2025-11-18 06:17:40 +07:00
41b6fb7782 mpu certi almost ready 2025-11-18 06:13:31 +07:00
MooN
7e2a589636 ui fix 2025-11-17 01:41:45 +06:30
MooN
7c266677e7 merge fix 2025-11-16 22:34:22 +06:30
MooN
063dfae87f Merge remote-tracking branch 'origin/master' into merge 2025-11-14 16:37:56 +06:30
MooN
9502ee7a04 13-Nov-25 2025-11-13 14:45:18 +06:30
MooN
5509bf4349 up 2025-11-13 11:27:36 +06:30
476e1d9eaa corrected refund flow 2025-11-13 02:49:21 +07:00
28d4672878 fixed password for refund 2025-11-13 01:01:01 +07:00
MooN
644df8211d qr_refundable_from_list 2025-11-12 21:16:22 +06:30
MooN
2358782f3d safe to route fix 2025-11-11 23:12:22 +06:30
MooN
f142df0144 refudn list 2025-11-11 22:58:55 +06:30
8da4b2399e fixed some formats 2025-11-11 17:26:54 +07:00
MooN
efb0c76f69 qr only history 2025-11-10 16:27:06 +06:30
MooN
d861c278a2 qr_generate 2025-11-09 16:32:15 +06:30
5efcc7ef24 fixed can't call sign on on demo mode 2025-11-07 15:34:00 +07:00
c7ac1e90bf fixed second generated QR 2025-11-07 14:04:59 +07:00
1b4a56c29f sec commit 2025-11-07 01:46:25 +07:00
a885d05b62 sec commit 2025-11-07 01:40:46 +07:00
1cedbc987c sec commit 2025-11-07 01:38:39 +07:00
0a2cc295a1 first commit 2025-11-06 13:38:40 +07:00
b5a82a5fd1 first commit 2025-11-06 01:08:32 +07:00
485 changed files with 24147 additions and 6633 deletions

7
.gitignore vendored
View File

@ -13,3 +13,10 @@
.externalNativeBuild
.cxx
local.properties
/.idea
/app/release/*
/app/sit/release/*
/app/uat/release/*
/app/uat
/.idea
/app/prod/release

View File

@ -1 +1 @@
KBZ-Master
KBZ-Master-latest

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AskMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Ask2AgentMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EditMigrationStateService">
<option name="migrationStatus" value="COMPLETED" />
</component>
</project>

View File

@ -4,7 +4,7 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-10-28T19:40:02.148831Z">
<DropdownSelection timestamp="2026-01-20T10:19:44.274945Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=0123456789ABCDEF" />

View File

@ -14,10 +14,11 @@
<option value="$PROJECT_DIR$/baselib" />
<option value="$PROJECT_DIR$/ecr" />
<option value="$PROJECT_DIR$/ecr-service-lib" />
<option value="$PROJECT_DIR$/link-service-lib" />
<option value="$PROJECT_DIR$/mpulib" />
<option value="$PROJECT_DIR$/nexdlkey-lib" />
<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>

View File

@ -0,0 +1,4 @@
kotlin version: 2.0.21
error message: The daemon has terminated unexpectedly on startup attempt #1 with error code: 0. The daemon process output:
1. Kotlin compile daemon is ready

View File

@ -14,32 +14,48 @@ android {
applicationId "com.utsmm.kbz"
minSdk 24
targetSdk 33
versionCode 5
versionName "1.05"
versionCode 21
versionName "2.1"
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"
// }
// }
// -----------------------------
// 🔥 MULTI-VARIANT FLAVORS
// -----------------------------
flavorDimensions "env"
productFlavors {
sit {
dimension "env"
applicationId "com.utsmm.kbz.sit"
versionNameSuffix "-sit"
resValue "string", "app_name", "KBZ-SIT"
}
uat {
dimension "env"
applicationId "com.utsmm.kbz.uat"
versionNameSuffix "-uat"
resValue "string", "app_name", "KBZ-UAT"
}
prod {
dimension "env"
applicationId "com.utsmm.kbz"
versionNameSuffix ""
resValue "string", "app_name", "KBZ-POS"
}
}
buildTypes {
release {
minifyEnabled false
minifyEnabled true
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
debuggable true
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
@ -90,7 +106,6 @@ 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"
@ -181,7 +196,7 @@ dependencies {
implementation project(path: ':paylibs')
implementation project(path: ':mpulib')
implementation project(path: ':baselib')
implementation project(path: ':paysdk-lib')
// implementation project(path: ':paysdk-lib')
implementation project(path: ':nexsdk-lib')
implementation project(path: ':qrgen-lib')
implementation project(path: ':xpay')
@ -189,6 +204,7 @@ dependencies {
implementation project(path: ':qrgen-lib')
//// implementation project(path: ':samlSirius')
implementation project(path: ':ecr')
implementation project(path: ':nexdlkey-lib')
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2' // 1.1.2
@ -196,15 +212,16 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.3.0'
androidTestImplementation 'androidx.test:core:1.5.0'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
// 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'
//time picker
implementation "com.google.android.material:material:1.11.0"
}

244
app/proguard-rules.pro vendored
View File

@ -20,7 +20,249 @@
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keepattributes Signature, *Annotation*, SourceFile, LineNumberTable, InnerClasses, EnclosingMethod
-dontwarn sun.misc.**
# Keep Bouncy Castle classes for security providers
# Hilt ProGuard Rules - CRITICAL FOR DEPENDENCY INJECTION
-dontwarn dagger.hilt.**
-keep class dagger.hilt.** { *; }
-keep class * extends dagger.hilt.** { *; }
# Keep all Hilt generated classes
-keep class **_HiltComponents { *; }
-keep class **_HiltComponents$* { *; }
-keep class **_HiltModules { *; }
-keep class **_HiltModules$* { *; }
-keep class * extends dagger.hilt.android.internal.managers.ApplicationComponentManager { *; }
-keep class * extends dagger.hilt.android.internal.managers.ActivityComponentManager { *; }
-keep class * extends dagger.hilt.android.internal.managers.FragmentComponentManager { *; }
-keep class * extends dagger.hilt.android.internal.managers.ViewComponentManager { *; }
-keep class * extends dagger.hilt.android.internal.managers.ServiceComponentManager { *; }
# Keep Hilt entry points and components
-keep @dagger.hilt.InstallIn class * { *; }
-keep @dagger.hilt.android.AndroidEntryPoint class * { *; }
-keep @dagger.hilt.android.HiltAndroidApp class * { *; }
# Keep classes annotated with @Module, @Component, @Subcomponent
-keep @dagger.Module class * { *; }
-keep @dagger.Component class * { *; }
-keep @dagger.Component.Builder class * { *; }
-keep @dagger.Subcomponent class * { *; }
-keep @dagger.Subcomponent.Builder class * { *; }
# Keep all classes that have @Inject constructors, fields, or methods
-keepclasseswithmembers class * {
@javax.inject.Inject <init>(...);
}
-keepclasseswithmembers class * {
@javax.inject.Inject <fields>;
}
-keepclasseswithmembers class * {
@javax.inject.Inject <methods>;
}
# Keep Application class and its generated Hilt class
-keep class com.utsmm.kbz.MyApplication { *; }
-keep class com.utsmm.kbz.Hilt_MyApplication { *; }
-keep class com.utsmyanmar.baselib.BaseApplication { *; }
# Keep main activity and its generated classes
-keep class com.utsmm.kbz.MainActivity { *; }
# ViewModels and Repository classes (important for injection)
-keep class * extends androidx.lifecycle.ViewModel { *; }
-keep class com.utsmyanmar.baselib.repo.Repository { *; }
-keep class com.utsmyanmar.baselib.emv.EmvParamOperation { *; }
-keep class com.utsmyanmar.baselib.emv.TerminalParamOperation { *; }
# Keep all Dagger generated classes - these are critical!
-keep class **_Factory { *; }
-keep class **_MembersInjector { *; }
-keep class **_Provide* { *; }
-keep class com.utsmyanmar.baselib.network.model.* { <fields>; }
-keep class com.utsmyanmar.baselib.network.model.sirius.* { <fields>; }
-keep class com.utsmyanmar.baselib.db.model.* { <fields>; }
-keep class com.utsmyanmar.ecr.data.* { <fields>; }
-keep class com.utsmyanmar.ecr.data.model.* { <fields>; }
-keep class com.utsmyanmar.mpulib.data.model.* { <fields>; }
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# this is start
-keep class org.bouncycastle.** { *; }
-keep interface org.bouncycastle.** { *; }
-keep class okhttp3.internal.platform.BouncyCastlePlatform { *; }
# Keep classes from the JNDI package
-keep class javax.naming.** { *; }
-keep class javax.naming.directory.** { *; }
# Keep Bouncy Castle classes
-keep class org.bouncycastle.** { *; }
# Keep Conscrypt classes
-keep class org.conscrypt.** { *; }
# Keep OpenJSSE classes
-keep class org.openjsse.** { *; }
# Keep classes from okhttp3.internal.platform.BouncyCastlePlatform
-keep class okhttp3.internal.platform.BouncyCastlePlatform { *; }
# Keep classes from okhttp3.internal.platform.ConscryptPlatform
-keep class okhttp3.internal.platform.ConscryptPlatform$Companion { *; }
#-keep class okhttp3.internal.platform.ConscryptPlatform$platformTrustManager$2 { *; }
# Keep classes from okhttp3.internal.platform.OpenJSSEPlatform
-keep class okhttp3.internal.platform.OpenJSSEPlatform { *; }
#this is end
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
# Jun9 2022
#-keep public class * implements com.bumptech.glide.module.GlideModule
#-keep class * extends com.bumptech.glide.module.AppGlideModule {
# <init>(...);
#}
#-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
# **[] $VALUES;
# public *;
#}
#-assumenosideeffects class android.util.Log {
#public static int d(...);
#public static int v(...);
#public static int i(...);
#public static int w(...);
#public static int wtf(...);
# }
-dontwarn okhttp3.internal.platform.**
-dontwarn org.conscrypt.**
-dontwarn org.bouncycastle.**
-dontwarn org.openjsse.**
# RxJava 3 Rules - Critical for Observable chains
-keep class io.reactivex.rxjava3.** { *; }
-dontwarn io.reactivex.rxjava3.**
-keep class io.reactivex.rxjava3.core.** { *; }
-keep class io.reactivex.rxjava3.android.** { *; }
-keep class io.reactivex.rxjava3.schedulers.** { *; }
# Retrofit and OkHttp rules
-keepattributes RuntimeVisibleAnnotations
-keep class retrofit2.** { *; }
-keepclassmembernames interface * {
@retrofit2.http.* <methods>;
}
# AndroidX and Lifecycle components
-keep class androidx.lifecycle.** { *; }
-keep class * extends androidx.lifecycle.ViewModel { *; }
-keep class androidx.activity.** { *; }
-keep class androidx.fragment.** { *; }
# Navigation component rules
-keep class androidx.navigation.** { *; }
-keep class * implements androidx.navigation.NavDirections { *; }
# DataBinding rules
-keep class androidx.databinding.** { *; }
-keep class * extends androidx.databinding.ViewDataBinding { *; }
# Room database rules (if using Room)
-keep class androidx.room.** { *; }
-keep class * extends androidx.room.RoomDatabase { *; }
# PayLibs and device-specific rules
-keep class com.utsmyanmar.paylibs.** { *; }
-keep class com.nexgo.** { *; }
-keep class com.sunmi.** { *; }
-keep class com.utsmyanmar.checkxread.** { *; }
-keep class com.utsmyanmar.ecr.** { *; }
-keep class com.utsmyanmar.mpulib.** { *; }
-keep class com.utsmyanmar.baselib.** { *; }
# Enum preservation for critical enums
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Keep model classes from obfuscation completely
-keep class com.utsmyanmar.paylibs.model.** { *; }
-keep class com.utsmyanmar.baselib.db.model.** { *; }
# Critical: Keep all native methods and JNI classes
-keepclasseswithmembernames class * {
native <methods>;
}
# Keep critical system params and utils
-keep class com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation { *; }
-keep class com.utsmyanmar.paylibs.utils.** { *; }
# Prevent obfuscation of classes used in reflection
-keep class * extends java.lang.Exception
-keep class * extends java.lang.Error
# CRITICAL: Keep all generated application components from obfuscation
-keep class com.utsmm.kbz.MyApplication_GeneratedInjector { *; }
#-keep class com.utsmm.kbz.MyApplication_HiltComponents$SingletonC { *; }
#-keep class com.utsmm.kbz.MyApplication_HiltComponents { *; }
# Keep all classes with "Generated" in their name (Hilt generates these)
-keep class **_Generated { *; }
-keep class **GeneratedInjector { *; }
# Additional protection for the specific classes causing crashes
-keep class **.D0.h { *; }
-keep class **.m2.f { *; }
-keep class **.J3.b { *; }
# Keep everything in the di package to prevent injection failures
-keep class com.utsmyanmar.baselib.di.** { *; }
-keep class com.utsmm.kbz.di.** { *; }
# Hilt Extension points
#-keep class * extends dagger.hilt.android.internal.managers.ApplicationComponentManager$ApplicationComponentBuilder { *; }
# Don't obfuscate any annotation processing related classes
-keep class dagger.internal.** { *; }
-keepnames class dagger.internal.** { *; }
# Keep annotation-based bindings
-keep @javax.inject.Inject class * { *; }
-keep @dagger.Provides class * { *; }
-keep @dagger.Module class * { *; }
# Keep Nexgo SDK
-keep class com.nexgo.** { *; }
# Keep DDI interface (VERY IMPORTANT)
-keep class com.xinguodu.ddiinterface.** { *; }
# Keep printer implementations
-keep class com.nexgo.oaf.apiv3.device.printer.** { *; }
# Prevent method shrinking/optimization
-dontoptimize
-dontshrink
-dontwarn com.xgd.smartpos.manager.app.UsageInfo
-dontwarn com.xgd.smartpos.manager.app.UsageStats

BIN
app/release/app-release.apk Normal file

Binary file not shown.

View File

@ -4,15 +4,15 @@
"type": "APK",
"kind": "Directory"
},
"applicationId": "com.utsmm.kbz",
"applicationId": "com.utsmm.kbz.sit",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 5,
"versionName": "1.05",
"versionCode": 1,
"versionName": "1.0",
"outputFile": "app-release.apk"
}
],

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.sit",
"variantName": "sitRelease",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
"versionCode": 2,
"versionName": "1.01-sit",
"outputFile": "app-sit-release.apk"
}
],
"elementType": "File",
"baselineProfiles": [
{
"minApi": 28,
"maxApi": 30,
"baselineProfiles": [
"baselineProfiles/1/app-sit-release.dm"
]
},
{
"minApi": 31,
"maxApi": 2147483647,
"baselineProfiles": [
"baselineProfiles/0/app-sit-release.dm"
]
}
],
"minSdkVersionForDexing": 24
}

View File

@ -10,6 +10,32 @@ import org.junit.runner.RunWith;
import static org.junit.Assert.*;
import com.utsmm.kbz.util.MockData;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmyanmar.checkxread.model.CardDataX;
import com.utsmyanmar.checkxread.util.CardTypeX;
import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.isobuilder.ISOMode;
import com.utsmyanmar.paylibs.isobuilder.builderx.ISOMsgX;
import com.utsmyanmar.paylibs.isobuilder.builderx.ISOVersion;
import com.utsmyanmar.paylibs.model.MsgField;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.model.enums.TransCVM;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.MessageType;
import com.utsmyanmar.paylibs.utils.core_utils.ByteUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.BaseCardType;
import com.utsmyanmar.paylibs.utils.enums.HostName;
import com.utsmyanmar.paylibs.utils.iso_utils.BitmapConfig;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionType;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmyanmar.paylibs.utils.params.Params;
import java.util.Locale;
import java.util.Map;
/**
* Instrumented test, which will execute on an Android device.
*
@ -23,4 +49,185 @@ public class ExampleInstrumentedTest {
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.utsmm.kbz", appContext.getPackageName());
}
@Test
public void testVoidPacket() {
CardDataX cardDataX = MockData.getInstance().generateMPUCard();
TradeData tradeData = TransactionUtil.getInstance().initMPUTransaction(cardDataX, CardTypeX.IC);
String bitmap = BitmapConfig.MPU_NEW_VOID;
MessageType messageType = MessageType.FINANCIAL;
ISOMsgX isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1987, ISOMode.ONLY_HEADER, HostName.FINEXUS)
.build();
TradeData transTradeData = setUpRebuildTransactions(tradeData, TransactionsType.VOID, HostName.FINEXUS);
transTradeData.getPayDetail().setAmount(50000);
PayDetail transPayDetail = transTradeData.getPayDetail();
byte[] sendBytes;
try {
sendBytes = isoMsgX.buildISOPackets(transTradeData, bitmap, messageType);
System.out.println("Hex Str : "+ ByteUtil.bytes2HexStr(sendBytes));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testSalePacket() {
CardDataX cardDataX = MockData.getInstance().generateMPUCard();
TradeData tradeData = TransactionUtil.getInstance().initEMVTransaction(cardDataX, CardTypeX.IC);
PayDetail payDetail = tradeData.getPayDetail();
payDetail.setProcessCode("000000");
payDetail.setTransactionType(TransactionType.SALE);
String bitmap = BitmapConfig.BPC_SALE;
MessageType messageType = MessageType.FINANCIAL;
ISOMsgX isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.BOTH_HEADER_TPDU, HostName.BPC)
.build();
byte[] sendBytes;
try {
sendBytes = isoMsgX.buildISOPackets(tradeData, bitmap, messageType);
System.out.println("Hex Str : "+ ByteUtil.bytes2HexStr(sendBytes));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testResponseSalePacket() {
String resp = "0071600000051730323130723000000A80820031363437363137333130303030303030323730303030303030303030303030353530303030313039313634353532303030303033323630313039313731353532303031303030303735343431393130303030343733343531303400048A023936";
resp = "00DB600000051730323130723000000A80820031363335373130353030333938393032373030303030303030303030303030353030303030313230313633323039303030303133323630313230313633323033303031303030303832333632393130383132333037313431303401105F2A02010482021C008407A00000006510109505808800E0009A032601209C01009F02060000000500009F03060000000000009F100807010104A09000B09F1A0201049F26080611D1D33562865F9F2701809F3303E0E8C89F34031E03009F360200049F37045A647F128A023936";
byte[] response = ByteUtil.hexStr2Bytes(resp);
String bitmap = BitmapConfig.BPC_SALE;
MessageType messageType = MessageType.FINANCIAL;
ISOMsgX isoMsgX = new ISOMsgX.ISOMsgXBuilder(ISOVersion.VERSION_1993, ISOMode.BOTH_HEADER_TPDU, HostName.BPC)
.build();
Map<String, MsgField> responseMap = isoMsgX.parseISOPackets(response,response.length);
System.out.println("Resp Str : "+ responseMap);
// try {
// responseMap = isoMsgX.parseISOPackets(response,response.length);
//
// System.out.println("Resp Str : "+ responseMap);
// } catch (Exception e) {
// e.printStackTrace();
// }
}
private TradeData setUpRebuildTransactions(TradeData tradeData, TransactionsType transactionsType, HostName hostName) {
LogUtil.d(Constant.TAG, "Starting Online Transaction--" + hostName + "--" + transactionsType);
TradeData newTrade = Params.newTrade(true);
PayDetail newPay = newTrade.getPayDetail();
PayDetail oldPay = tradeData.getPayDetail();
newPay.setCardType(100);
newPay.setPINCipher("");
newPay.setHostName(hostName.name);
newPay.setTransType(transactionsType.name);
newPay.setProcessCode(transactionsType.processCode);
newPay.setCardNo(oldPay.getCardNo());
newPay.setCardHolderName(oldPay.getCardHolderName());
newPay.setEXPDate(oldPay.getEXPDate());
newPay.setTradeDate(oldPay.getTradeDate());
newPay.setTradeTime(oldPay.getTradeTime());
newPay.setAmount(oldPay.getAmount());
newPay.setTransactionType(transactionsType.value);
newPay.setAccountType(oldPay.getAccountType());
newPay.setCardInfo(oldPay.getCardInfo());
newPay.setSettlementEnabled(SystemParamsOperation.getInstance().getSettlementStatus());
// added on Nov, 13 2024
newPay.setICC55(oldPay.getICC55());
if(newPay.getICC55() != null && !newPay.getICC55().isEmpty()) {
newPay.setAppLabel(oldPay.getAppLabel());
newPay.setAppName(oldPay.getAppName());
newPay.setTSI(oldPay.getTSI());
newPay.setAID(oldPay.getAID());
newPay.setArqC(oldPay.getArqC());
newPay.setTVR(oldPay.getTVR());
}
if(transactionsType != TransactionsType.PRE_AUTH_COMPLETE) {
newPay.setTradeDateTime(oldPay.getTradeDateTime());
}
if (transactionsType == TransactionsType.VOID || transactionsType == TransactionsType.REFUND) {
String field60;
if(hostName == HostName.BPC) {
field60 = String.format(Locale.getDefault(), "%010d00", oldPay.getAmount());
} else {
field60 = String.format(Locale.getDefault(), "%012d", oldPay.getAmount());
}
// String field60 = String.format(Locale.getDefault(), "%010d00", oldPay.getAmount());
newPay.setReferNo(oldPay.getReferNo());
newPay.setTransCVM(TransCVM.SIGNATURE);
newTrade.setField60(field60);
} else if (transactionsType == TransactionsType.PRE_AUTH_VOID) {
newPay.setCardType(oldPay.getCardType());
newPay.setCustomOrderNo(oldPay.getVoucherNo());
newPay.setReferNo(oldPay.getReferNo());
newPay.setCardInfo(oldPay.getCardInfo());
newPay.setPINCipher(oldPay.getPINCipher());
newPay.setTempKSN(oldPay.getTempKSN());
newPay.setTransCVM(TransCVM.SIGNATURE);
// for manual entry reversal which need de 35
} else if (transactionsType == TransactionsType.TIP_ADJUSTMENT ) {
newPay.setReferNo(oldPay.getReferNo());
newPay.setApprovalCode(oldPay.getApprovalCode());
} else if (transactionsType == TransactionsType.PRE_AUTH_COMPLETE) {
newPay.setCardType(oldPay.getCardType());
newPay.setCardInfo(oldPay.getCardInfo());
newPay.setPINCipher(oldPay.getPINCipher());
newPay.setReferNo(oldPay.getReferNo());
newPay.setTempKSN(oldPay.getTempKSN());
} else if (transactionsType == TransactionsType.PRE_AUTH_COMPLETE_VOID) {
newPay.setVoucherNo(oldPay.getVoucherNo());
newPay.setCustomOrderNo(oldPay.getVoucherNo());
newPay.setReferNo(oldPay.getReferNo());
newPay.setCardInfo(oldPay.getCardInfo());
/*
* new requirements */
newPay.setCardType(BaseCardType.IC.getValue());
newPay.setPINCipher("55");
newPay.setTransCVM(TransCVM.SIGNATURE);
}
if(oldPay.getAccountType().equals("MPU")){
// newPay.setIsFreeSign(true);
newPay.setTransCVM(TransCVM.SIGNATURE);
}
newTrade.setPayDetail(newPay);
return newTrade;
}
}

View File

@ -9,7 +9,8 @@
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<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" />
@ -27,6 +28,14 @@
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<!-- Permission for exact alarms on Android 12+ -->
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<!-- Permissions for background auto settlement -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
<!-- android:noHistory="true"-->
<!-- android:excludeFromRecents="true"-->
@ -46,30 +55,32 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme.NoActionBar"
>
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">
android:exported="true"
android:showWhenLocked="true"
android:turnScreenOn="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.HOME"/>
<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" />
<receiver android:name="com.utsmm.kbz.service.AutoAlarmReceiver" />
<service
android:name="com.utsmm.kbz.service.SmileSettleService"
android:name="com.utsmm.kbz.service.AutoSettleService"
android:enabled="true"
android:exported="false">
<meta-data

Binary file not shown.

View File

@ -1,5 +1,6 @@
package com.utsmm.kbz;
import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
@ -16,23 +17,39 @@ import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
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.nexgo.downloadkey.downloadflow.DownloadFEntity;
import com.nexgo.downloadkey.downloadflow.DownloadFlow;
import com.nexgo.downloadkey.downloadflow.DownloadFlowProcessListener;
import com.nexgo.downloadkey.downloadflow.DownloadFlowResultEntity;
import com.nexgo.downloadkey.downloadflow.DownloadResult;
import com.nexgo.oaf.apiv3.device.pinpad.PinPad;
import com.nexgo.oaf.apiv3.device.pinpad.WorkKeyTypeEnum;
import com.utsmyanmar.baselib.BaseApplication;
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.model.PayDetail;
import com.utsmyanmar.paylibs.model.SettleData;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
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.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.service.AutoAlarmReceiver;
import com.utsmm.kbz.ui.core_ui.InputPasswordFragment;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.navigation.NaviAdminFragment;
@ -43,6 +60,7 @@ import com.utsmm.kbz.util.tms.TMSUtil;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
@ -56,6 +74,8 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.params.Params;
/**
* Main Activity handling application navigation and fragment interactions
*/
@ -95,6 +115,8 @@ public class MainActivity extends AppCompatActivity implements
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
BaseApplication.getInstance().deviceEngine.getPlatform().hideNavigationBar();
// Keep screen on
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
@ -124,8 +146,35 @@ public class MainActivity extends AppCompatActivity implements
// Initialize special back handling fragments
initSpecialBackHandlingFragments();
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(new Runnable() {
@Override
public void run() {
initKey();
}
}, 500);
}
private void initKey(){
// SystemParamsOperation.getInstance().setTmsAddress("https://api-tms-uat.kbzbank.com:8443/sirius");
SystemParamsOperation.getInstance().setTmsAddress("https://sirius-nest.utsmyanmar.com");
// SystemParamsOperation.getInstance().setEReceiptAddress("https://api-tms-uat.kbzbank.com:8443/receipt");
SystemParamsOperation.getInstance().setEReceiptAddress("https://receipt-nest.utsmyanmar.com");
PinPad pinPad = MyApplication.getInstance().deviceEngine.getPinPad();
byte[] encryptedPIK = SystemParamsOperation.getInstance().getPIK();
if (encryptedPIK != null && encryptedPIK.length != 0) {
int result = pinPad.writeWKey(9, WorkKeyTypeEnum.PINKEY, encryptedPIK, encryptedPIK.length);
LogUtil.d(TAG, "save PIK key result: "+result);
} else {
LogUtil.d(TAG, "There's no PIK key!");
}
}
private void initViewModels() {
sharedViewModel = new ViewModelProvider(this).get(SharedViewModel.class);
}
@ -240,7 +289,7 @@ public class MainActivity extends AppCompatActivity implements
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this,
0,
new Intent(this, SmileAlarmReceiver.class),
new Intent(this, AutoAlarmReceiver.class),
PendingIntent.FLAG_UPDATE_CURRENT
);
@ -382,20 +431,95 @@ public class MainActivity extends AppCompatActivity implements
SystemParamsOperation.getInstance().setSetupEcr(false);
SystemParamsOperation.getInstance().setDownloadedParams(false);
handleAutoSettlementIntent(getIntent());
BaseApplication.getInstance().deviceEngine.getPlatform().hideNavigationBar();
}
@Override
public void onStop(){
super.onStop();
// BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
// BaseApplication.getInstance().deviceEngine.getPlatform().enableHomeButton();
// BaseApplication.getInstance().deviceEngine.getPlatform().enableTaskButton();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
handleAutoSettlementIntent(intent);
}
private void handleAutoSettlementIntent(Intent intent) {
if (intent == null) return;
// Handle regular auto settlement
boolean auto = intent.getBooleanExtra("AUTO_SETTLEMENT", false);
if (auto) {
PayDetail payDetail = (PayDetail) intent.getSerializableExtra("EXTRA_PAY_DETAIL");
if (payDetail != null) {
sharedViewModel.payDetail.setValue(payDetail);
sharedViewModel.transactionsType.setValue(TransactionsType.SETTLEMENT);
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(payDetail.getAmount()));
try {
navController.navigate(R.id.transactionResultFragment);
} catch (Exception e) {
LogUtil.e(TAG, "Navigation error: " + e.getMessage());
}
}
return;
}
// Handle QR auto settlement
boolean autoQR = intent.getBooleanExtra("AUTO_QR_SETTLEMENT", false);
if (autoQR) {
int qrSaleCount = intent.getIntExtra("QR_SALE_COUNT", 0);
long qrSaleAmount = intent.getLongExtra("QR_SALE_AMOUNT", 0L);
int qrRefundCount = intent.getIntExtra("QR_REFUND_COUNT", 0);
long qrRefundAmount = intent.getLongExtra("QR_REFUND_AMOUNT", 0L);
long totalAmount = intent.getLongExtra("QR_TOTAL_AMOUNT", 0L);
List<PayDetail> qrTransList = (List<PayDetail>) intent.getSerializableExtra("QR_TRANS_LIST");
// Create QR settlement PayDetail
SettleData settleData = new SettleData(
qrSaleCount, qrSaleAmount, 0, 0L, qrRefundCount, qrRefundAmount, 0, 0L);
TradeData tradeData = Params.newTrade(false);
PayDetail payDetail = tradeData.getPayDetail();
payDetail.setSettleDataObj(settleData);
payDetail.setTransactionType(TransactionsType.MMQR_SETTLEMENT.value);
payDetail.setTransType(TransactionsType.MMQR_SETTLEMENT.name);
payDetail.setAmount(totalAmount);
payDetail.setTradeAnswerCode("000");
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(totalAmount));
sharedViewModel.payDetails.setValue(qrTransList);
sharedViewModel.payDetail.setValue(payDetail);
sharedViewModel.transactionsType.setValue(TransactionsType.MMQR_SETTLEMENT);
try {
navController.navigate(R.id.transactionResultFragment);
} catch (Exception e) {
LogUtil.e(TAG, "QR Auto Settlement navigation error: " + e.getMessage());
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
// BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
// BaseApplication.getInstance().deviceEngine.getPlatform().enableHomeButton();
// BaseApplication.getInstance().deviceEngine.getPlatform().enableTaskButton();
// Clean up RxJava disposables
compositeDisposable.clear();
// Reset screen mode
// Disconnect ECR
ECRHelper.INSTANCE.disconnect();
BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
}
// Navigation drawer interaction listeners
@ -406,6 +530,12 @@ public class MainActivity extends AppCompatActivity implements
navController.navigate(R.id.inputPasswordFragment);
}
@Override
public void onPause(){
super.onPause();
BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
}
@Override
public void onClickFunction() {
closeDrawer();

View File

@ -20,8 +20,12 @@ import androidx.lifecycle.Observer;
import com.denzcoskun.imageslider.ImageSlider;
import com.denzcoskun.imageslider.constants.ScaleTypes;
import com.denzcoskun.imageslider.models.SlideModel;
import com.nexgo.oaf.apiv3.emv.AidEntity;
import com.nexgo.oaf.apiv3.emv.CapkEntity;
import com.pos.connection.bridge.binder.ECRConstant;
import com.utsmm.kbz.util.MockData;
import com.utsmyanmar.baselib.BaseApplication;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
@ -35,7 +39,9 @@ import com.utsmyanmar.ecr.data.ResultOf;
import com.utsmyanmar.ecr.data.model.Transactions;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.print.PrintHelper;
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.CurrencyType;
@ -43,7 +49,6 @@ 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;
@ -74,6 +79,7 @@ import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.params.Params;
@AndroidEntryPoint
public class MainFragment extends DataBindingFragment {
@ -106,7 +112,6 @@ public class MainFragment extends DataBindingFragment {
return routeId;
}
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
@ -114,7 +119,6 @@ public class MainFragment extends DataBindingFragment {
tmsProcessViewModel = getFragmentScopeViewModel(TMSProcessViewModel.class);
}
@Override
public void onResume() {
super.onResume();
@ -122,9 +126,9 @@ public class MainFragment extends DataBindingFragment {
setNavBarIconWithTitle(getResourceString(R.string.menu_dashboard));
// logcat is resetting cuz of this setup , because it is using serial port
if(SystemParamsOperation.getInstance().getECRStatus()){
// if(SystemParamsOperation.getInstance().getECRStatus()){
// setUpECR();
}
// }
sharedViewModel.isEcrFinished.postValue(true);
sharedViewModel.isEcr.postValue(false);
@ -134,16 +138,41 @@ public class MainFragment extends DataBindingFragment {
sharedViewModel.setAmountExist(false);
sharedViewModel.setCardDataExist(false);
sharedViewModel.setTransMenu(null);
updateButtonStatus();
delayFunctionCall(this::checkTerminalStatus);
delayFunctionCall(()-> {
delayFunctionCall(() -> {
NexGoSDK.getInstance().cancelCheckCard();
NexGoSDK.getInstance().closeReader();
enableHomeButton();
// disableTaskButton();
// BaseApplication.getInstance().deviceEngine.getPlatform().hideNavigationBar();
BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
});
}
private void disableHomeButton() {
int result = BaseApplication.getInstance().deviceEngine.getPlatform().disableHomeButton();
LogUtil.d(TAG, "Disable Home Button Result:" + result);
}
private void disableTaskButton() {
int result = BaseApplication.getInstance().deviceEngine.getPlatform().disableTaskButton();
LogUtil.d(TAG, "Disable Task Button Result:" + result);
}
private void enableHomeButton() {
int result = BaseApplication.getInstance().deviceEngine.getPlatform().enableHomeButton();
LogUtil.d(TAG, "Enable Home Button Result:" + result);
}
private void enableTaskButton() {
int result = BaseApplication.getInstance().deviceEngine.getPlatform().enableTaskButton();
LogUtil.d(TAG, "Disable Task Button Result:" + result);
}
private void checkTerminalStatus() {
if (!SystemParamsOperation.getInstance().isActive()) {
@ -157,7 +186,7 @@ public class MainFragment extends DataBindingFragment {
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(SystemParamsOperation.getInstance().isAlertSound()) {
if (SystemParamsOperation.getInstance().isAlertSound()) {
delayFunctionCall(this::checkPrinter);
}
@ -166,13 +195,8 @@ public class MainFragment extends DataBindingFragment {
mainViewModel.observeSettlementPOS();
}
private void checkDownload() {
Log.d(TAG, "Calling from Check download: ");
if (!SystemParamsOperation.getInstance().isDownloadedParams() && SystemParamsOperation.getInstance().isActive() && tmsProcessViewModel.getIsCalled().getValue() == null) {
@ -187,12 +211,18 @@ public class MainFragment extends DataBindingFragment {
@Override
public void onDestroy() {
super.onDestroy();
// BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
// enableTaskButton();
// enableHomeButton();
}
@Override
public void onPause() {
super.onPause();
// BaseApplication.getInstance().deviceEngine.getPlatform().showNavigationBar();
// enableTaskButton();
// enableHomeButton();
}
@Override
@ -203,11 +233,13 @@ public class MainFragment extends DataBindingFragment {
setUpCarouselImages();
if(TextUtils.equals(SystemParamsOperation.getInstance().getCurrentSerialNum(),"000001")) {
if (TextUtils.equals(SystemParamsOperation.getInstance().getCurrentSerialNum(), "000001")) {
setPreviousTraceNum();
}
sharedViewModel.setManualEntryStatus(SystemParamsOperation.getInstance().getManualEntryStatus());
// generateMockQR();
}
/*
@ -215,22 +247,18 @@ public class MainFragment extends DataBindingFragment {
*
* value - 0 = AID, 1 = CAPK
* */
private void queryAidCAPKList(int value) {
private void queryAidCAPKList() {
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);
List<CapkEntity> capkList = MyApplication.getInstance().deviceEngine.getEmvHandler2("app2").getCapkList();
List<AidEntity> aidList = MyApplication.getInstance().deviceEngine.getEmvHandler2("app2").getAidList();
for (CapkEntity capkEntity : capkList) {
LogUtil.d(TAG, "CAPK Entity :" + capkEntity.getRid());
}
for (AidEntity aidEntity : aidList) {
LogUtil.d(TAG, "AID Entity :" + aidEntity.getAid());
}
}
private void setPreviousTraceNum() {
@ -238,7 +266,7 @@ public class MainFragment extends DataBindingFragment {
mainViewModel.lastTrans.observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
@Override
public void onChanged(PayDetail payDetail) {
if(payDetail == null) {
if (payDetail == null) {
return;
}
@ -254,7 +282,7 @@ public class MainFragment extends DataBindingFragment {
if (checkECRServiceAppExistOrNot()) {
if(!SystemParamsOperation.getInstance().isSetupEcr()){
if (!SystemParamsOperation.getInstance().isSetupEcr()) {
initECR();
delayFunctionCall(this::createECRInstance);
SystemParamsOperation.getInstance().setSetupEcr(true);
@ -272,7 +300,7 @@ public class MainFragment extends DataBindingFragment {
//
// currently will test with Bluetooth , afterward will switch to VSP mode
if(SystemParamsOperation.getInstance().isBluetoothMode()) {
if (SystemParamsOperation.getInstance().isBluetoothMode()) {
Bundle bundle = new Bundle();
bundle.putString(ECRConstant.Configuration.MODE, ECRConstant.Mode.Bluetooth);
bundle.putString(ECRConstant.Configuration.TYPE, ECRConstant.Type.MASTER);
@ -292,7 +320,8 @@ public class MainFragment extends DataBindingFragment {
private void updateButtonStatus() {
mainViewModel.settlementStatus.setValue(SystemParamsOperation.getInstance().getSettlementStatus());
mainViewModel.kPayStatus.setValue(SystemParamsOperation.getInstance().getWavePayStatus());
mainViewModel.kPayStatus.setValue(SystemParamsOperation.getInstance().getQRPayStatus());
mainViewModel.voidStatus.setValue(SystemParamsOperation.getInstance().getVoidStatus());
}
private void setUpCarouselImages() {
@ -301,16 +330,16 @@ public class MainFragment extends DataBindingFragment {
imgList.clear();
if(imgUrls == null || imgUrls.isEmpty() ) {
if (imgUrls == null || imgUrls.isEmpty()) {
String defaultUrl = getResourceString(R.string.txt_default_carousel_img_url);
imgList.add(new SlideModel(defaultUrl,"", ScaleTypes.CENTER_CROP));
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));
for (String url : urls) {
imgList.add(new SlideModel(url.trim(), "", ScaleTypes.CENTER_CROP));
}
@ -318,7 +347,6 @@ public class MainFragment extends DataBindingFragment {
}
private boolean checkECRServiceAppExistOrNot() {
PackageInfo packageInfo;
try {
@ -332,7 +360,6 @@ public class MainFragment extends DataBindingFragment {
}
@Override
protected DataBindingConfig getDataBindingConfig() {
@ -342,11 +369,9 @@ public class MainFragment extends DataBindingFragment {
}
private void checkPrinter() {
if (PrintHelper.getInstance().paperRollStatus() == 2) {
}
else if (PrintHelper.getInstance().paperRollStatus() == 4) {
} else if (PrintHelper.getInstance().paperRollStatus() == 4) {
mainViewModel.playAtOnce.setValue(false);
showPrinterAlertDialog(getResourceString(R.string.txt_paper_roll_not_ready), new DialogCallback() {
@ -362,21 +387,20 @@ public class MainFragment extends DataBindingFragment {
}
});
// startSound(getResourceString(R.string.txt_audio_printer_alert));
} else if (PrintHelper.getInstance().paperRollStatus() == 1) {
} else if (PrintHelper.getInstance().paperRollStatus() == 1) {
if( mainViewModel.playAtOnce.getValue() != null && !mainViewModel.playAtOnce.getValue()) {
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!");
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);
@ -420,7 +444,7 @@ public class MainFragment extends DataBindingFragment {
ECRHelper.INSTANCE.bindECRService();
LogUtil.d(TAG,"Bind ECR Service successfully!");
LogUtil.d(TAG, "Bind ECR Service successfully!");
}
private void onReceivedEcrCommand() {
@ -451,7 +475,7 @@ public class MainFragment extends DataBindingFragment {
String pkgName = BuildConfig.APPLICATION_ID;
String serialNo = TerminalUtil.getInstance().getSerialNo();
ResultOf<Transactions> result = ECRProcess.INSTANCE.parseECRRequest(ecrKey,pkgName,serialNo,msg);
ResultOf<Transactions> result = ECRProcess.INSTANCE.parseECRRequest(ecrKey, pkgName, serialNo, msg);
if (result instanceof ResultOf.Success) {
Transactions trans = ((ResultOf.Success<Transactions>) result).getValue();
@ -472,13 +496,13 @@ public class MainFragment extends DataBindingFragment {
}
break;
case VOID:
if(!SystemParamsOperation.getInstance().getVoidStatus()) {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(trans,"Void is disabled!");
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) {
if (Objects.requireNonNull(getNavController(Constants.NAV_HOST_ID).getCurrentDestination()).getId() == R.id.nav_main) {
setToolBarTitle(getResourceString(R.string.menu_sale_void));
}
@ -503,8 +527,8 @@ public class MainFragment extends DataBindingFragment {
}
case SETTLEMENT: {
if(!SystemParamsOperation.getInstance().getSettlementStatus()) {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(trans,"Settlement is disabled!");
if (!SystemParamsOperation.getInstance().getSettlementStatus()) {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(trans, "Settlement is disabled!");
return;
}
CoreUtils.getInstance(sharedViewModel).setUpECRSettlement();
@ -538,25 +562,25 @@ public class MainFragment extends DataBindingFragment {
mainViewModel.observeSettlementPOS();
observeLastTrans = payDetail -> {
if(payDetail == null) {
if (payDetail == null) {
return;
}
// SystemParamsOperation.getInstance().saveSerialNumber(payDetail.getVoucherNo());
// SystemParamsOperation.getInstance().saveInvoiceNumber(payDetail.getInvoiceNo());
if(lastPay != null) {
if (lastPay != null) {
Date lastPayDate = POSUtil.getInstance().getDateByString(lastPay.getTransDate());
Date observePayDate = POSUtil.getInstance().getDateByString(payDetail.getTransDate());
if(lastPayDate.compareTo(observePayDate) < 0) {
if (lastPayDate.compareTo(observePayDate) < 0) {
payDetail = lastPay;
}
}
// LogUtil.d(TAG,"TransDetail :"+payDetail.getTransType() + "- Trans Time :"+payDetail.getTransDate());
if(payDetail.getTransactionType() == TransactionsType.SETTLEMENT.value){
if (payDetail.getTransactionType() == TransactionsType.SETTLEMENT.value) {
return;
}
@ -580,7 +604,7 @@ public class MainFragment extends DataBindingFragment {
String configRawDay = SystemParamsOperation.getInstance().getClearBatchDay();
if(configRawDay != null && !configRawDay.trim().isEmpty()) {
if (configRawDay != null && !configRawDay.trim().isEmpty()) {
try {
configDay = Integer.parseInt(configRawDay);
} catch (Exception e) {
@ -590,7 +614,7 @@ public class MainFragment extends DataBindingFragment {
}
if(configTimer != null && !configTimer.trim().isEmpty() && checkValidTime(configTimer.trim())) {
if (configTimer != null && !configTimer.trim().isEmpty() && checkValidTime(configTimer.trim())) {
configTime = configTimer.trim();
}
Date configDateTime = POSUtil.getInstance().getDateTime(configTime);
@ -600,22 +624,22 @@ public class MainFragment extends DataBindingFragment {
Date yesterdayDate = POSUtil.getInstance().getYesterdayDate();
if(today.compareTo(transDate) == 0) {
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) {
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() ) {
if (checkSyncTrans() || !SystemParamsOperation.getInstance().isClearBatch()) {
// LogUtil.d(TAG,"Clearing....");
if(!SystemParamsOperation.getInstance().getSettlementStatus()) {
clearBatchAndDownload(configDay,payDetail);
if (!SystemParamsOperation.getInstance().getSettlementStatus()) {
clearBatchAndDownload(configDay, payDetail);
}
}
@ -628,36 +652,35 @@ public class MainFragment extends DataBindingFragment {
} else {
// LogUtil.d(TAG,"Last Trans is Before Today!");
Date yest;
if(configTime.equals("00:00")) {
if (configTime.equals("00:00")) {
yest = configDateTime;
} else {
yest = yesterdayConfigDateTime;
}
Date lastTransDateTime = POSUtil.getInstance().getDateByTransDateTime(lastTransDate,lastTransTime);
Date lastTransDateTime = POSUtil.getInstance().getDateByTransDateTime(lastTransDate, lastTransTime);
// LogUtil.d(TAG,"Compare Result : "+lastTransDateTime.compareTo(yest));
if(yest.compareTo(lastTransDateTime) < 0) {
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 (!SystemParamsOperation.getInstance().getSettlementStatus()) {
clearBatchAndDownload(configDay, payDetail);
}
// }
}
}
};
if(mainViewModel.lastTrans.hasActiveObservers()) {
if (mainViewModel.lastTrans.hasActiveObservers()) {
mainViewModel.lastTrans.removeObserver(observeLastTrans);
}
mainViewModel.lastTrans.observe(getViewLifecycleOwner(),observeLastTrans);
mainViewModel.lastTrans.observe(getViewLifecycleOwner(), observeLastTrans);
}
@ -666,16 +689,16 @@ public class MainFragment extends DataBindingFragment {
mainViewModel.allTrans.observe(getViewLifecycleOwner(), new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
if(payDetails == null || payDetails.isEmpty()) {
if (payDetails == null || payDetails.isEmpty()) {
return;
}
PayDetail tempPay = payDetails.get(0);
for (int i = 0; i < payDetails.size() ; i++) {
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 (tempDate.compareTo(indexDate) > 0) {
// if before
tempPay = payDetails.get(i);
}
@ -698,7 +721,7 @@ public class MainFragment extends DataBindingFragment {
private boolean checkSyncTrans() {
String transDateString = SystemParamsOperation.getInstance().getSyncTransDate();
Date today = POSUtil.getInstance().getCurrentDate();
if(transDateString == null || transDateString.isEmpty()) {
if (transDateString == null || transDateString.isEmpty()) {
return true;
}
Date transDate = POSUtil.getInstance().getDateByString(transDateString);
@ -707,8 +730,7 @@ public class MainFragment extends DataBindingFragment {
}
private void clearBatchAndDownload(int configDay,PayDetail payDetail) {
private void clearBatchAndDownload(int configDay, PayDetail payDetail) {
Date yesterday = POSUtil.getInstance().getYesterdayDate();
@ -717,11 +739,11 @@ public class MainFragment extends DataBindingFragment {
Date transDate;
if(list == null || list.size() == 0) {
if (list == null || list.size() == 0) {
return;
}
for (PayDetail pay:list) {
for (PayDetail pay : list) {
/*
* To Hold One day transaction!
* */
@ -729,11 +751,11 @@ public class MainFragment extends DataBindingFragment {
transDate = POSUtil.getInstance().getDateByString(pay.getTransDate());
if (pay.getTransactionType() == TransactionsType.SALE.value) {
if(lastInputDay.compareTo(transDate) > 0) {
if (lastInputDay.compareTo(transDate) > 0) {
mainViewModel.deletePayDetail(pay);
}
} else {
if(yesterday.compareTo(transDate) > 0 ) {
if (yesterday.compareTo(transDate) > 0) {
mainViewModel.deletePayDetail(pay);
}
}
@ -745,11 +767,11 @@ public class MainFragment extends DataBindingFragment {
mainViewModel.deleteTrans.observe(getViewLifecycleOwner(), lists -> {
Date transDate;
if(lists == null || lists.size() == 0) {
if (lists == null || lists.size() == 0) {
return;
}
for (PayDetail pay:lists) {
for (PayDetail pay : lists) {
/*
* To Hold One day transaction!
* */
@ -759,7 +781,7 @@ public class MainFragment extends DataBindingFragment {
// LogUtil.d(TAG,"Yesterday Date: "+yesterday.toString());
// LogUtil.d(TAG,"Compare result :"+yesterday.compareTo(transDate));
if(yesterday.compareTo(transDate) > 0) {
if (yesterday.compareTo(transDate) > 0) {
mainViewModel.deletePayDetail(pay);
}
@ -768,11 +790,11 @@ public class MainFragment extends DataBindingFragment {
mainViewModel.preAuthTrans.observe(getViewLifecycleOwner(), lists -> {
Date transDate;
if(lists == null || lists.size() == 0) {
if (lists == null || lists.size() == 0) {
return;
}
for (PayDetail pay:lists) {
for (PayDetail pay : lists) {
transDate = POSUtil.getInstance().getDateByString(pay.getTransDate());
@ -788,21 +810,21 @@ public class MainFragment extends DataBindingFragment {
*
* Need to think about his problem .... Nov 7, 2024
* */
if(!SystemParamsOperation.getInstance().isClearBatch()) {
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());
// }
private void generateMockQR() {
String transDate = "24/12/25";
String transTime = "12:06:30";
TradeData tradeData = MockData.getInstance().generateMockDataWithTime(TransactionsType.MMQR, 1, 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 {
@ -812,16 +834,16 @@ public class MainFragment extends DataBindingFragment {
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()) {
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);
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);
safeRouteTo(R.id.nav_main, mainToDashboard, Constants.NAV_HOST_ID);
}
}
@ -830,10 +852,10 @@ public class MainFragment extends DataBindingFragment {
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());
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()) {
} 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);
@ -844,11 +866,23 @@ public class MainFragment extends DataBindingFragment {
} else {
processBatch();
sharedViewModel.transactionsType.setValue(TransactionsType.SALE);
sharedViewModel.setTransMenu(TransMenu.SALE);
sharedViewModel.processCode.postValue(ProcessCode.SALE_PURCHASE + ProcessCode.SMART + ProcessCode.TO_ACCOUNT);
navigateToAmount();
}
}
public void onClickQR() {
if (TMSUtil.getInstance().checkQRParams().isStatus() == ValidityStatus.FAILURE) {
showDeclineDialog(getResourceString(R.string.txt_please_download_config) + "\n" + TMSUtil.getInstance().checkQRParams().getMessage());
} else {
routeId = R.id.action_nav_main_to_qrFragment;
safeNavigateToRouteId();
}
}
public void onClickQRPay() {
String mmqrIp = SystemParamsOperation.getInstance().getSecHostIpAddress();
@ -878,11 +912,13 @@ public class MainFragment extends DataBindingFragment {
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 {
}
// 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);
@ -922,5 +958,24 @@ public class MainFragment extends DataBindingFragment {
safeNavigateToRouteId();
}
}
public void onClickVoid() {
if (mainViewModel.payDetailSingle.getValue() != null) {
mainViewModel.startReversal(mainViewModel.payDetailSingle.getValue());
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.setTransactionsType(TransactionsType.VOID);
// sharedViewModel.transMenu.postValue(TransMenu.TRANSACTIONS);
sharedViewModel.setTransMenu(TransMenu.TRANSACTIONS);
routeId = R.id.action_nav_main_to_inputPasswordFragment;
safeRouteTo(currentId(), routeId, hostId());
}
}
public void onClickReport() {
routeId = R.id.action_nav_main_to_manageFunctionFragment;
safeRouteTo(currentId(), routeId, hostId());
}
}
}

View File

@ -11,6 +11,7 @@ import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModel;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.utsmm.kbz.service.AutoSettleService;
import com.utsmyanmar.baselib.db.model.EmvDetail;
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
@ -22,7 +23,6 @@ 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;
@ -58,6 +58,9 @@ public class MainViewModel extends ViewModel {
public MutableLiveData<Boolean> kPayStatus = new MutableLiveData<>();
public MutableLiveData<Boolean> voidStatus = new MutableLiveData<>();
public SingleLiveEvent<String> disabledMsg = new SingleLiveEvent<>();
public SingleLiveEvent<List<PayDetail>> settlementPOS = new SingleLiveEvent<>();
@ -75,8 +78,8 @@ public class MainViewModel extends ViewModel {
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);
if (intent.getAction().equals(AutoSettleService.ACTION_DATA_RECEIVED)) {
String data = intent.getStringExtra(AutoSettleService.EXTRA_DATA);
}
}
@ -90,13 +93,15 @@ public class MainViewModel extends ViewModel {
playAtOnce.setValue(false);
LocalBroadcastManager.getInstance(context).registerReceiver(dataReceiver,
new IntentFilter(SmileSettleService.ACTION_DATA_RECEIVED));
new IntentFilter(AutoSettleService.ACTION_DATA_RECEIVED));
settlementStatus.setValue(SystemParamsOperation.getInstance().getSettlementStatus());
kPayStatus.setValue(SystemParamsOperation.getInstance().getWavePayStatus());
kPayStatus.setValue(SystemParamsOperation.getInstance().getQRPayStatus());
disabledMsg.setValue(SystemParamsOperation.getInstance().getDisabledMsg());
voidStatus.setValue(SystemParamsOperation.getInstance().getVoidStatus());
}
@Override

View File

@ -5,5 +5,6 @@ public enum CardTransactionType {
MPU,
EMV,
MAG,
FALLBACK
FALLBACK,
MOCK
}

View File

@ -0,0 +1,156 @@
package com.utsmm.kbz.service;
import android.app.AlarmManager;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.PowerManager;
import androidx.core.app.NotificationCompat;
import com.utsmm.kbz.R;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import java.util.Calendar;
public class AutoAlarmReceiver extends BroadcastReceiver {
private static final String TAG = AutoAlarmReceiver.class.getSimpleName();
private static final String WAKE_LOCK_TAG = "KBZAutoSettle::AlarmWakeLock";
private static final String NOTIFICATION_CHANNEL_ID = "AUTO_SETTLEMENT_ALARM";
@Override
public void onReceive(Context context, Intent intent) {
LogUtil.d(TAG, "AutoAlarmReceiver triggered at: " + new java.util.Date().toString());
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG);
wakeLock.acquire(60000);
try {
showAlarmTriggeredNotification(context);
scheduleNextDayAlarm(context);
try {
Intent serviceIntent = new Intent(context, AutoSettleService.class);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
context.startForegroundService(serviceIntent);
LogUtil.d(TAG, "AutoSettleService started as foreground service");
} else {
context.startService(serviceIntent);
LogUtil.d(TAG, "AutoSettleService started successfully");
}
} catch (Exception e) {
LogUtil.e(TAG, "Failed to start AutoSettleService: " + e.getMessage());
e.printStackTrace();
}
} finally {
// Release wake lock
if (wakeLock.isHeld()) {
wakeLock.release();
}
}
}
private void scheduleNextDayAlarm(Context context) {
try {
String timeStr = SystemParamsOperation.getInstance().getClearBatchTime();
LogUtil.d(TAG, " Rescheduling next day's alarm for timeStr: " + timeStr);
if (timeStr == null || timeStr.trim().isEmpty()) {
LogUtil.d(TAG, "Clear batch time is empty, cannot reschedule");
return;
}
String[] parts = timeStr.trim().split(":");
if (parts.length != 2) {
LogUtil.d(TAG, "Invalid time format: " + timeStr);
return;
}
int hour = Integer.parseInt(parts[0]);
int minute = Integer.parseInt(parts[1]);
// Validate time range
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
LogUtil.d(TAG, "Invalid time values - hour: " + hour + ", minute: " + minute);
return;
}
// Set up next day's alarm
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_YEAR, 1); // Next day
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
long nextTriggerTime = calendar.getTimeInMillis();
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
if (alarmManager == null) {
LogUtil.e(TAG, "AlarmManager is null, cannot reschedule");
return;
}
Intent intent = new Intent(context, AutoAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
1001,
intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
if (alarmManager.canScheduleExactAlarms()) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextTriggerTime, pendingIntent);
} else {
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextTriggerTime, pendingIntent);
}
} else {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, nextTriggerTime, pendingIntent);
}
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, nextTriggerTime, pendingIntent);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void showAlarmTriggeredNotification(Context context) {
try {
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID,
"Auto Settlement Alarms",
NotificationManager.IMPORTANCE_HIGH
);
channel.setDescription("Notifications for auto settlement alarm triggers");
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Auto Settlement Triggered")
.setContentText("Auto settlement alarm triggered at " + new java.util.Date().toString())
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true);
notificationManager.notify(1001, builder.build());
} catch (Exception e) {
LogUtil.e(TAG, "Failed to show alarm notification: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,573 @@
package com.utsmm.kbz.service;
import android.annotation.SuppressLint;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.lifecycle.Observer;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import com.google.gson.Gson;
import com.utsmm.kbz.MainActivity;
import com.utsmm.kbz.util.EReceiptUtil;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
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 io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.schedulers.Schedulers;
import retrofit2.HttpException;
import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.isobuilder.ISOMode;
import com.utsmyanmar.paylibs.isobuilder.builderx.ISOMsgX;
import com.utsmyanmar.paylibs.isobuilder.builderx.ISOVersion;
import com.utsmyanmar.paylibs.model.MsgField;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.QRSettleData;
import com.utsmyanmar.paylibs.model.SettleData;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.network.ISOCallback;
import com.utsmyanmar.paylibs.network.ISOSocket;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.MessageType;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.HostName;
import com.utsmyanmar.paylibs.utils.iso_utils.BitmapConfig;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionType;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmyanmar.paylibs.utils.params.Params;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@AndroidEntryPoint
public class AutoSettleService extends Service {
private static final String TAG = AutoSettleService.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;
// Flags to prevent infinite loops
private boolean regularSettlementCompleted = false;
private boolean qrSettlementCompleted = false;
// Observers to keep reference for cleanup
private Observer<java.util.List<com.utsmyanmar.paylibs.model.PayDetail>> regularSettlementObserver;
private Observer<java.util.List<com.utsmyanmar.paylibs.model.PayDetail>> qrSettlementObserver;
@Inject
Repository repository;
public static final String NOTIFICATION_CHANNEL_ID = "10001";
private final static String default_notification_channel_id = "default";
private void startForegroundService() {
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// Create notification channel for Android 8+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
NOTIFICATION_CHANNEL_ID,
"Auto Settlement Service",
NotificationManager.IMPORTANCE_LOW // Use LOW importance for foreground service
);
channel.setDescription("Auto settlement background service");
notificationManager.createNotificationChannel(channel);
}
// Create foreground notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Auto Settlement Active")
.setContentText("Processing scheduled settlement...")
.setPriority(NotificationCompat.PRIORITY_LOW)
.setOngoing(true) // Make it non-dismissible
.setAutoCancel(false);
// Start foreground service
startForeground(1002, builder.build());
}
private void createNotification() {
NotificationManager mNotificationManager = (NotificationManager)getSystemService( NOTIFICATION_SERVICE ) ;
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext() , default_notification_channel_id ) ;
mBuilder.setContentTitle( "Auto Settlement Running" ) ;
mBuilder.setContentText( "Processing transactions..." ) ;
mBuilder.setTicker( "Auto Settlement Service" ) ;
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 , "AUTO_SETTLEMENT_CHANNEL" , 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) {
LogUtil.d(TAG, "<<<<<<<<<<<<<<< Auto Settlement Service Started >>>>>>>>>>>>>>>>.");
try {
// Start as foreground service for Android 8+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
startForegroundService();
}
sendDataToViewModel("Auto settlement initiated");
// Also create regular notification
createNotification();
if (SystemParamsOperation.getInstance().getSettlementStatus()) {
performSettlement();
// regularSettlementCompleted = true;
performQRSettlement();
} else {
LogUtil.d(TAG, "Settlement is disabled in system parameters");
stopSelf();
}
} catch (Exception e) {
LogUtil.e(TAG, "Error in onStartCommand: " + e.getMessage());
e.printStackTrace();
stopSelf();
}
return START_NOT_STICKY;
}
private void performSettlement() {
if (regularSettlementCompleted) {
return;
}
final ISOMsgX isoMsgX = new ISOMsgX.ISOMsgXBuilder(
ISOVersion.VERSION_1993,
ISOMode.BOTH_HEADER_TPDU,
HostName.BPC
).build();
regularSettlementObserver = new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> list) {
if (regularSettlementCompleted) {
return;
}
regularSettlementCompleted = true;
repository.getSettlementPOS().removeObserver(this);
int saleCount = 0;
long saleAmount = 0L;
int preCount = 0;
long preAmount = 0L;
int refundCount = 0;
long refundAmount = 0L;
int caCount = 0;
long caAmount = 0L;
if (list != null && !list.isEmpty()) {
for (PayDetail pay : list) {
if (pay.getTransactionType() == TransactionType.SALE && !pay.isCanceled) {
saleCount++;
saleAmount += pay.getAmount();
} else if (pay.getTransactionType() == TransactionType.PRE_SALE_COMPLETE && !pay.isCanceled) {
preCount++;
preAmount += pay.getAmount();
} else if (pay.getTransactionType() == TransactionType.REFUND) {
refundCount++;
refundAmount += pay.getAmount();
} else if (pay.getTransactionType() == TransactionType.CASH_ADVANCE) {
caCount++;
caAmount += pay.getAmount();
}
}
}
TradeData tradeData = Params.newTrade(true);
PayDetail payDetail = tradeData.getPayDetail();
String bitmap = BitmapConfig.BPC_SETTLEMENT;
payDetail.setTransType(TransactionsType.SETTLEMENT.name);
payDetail.setTransactionType(TransactionType.SETTLEMENT);
payDetail.setProcessCode(TransactionsType.SETTLEMENT.processCode);
payDetail.setBatchNo(SystemParamsOperation.getInstance().getCurrentBatchNum());
SettleData settleData = new SettleData(
saleCount, saleAmount, preCount, preAmount, refundCount, refundAmount, caCount, caAmount);
payDetail.setSettleDataObj(settleData);
long totalAmount = saleAmount + preAmount + refundAmount + caAmount;
String settlementData;
if (refundAmount != 0L) {
long creditTotal = saleAmount + preAmount + caAmount;
long subTotal = creditTotal - refundAmount;
if (subTotal < 0L) {
settlementData = "D" + String.format(Locale.getDefault(), "%012d", Math.abs(subTotal));
} else {
settlementData = "C" + String.format(Locale.getDefault(), "%012d", subTotal);
}
} else {
settlementData = "C" + String.format(Locale.getDefault(), "%012d", totalAmount);
}
payDetail.setSettleData(settlementData);
payDetail.setAmount(totalAmount);
tradeData.setPayDetail(payDetail);
tradeData.setField60(SystemParamsOperation.getInstance().getCurrentBatchNum());
byte[] sendBytes = isoMsgX.buildISOPackets(tradeData, bitmap, MessageType.SETTLEMENT);
ISOSocket.getInstance().enqueue(sendBytes, sendBytes.length, false, new ISOCallback() {
@Override
public void onReceive(byte[] bytes, int length) {
Map<String, MsgField> responseMap = isoMsgX.parseISOPackets(bytes, length);
if (responseMap != null) {
String resultStr = "";
try {
resultStr = responseMap.get("F039").getDataStr();
} catch (NullPointerException e) {
e.printStackTrace();
payDetail.setIsNeedReversal(true);
return;
}
payDetail.setTradeAnswerCode(resultStr);
if (TextUtils.equals(resultStr, Constant.ANSWER_CODE_ACCEPT) || TextUtils.equals(resultStr, Constant.ANSWER_CODE_APPROVED)) {
payDetail.setIsNeedReversal(false);
} else if (TextUtils.equals(resultStr, "95") || TextUtils.equals(resultStr, "095")) {
payDetail.setIsNeedReversal(true);
}
}
}
@Override
public void onError(String msg) {
ISOSocket.getInstance().switchIp();
ISOSocket.getInstance().enqueue(sendBytes, sendBytes.length, false, this);
}
@Override
public void onComplete() {
LogUtil.d(TAG, "Auto settlement transaction completed successfully");
if (list != null && !list.isEmpty()) {
for (PayDetail p : list) {
repository.deletePayDetail(p);
}
}
repository.insertPayDetail(payDetail);
try {
PayDetail cleanPayDetail = new PayDetail();
cleanPayDetail.setTransType(payDetail.getTransType());
cleanPayDetail.setTransactionType(payDetail.getTransactionType());
cleanPayDetail.setProcessCode(payDetail.getProcessCode());
cleanPayDetail.setBatchNo(payDetail.getBatchNo());
cleanPayDetail.setSettleData(payDetail.getSettleData());
cleanPayDetail.setAmount(payDetail.getAmount());
cleanPayDetail.setTradeAnswerCode(payDetail.getTradeAnswerCode());
cleanPayDetail.setIsNeedReversal(payDetail.getIsNeedReversal());
// Use notification-based approach to reliably launch the app
launchAppWithSettlementResult("AUTO_SETTLEMENT", cleanPayDetail, null);
} catch (Exception e) {
LogUtil.e(TAG, "Error launching app with settlement result: " + e.getMessage());
e.printStackTrace();
}
checkIfBothSettlementsComplete();
}
});
}
};
repository.getSettlementPOS().observeForever(regularSettlementObserver);
}
private void performQRSettlement() {
if (qrSettlementCompleted) {
return;
}
qrSettlementObserver = new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetailList) {
if (qrSettlementCompleted) {
return;
}
qrSettlementCompleted = true;
repository.getTransactionHistory().removeObserver(this);
if (payDetailList != null) {
int qrSaleCount = 0;
long qrSaleAmount = 0;
int qrRefundCount = 0;
long qrRefundAmount = 0;
ArrayList<PayDetail> qrTransactionsList = new ArrayList<>();
ArrayList<PayDetail> qrTransListAll = new ArrayList<>();
try {
for (PayDetail payDetail : payDetailList) {
if ((payDetail.getTransactionType() == TransactionsType.MMQR.value
|| payDetail.getTransactionType() == TransactionsType.MMQR_REFUND.value)
&& payDetail.getQrTransStatus() == 1) {
qrTransactionsList.add(payDetail);
if (payDetail.getTransactionType() == TransactionsType.MMQR.value) {
qrSaleCount++;
qrSaleAmount += payDetail.getAmount();
} else if (payDetail.getTransactionType() == TransactionsType.MMQR_REFUND.value) {
qrRefundCount++;
qrRefundAmount += payDetail.getAmount();
}
} else if (payDetail.getTransactionType() == TransactionsType.MMQR.value
|| payDetail.getTransactionType() == TransactionsType.MMQR_REFUND.value) {
qrTransListAll.add(payDetail);
}
}
} catch (IllegalStateException e) {
LogUtil.e(TAG, "QR Auto Settlement: Database cursor error - likely due to large data size: " + e);
checkIfBothSettlementsComplete();
return;
}
if (!qrTransactionsList.isEmpty()) {
LogUtil.d(TAG, "Processing QR Auto Settlement with " + qrTransactionsList.size() + " transactions");
long totalAmount = qrSaleAmount - qrRefundAmount;
// Increment batch number for QR settlement
SystemParamsOperation.getInstance().getIncrementBatchNo();
// Create settlement data for QR transactions
SettleData settleData = new SettleData(
qrSaleCount, qrSaleAmount, 0, 0L, qrRefundCount, qrRefundAmount, 0, 0L);
TradeData tradeData = Params.newTrade(false);
PayDetail payDetail = tradeData.getPayDetail();
payDetail.setSettleDataObj(settleData);
payDetail.setTransactionType(TransactionsType.MMQR_SETTLEMENT.value);
payDetail.setTransType(TransactionsType.MMQR_SETTLEMENT.name);
payDetail.setAmount(totalAmount);
payDetail.setTradeAnswerCode("000");
payDetail.setBatchNo(SystemParamsOperation.getInstance().getCurrentBatchNum());
payDetail.setQrSettleData(QRSettleData.convertFromPayDetail(qrTransactionsList));
// Insert QR settlement record
repository.insertPayDetail(payDetail);
// Delete settled QR transactions
for (PayDetail pay : qrTransactionsList) {
repository.deletePayDetail(pay);
}
// Delete all other QR transactions (failed ones)
for (PayDetail pay : qrTransListAll) {
repository.deletePayDetail(pay);
}
// Push e-receipt data using repository directly
try {
EReceiptRequest request = EReceiptUtil.getInstance().generateQRSettlement(payDetail, QRSettleData.convertFromPayDetail(qrTransactionsList));
sendEReceipt(request);
LogUtil.d(TAG, "QR Settlement e-receipt data prepared and sent");
} catch (Exception e) {
LogUtil.e(TAG, "Error preparing QR settlement e-receipt: " + e.getMessage());
}
try {
// Create QR settlement data bundle
Bundle qrData = new Bundle();
qrData.putInt("QR_SALE_COUNT", qrSaleCount);
qrData.putLong("QR_SALE_AMOUNT", qrSaleAmount);
qrData.putInt("QR_REFUND_COUNT", qrRefundCount);
qrData.putLong("QR_REFUND_AMOUNT", qrRefundAmount);
qrData.putLong("QR_TOTAL_AMOUNT", totalAmount);
qrData.putSerializable("QR_TRANS_LIST", qrTransactionsList);
// Use notification-based approach to reliably launch the app
launchAppWithSettlementResult("AUTO_QR_SETTLEMENT", null, qrData);
} catch (Exception e) {
LogUtil.e(TAG, "Error launching app for QR settlement: " + e.getMessage());
e.printStackTrace();
}
LogUtil.d(TAG, "QR Auto Settlement completed successfully");
} else {
LogUtil.d(TAG, "No QR transactions found for auto settlement");
}
}
checkIfBothSettlementsComplete();
}
};
repository.getTransactionHistory().observeForever(qrSettlementObserver);
}
private void checkIfBothSettlementsComplete() {
if (regularSettlementCompleted && qrSettlementCompleted) {
LogUtil.d(TAG, "Both settlements completed, stopping service");
stopSelf();
}
}
@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);
}
@Override
public void onDestroy() {
super.onDestroy();
// Clean up observers to prevent memory leaks
if (regularSettlementObserver != null && repository != null) {
repository.getSettlementPOS().removeObserver(regularSettlementObserver);
}
if (qrSettlementObserver != null && repository != null) {
repository.getTransactionHistory().removeObserver(qrSettlementObserver);
}
}
private void launchAppWithSettlementResult(String settlementType,
PayDetail payDetail,
Bundle qrData) {
try {
Intent launchIntent = new Intent(this, MainActivity.class);
launchIntent.putExtra(settlementType, true);
if ("AUTO_SETTLEMENT".equals(settlementType) && payDetail != null) {
launchIntent.putExtra("EXTRA_TRANSACTION_TYPE", TransactionsType.SETTLEMENT.value);
launchIntent.putExtra("EXTRA_PAY_DETAIL", payDetail);
} else if ("AUTO_QR_SETTLEMENT".equals(settlementType) && qrData != null) {
launchIntent.putExtra("EXTRA_TRANSACTION_TYPE", TransactionsType.MMQR_SETTLEMENT.value);
launchIntent.putExtras(qrData);
}
PendingIntent pendingIntent = PendingIntent.getActivity(
this,
(int) System.currentTimeMillis(),
launchIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
"SETTLEMENT_COMPLETE",
"Settlement Complete",
NotificationManager.IMPORTANCE_HIGH
);
channel.setDescription("Auto settlement completion notifications");
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "SETTLEMENT_COMPLETE")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Auto Settlement Complete")
.setContentText("Tap to view settlement results and print receipt")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.setFullScreenIntent(pendingIntent, true);
notificationManager.notify(2001, builder.build());
LogUtil.d(TAG, " Settlement complete notification created - will launch app when tapped");
try {
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP |
Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
startActivity(launchIntent);
} catch (Exception directException) {
LogUtil.d(TAG, "Direct launch failed (expected on modern Android), notification approach will handle it");
}
} catch (Exception e) {
LogUtil.e(TAG, "Error creating settlement notification: " + e.getMessage());
e.printStackTrace();
}
}
private void sendEReceipt(EReceiptRequest request) {
try {
LogUtil.d(TAG, "Sending e-receipt: " + new Gson().toJson(request));
repository.sendReceipt(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> LogUtil.d(TAG, "E-Receipt sent successfully: " + response.getMessage()),
error -> {
if (error instanceof HttpException) {
HttpException httpEx = (HttpException) error;
try {
String errorJson = httpEx.response().errorBody().string();
LogUtil.e(TAG, "E-Receipt error: " + errorJson);
} catch (Exception e) {
LogUtil.e(TAG, "E-Receipt send failed: " + error.getMessage());
}
} else {
LogUtil.e(TAG, "E-Receipt send failed: " + error.getMessage());
}
}
);
} catch (Exception e) {
LogUtil.e(TAG, "Error sending e-receipt: " + e.getMessage());
}
}
}

View File

@ -1,14 +0,0 @@
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

@ -1,183 +0,0 @@
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

@ -1,17 +1,24 @@
package com.utsmm.kbz.ui;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Toast;
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.utsmm.kbz.config.Constants;
import com.nexgo.downloadkey.downloadflow.DownloadFEntity;
import com.nexgo.downloadkey.downloadflow.DownloadFlow;
import com.nexgo.downloadkey.downloadflow.DownloadFlowProcessListener;
import com.nexgo.downloadkey.downloadflow.DownloadFlowResultEntity;
import com.nexgo.downloadkey.downloadflow.DownloadResult;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.sirius.SiriusError;
@ -50,7 +57,7 @@ public class SettingsFragment extends DataBindingFragment {
private MainViewModel mainViewModel;
private int count = 0;
// Data binding will handle view access automatically
private FragmentSettingsModernBinding binding;
@Inject
@ -58,14 +65,12 @@ public class SettingsFragment extends DataBindingFragment {
@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());
}
@ -89,30 +94,23 @@ public class SettingsFragment extends DataBindingFragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
try {
LogUtil.d(TAG, "onViewCreated called");
SystemParamsOperation.getInstance().setDemoStatus(false);
// Get the binding from the base class - this is automatically created
binding = (FragmentSettingsModernBinding) mBinding;
updateDemoSettings();
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());
}
setToolBarTitleWithBackIcon("Settings");
}
@ -144,35 +142,34 @@ public class SettingsFragment extends DataBindingFragment {
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");
// 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");
// 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");
// 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");
// binding.multiHostSwitch.setChecked(isEnabled);
// binding.multiHostSummary.setText(isEnabled ?
// "Multiple host support enabled" :
// "Single host mode - Primary host only");
}
private void updateTmsAddressSettings() {
@ -183,6 +180,12 @@ public class SettingsFragment extends DataBindingFragment {
// ClickEvent class for data binding - this is the proper pattern
public class ClickEvent {
public void onHostConfigClick(){
int routeId = R.id.action_nav_settings_to_hostConfigFragment;
int currentId = R.id.nav_settings;
int hostId = Constants.NAV_HOST_ID;
safeRouteTo(currentId, routeId, hostId);
}
public void onVersionClick() {
try {
@ -197,6 +200,16 @@ public class SettingsFragment extends DataBindingFragment {
}
}
public void onInjectKeyClick() {
try {
LogUtil.d(TAG, "Inject Key clicked");
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
.navigate(R.id.action_nav_settings_to_injectKeyFragment);
} catch (Exception e) {
LogUtil.e(TAG, "Error navigating to inject key: " + e.getMessage());
}
}
public void onDemoClick() {
try {
boolean newValue = !SystemParamsOperation.getInstance().getDemoStatus();
@ -278,7 +291,6 @@ public class SettingsFragment extends DataBindingFragment {
public void onUpdateConfigClick() {
try {
LogUtil.d(TAG, "Update config clicked");
settlementViewModel.getSettlementPOS().observe(getViewLifecycleOwner(), payDetails -> {
try {
if (payDetails != null && payDetails.size() > 0) {

View File

@ -3,6 +3,8 @@ package com.utsmm.kbz.ui.adapters;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.graphics.PorterDuff;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
@ -294,9 +296,12 @@ public class MyBindingAdapter {
@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());
// textView.setText("INV:"+payDetail.getInvoiceNo());
//tempo fix for qr trace num
textView.setText("TRC:"+payDetail.getVoucherNo());
} else {
textView.setText("TRC:"+payDetail.getVoucherNo());
}
}
}

View File

@ -0,0 +1,78 @@
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.recyclerview.widget.RecyclerView;
import com.utsmm.kbz.R;
import com.utsmm.kbz.databinding.ItemQrPayButtonBinding;
import com.utsmm.kbz.ui.qr_pay.QRPayItem;
import java.util.List;
public class QRPayAdapter extends RecyclerView.Adapter<QRPayAdapter.ViewHolder> {
public interface OnItemClickListener {
void onItemClick(int position);
}
private final List<QRPayItem> items;
private final OnItemClickListener listener;
public QRPayAdapter(List<QRPayItem> item, OnItemClickListener listener) {
this.items = item;
this.listener = listener;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemQrPayButtonBinding binding = DataBindingUtil.inflate(
LayoutInflater.from(parent.getContext()),
R.layout.item_qr_pay_button,
parent,
false
);
return new ViewHolder(binding);
}
private final int[] colors = new int[]{
R.color.colorPrimary,
R.color.amber,
R.color.forestGreen
};
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
QRPayItem item = items.get(position);
holder.binding.setItem(item);
holder.binding.executePendingBindings();
holder.binding.btnItem.setOnClickListener(v -> {
if(item.isActive && listener != null){
listener.onItemClick(position);
}
});
}
@Override
public int getItemCount() {
return items == null ? 0 : items.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
final ItemQrPayButtonBinding binding;
public ViewHolder(@NonNull ItemQrPayButtonBinding binding) {
super(binding.getRoot());
this.binding = binding;
}
}
}

View File

@ -8,11 +8,19 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum;
import com.utsmm.kbz.ui.pinpad.PinPadViewModel;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TerminalUtil;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.checkxread.checkcard.CheckCardResultX;
import com.utsmyanmar.checkxread.model.CardDataX;
import com.utsmyanmar.checkxread.readcard.MPUXReadCard;
import com.utsmyanmar.checkxread.readcard.ReadCardResultX;
import com.utsmyanmar.checkxread.sdk.NexGoSDK;
import com.utsmyanmar.checkxread.util.CardTypeX;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.BR;
@ -37,6 +45,8 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind
private TransProcessViewModel transProcessViewModel;
private PinPadViewModel pinPadViewModel;
private static final String TAG = CardWaitingFragment.class.getSimpleName();
private static final int cardWaitingTimeOut = 60;
@ -59,6 +69,8 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind
transProcessViewModel = getFragmentScopeViewModel(TransProcessViewModel.class);
pinPadViewModel = getFragmentScopeViewModel(PinPadViewModel.class);
}
@Override
@ -106,11 +118,15 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind
public void onClickManualEntry() {
// showSingleInfoDialogAutoHide("Coming Soon!");
routeId = R.id.action_cardWaitingFragment_to_manualEntryFragment;
safeNavigateToRouteId();
}
public void onClickTap() {
cardReadViewModel.setCardTransactionType(CardTransactionType.MOCK);
routeId = R.id.action_cardWaitingFragment_to_processingCardFragment;
safeNavigateToRouteId();
}
}
@Override
@ -232,6 +248,7 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind
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) {
@ -258,13 +275,16 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind
cardReadViewModel.setCardTransactionType(CardTransactionType.FALLBACK);
} else if (cardType == CardTypeX.IC || cardType == CardTypeX.NFC) {
cardReadViewModel.cardTypeData.postValue(cardType.value);
if(isMPU) {
sharedViewModel.isEmv.setValue(false);
cardReadViewModel.setCardTransactionType(CardTransactionType.MPU);
} else {
cardReadViewModel.cardTypeData.postValue(cardType.value);
// cardReadViewModel.cardTypeData.postValue(cardType.value);
cardReadViewModel.setCardTransactionType(CardTransactionType.EMV);
}
// cardReadViewModel.cardTypeData.postValue(cardType.value);
// cardReadViewModel.setCardTransactionType(CardTransactionType.EMV);
}
delayFunctionCall(()->{
routeId = R.id.action_cardWaitingFragment_to_processingCardFragment;

View File

@ -1,295 +0,0 @@
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

@ -16,6 +16,7 @@ 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.sdk.NexGoSDK;
import com.utsmyanmar.checkxread.util.CardTypeX;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
@ -134,6 +135,8 @@ public class EmvTransactionFragment extends DataBindingFragment {
emvTransactionViewModel.customPinPadKeyboard = binding.customPinPad;
initSharedData();
initData();

View File

@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.ui.NumberKeyboard;
import com.utsmyanmar.baselib.util.CardDetectCallback;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
@ -71,7 +72,7 @@ public class InputAmountFragment extends DataBindingFragment implements DataBind
super.onViewCreated(view, savedInstanceState);
setUpTimer();
// setUpTimer();
setupBackButtonPressDetection(this);
}
@ -98,6 +99,22 @@ public class InputAmountFragment extends DataBindingFragment implements DataBind
setToolBarTitleWithBackIcon(getResourceString(R.string.txt_subtitle_amount));
boolean decimalEnabled = SystemParamsOperation.getInstance().getDecimalEnable();
boolean qrDecimalEnabled = SystemParamsOperation.getInstance().isQrDecimalEnable();
boolean isDecimalEnabled;
if(sharedViewModel.transactionsType.getValue() == TransactionsType.MMQR){
isDecimalEnabled = qrDecimalEnabled;
}else {
isDecimalEnabled = decimalEnabled;
}
View keyboardView = getView().findViewById(R.id.numberKeyboard);
if (keyboardView instanceof NumberKeyboard) {
((NumberKeyboard) keyboardView).setDecimalEnable(isDecimalEnabled);
}
if(sharedViewModel.isEcr.getValue() != null){
if(sharedViewModel.isEcr.getValue()){
@ -204,7 +221,17 @@ public class InputAmountFragment extends DataBindingFragment implements DataBind
if(isInputValid(Objects.requireNonNull(inputAmountViewModel.inputAmountView.getValue()))){
inputAmountViewModel.invalidAmountMsg.setValue("");
boolean decimalEnabled = SystemParamsOperation.getInstance().getDecimalEnable();
// boolean decimalEnabled = SystemParamsOperation.getInstance().getDecimalEnable();
boolean cardDecimalEnabled = SystemParamsOperation.getInstance().getDecimalEnable();
boolean qrDecimalEnabled = SystemParamsOperation.getInstance().isQrDecimalEnable();
boolean decimalEnabled;
if(sharedViewModel.transactionsType.getValue() == TransactionsType.MMQR){
decimalEnabled = qrDecimalEnabled;
}else {
decimalEnabled = cardDecimalEnabled;
}
String inputValue = inputAmountViewModel.inputAmountView.getValue();
if (decimalEnabled) {

View File

@ -142,6 +142,10 @@ public class InputPasswordFragment extends DataBindingFragment implements DataBi
private void checkRoute() {
switch (Objects.requireNonNull(sharedViewModel.transactionsType.getValue())) {
case MMQR_REFUND:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
routeId = R.id.action_inputPasswordFragment_to_QRRefundProcessFragment;
break;
case PRE_AUTH_COMPLETE_VOID:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
sharedViewModel.transactionName.postValue(getResourceString(R.string.title_pre_auth_complete));
@ -172,7 +176,7 @@ public class InputPasswordFragment extends DataBindingFragment implements DataBi
break;
case REFUND:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
routeId = R.id.action_inputPasswordFragment_to_selectRefundFragment;
routeId = R.id.action_inputPasswordFragment_to_inputAmountFragment;
break;
case PRE_AUTH_COMPLETE:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SYSTEM);
@ -180,7 +184,7 @@ public class InputPasswordFragment extends DataBindingFragment implements DataBi
break;
case SETTLEMENT:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SETTLEMENT);
routeId = R.id.action_inputPasswordFragment_to_settlementTransactionFragment;
routeId = R.id.action_inputPasswordFragment_to_selectSettlementFragment;
break;
case SETTING:
inputPasswordViewModel.passwordType.setValue(InputPasswordType.SETTING);

View File

@ -220,11 +220,13 @@ public class InputRRNFragment extends DataBindingFragment {
newPay = transProcessViewModel.getPayDetail();
}
newPay.setReferNo(rrnNo);
if(sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_FULL_VOID) {
newPay.setAmount(payDetail.getAmount());
}
}
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountFormat(payDetail.getAmount()));
newPay.setTradeDateTime(payDetail.getTradeDateTime());
if(isEmvTrans()) {
@ -311,7 +313,9 @@ public class InputRRNFragment extends DataBindingFragment {
}
newPay.setReferNo(rrnNo);
newPay.setApprovalCode(payDetail.getApprovalCode());
newPay.setTradeTime(payDetail.getTradeTime());
newPay.setTradeDate(payDetail.getTradeDate());
if(newPay.getAmount() > payDetail.getAmount()) {
newPay.setTradeAnswerCode("C1"); // ---> refer to BaseErrorCode class// ,
newPay.setTransType(sharedViewModel.transactionsType.getValue().name);
@ -522,7 +526,7 @@ public class InputRRNFragment extends DataBindingFragment {
String date = payDetail.getTransDate();
String time = payDetail.getTransTime();
if(checkRefund(configTime,date,time)) {
// if(checkRefund(configTime,date,time)) {
PayDetail newPay = transProcessViewModel.getPayDetail();
newPay.setReferNo(rrnNo);
@ -533,9 +537,9 @@ public class InputRRNFragment extends DataBindingFragment {
callNextScreen();
} else {
terminatedTransRefund(isECR);
}
// } else {
// terminatedTransRefund(isECR);
// }
} else {

View File

@ -299,7 +299,7 @@ public class InputTraceNoFragment extends DataBindingFragment {
if(sharedViewModel.hostType.getValue() == HostType.MPU) {
sharedViewModel.isEmv.setValue(false);
transProcessViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
transProcessViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
transProcessViewModel.setOldTransPayDetail(payDetail);
transProcessViewModel.setPayDetail(payDetail);
} else {

View File

@ -17,7 +17,6 @@ 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;
@ -28,7 +27,8 @@ 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();
private static final String TAG = PrintReceiptFragment.class.getSimpleName();
private boolean printerEnabled = SystemParamsOperation.getInstance().getPrinterEnabled();
@Override
protected int currentId() {
@ -49,7 +49,6 @@ public class PrintReceiptFragment extends DataBindingFragment implements DataBin
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
@ -77,6 +76,7 @@ public class PrintReceiptFragment extends DataBindingFragment implements DataBin
setToolBarTitleWithoutBackIcon(getResourceString(R.string.title_print_receipt));
sharedViewModel.printReceiptButtons.setValue(0);
sharedViewModel.printerDisabled.setValue(printerEnabled);
PayDetail payDetail = sharedViewModel.payDetail.getValue();
@ -124,6 +124,13 @@ public class PrintReceiptFragment extends DataBindingFragment implements DataBin
sharedViewModel.setPrintStatus(PrintStatus.FIRST_PRINT);
if(!printerEnabled){
sharedViewModel.postPrintReceiptMsg("Receipt is saved as E-receipt!");
}
// else{
// sharedViewModel.postPrintReceiptMsg("Print Receipt for Merchant?");
// }
observePrintProcess();
setBackPressCallback(this);
@ -139,8 +146,11 @@ public class PrintReceiptFragment extends DataBindingFragment implements DataBin
case FIRST_PRINT:
sharedViewModel.postPrintReceiptMsg("Printing Receipt for Merchant");
startPrintProcess(true);
// sharedViewModel.postPrintReceiptMsg("Print Receipt for Customer?");
// sharedViewModel.setVisibilityPrintReceiptButtons(0);
break;
case FIRST_PRINT_DONE:
// sharedViewModel.postPrintReceiptMsg("Print Receipt for Customer?");
sharedViewModel.postPrintReceiptMsg("Confirm Print Receipt for Customer");
if(sharedViewModel.isEcr.getValue() != null &&
sharedViewModel.isEcr.getValue() &&
@ -215,7 +225,6 @@ public class PrintReceiptFragment extends DataBindingFragment implements DataBin
@Override
public void onClickCancel() {
dismissPrinterAlertDialog();
}
@Override
public void onClickRetry() {
@ -248,16 +257,39 @@ public class PrintReceiptFragment extends DataBindingFragment implements DataBin
public class ClickEvent {
public void onConfirm() {
// PrintStatus printStatus = sharedViewModel.getPrintStatus().getValue();
//
// if(printStatus == PrintStatus.NOT_PRINT){
// sharedViewModel.setVisibilityPrintReceiptButtons(8);
// sharedViewModel.setPrintStatus(PrintStatus.FIRST_PRINT);
// }else if(printStatus == PrintStatus.FIRST_PRINT || printStatus == PrintStatus.FIRST_PRINT_DONE){
// sharedViewModel.setVisibilityPrintReceiptButtons(8);
// sharedViewModel.setPrintStatus(PrintStatus.SECOND_PRINT);
// }
sharedViewModel.setVisibilityPrintReceiptButtons(8);
//
sharedViewModel.setPrintStatus(PrintStatus.SECOND_PRINT);
}
public void onCancel() {
sharedViewModel.setVisibilityPrintReceiptButtons(8);
isCardInside();
// PrintStatus printStatus = sharedViewModel.getPrintStatus().getValue();
//
// if(printStatus == PrintStatus.NOT_PRINT){
// sharedViewModel.setPrintStatus(PrintStatus.FIRST_PRINT_DONE);
// }else{
// sharedViewModel.setVisibilityPrintReceiptButtons(8);
// isCardInside();
// }
}
public void onContinue(){
isCardInside();
}
}

View File

@ -1,18 +1,27 @@
package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum;
import com.utsmm.kbz.config.data.model.CardTransactionType;
import com.utsmm.kbz.util.MockData;
import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TerminalUtil;
import com.utsmyanmar.checkxread.checkcard.CheckCardResultX;
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.sdk.NexGoSDK;
import com.utsmyanmar.checkxread.util.CardTypeX;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
@ -34,6 +43,8 @@ import com.utsmm.kbz.util.TransactionUtil;
import com.utsmyanmar.paylibs.utils.LogUtil;
import java.util.HashSet;
public class ProcessingCardFragment extends DataBindingFragment {
private static final String TAG = ProcessingCardFragment.class.getSimpleName();
private CardReadViewModel cardReadViewModel;
@ -41,6 +52,8 @@ public class ProcessingCardFragment extends DataBindingFragment {
private TransProcessViewModel transProcessViewModel;
private PinPadViewModel pinPadViewModel;
private EmvTransactionProcessViewModel emvTransactionViewModel;
private int routeId;
@Override
@ -94,7 +107,8 @@ public class ProcessingCardFragment extends DataBindingFragment {
private void checkCardTransactionType() {
switch (cardReadViewModel.getCardTransactionType()) {
case MPU: readMPUCard();
case MPU:
readMPUCard();
break;
case EMV: handlePreEmvProcess();
break;
@ -102,28 +116,64 @@ public class ProcessingCardFragment extends DataBindingFragment {
break;
case MAG: readMAGStripe(false,true);
break;
case MOCK: mockMPUCard();
break;
}
}
private void processMPU(){
if(sharedViewModel.getAmountExist().getValue() != null && !sharedViewModel.getAmountExist().getValue()) {
routeId = R.id.action_processingCardFragment_to_inputAmountFragment;
}
routeId = R.id.action_processingCardFragment_to_pinPadFragment;
safeNavigateToRouteId();
}
private void mockMPUCard() {
LogUtil.d(TAG,"initialize mock card data...");
routeId = R.id.action_processingCardFragment_to_pinPadFragment;
transProcessViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
pinPadViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
CardDataX cardDataX = MockData.getInstance().generateMPUCard();
TradeData tradeData = TransactionUtil.getInstance().initMPUTransaction(cardDataX, CardTypeX.IC);
transProcessViewModel.setTradeData(tradeData);
pinPadViewModel.setTradeData(tradeData);
sharedViewModel.setCardDataExist(true);
safeNavigateToRouteId();
}
private void readMPUCard() {
cardReadViewModel.startReadXProcess(MPUXReadCard.getInstance(), new ReadCardResultX() {
@Override
public void onSuccess(CardDataX cardDataX) {
if(!TerminalUtil.getInstance().getBinList().isEmpty()) {
if(TerminalUtil.getInstance().getBinList().contains(cardDataX.getBin())) {
LogUtil.d(TAG," <= BIN found in list, switching to EMV process");
cardReadViewModel.cancelCheckCard();
initCheckCard();
return;
}
}
routeId = R.id.action_processingCardFragment_to_pinPadFragment;
transProcessViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
pinPadViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
transProcessViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
pinPadViewModel.transType.setValue(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 ) {
if(sharedViewModel.getTransactionsType().getValue() == TransactionsType.PRE_AUTH_VOID ) {
sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_function_not_supported));
sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_alert_pre_auth_cancel));
routeId = R.id.action_processingCardFragment_to_errorFragment;
safeNavigateToRouteId();
return;
}
// else if(sharedViewModel.transactionsType.getValue() == TransactionsType.REFUND) {
// sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_card_not_supported));
@ -164,7 +214,7 @@ public class ProcessingCardFragment extends DataBindingFragment {
// pin required scenario
routeId = R.id.action_processingCardFragment_to_pinPadFragment;
transProcessViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
transProcessViewModel.transType.setValue(sharedViewModel.transactionsType.getValue());
pinPadViewModel.transType.postValue(sharedViewModel.transactionsType.getValue());
/* need to check card scheme according to card number --!^--- check below function*/
@ -189,10 +239,11 @@ public class ProcessingCardFragment extends DataBindingFragment {
}
if(sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_PARTIAL_VOID ) {
// sharedViewModel.transMenu.postValue(null);
sharedViewModel.setTransMenu(null);
if(sharedViewModel.getTransactionsType().getValue() == TransactionsType.PRE_AUTH_VOID ) {
sharedViewModel.set_errorFragmentMsg(getResourceString(R.string.txt_alert_pre_auth_cancel));
routeId = R.id.action_processingCardFragment_to_errorFragment;
}
// else if(sharedViewModel.transactionsType.getValue() == TransactionsType.REFUND) {
// routeId = R.id.action_processingCardFragment_to_errorFragment;
@ -245,6 +296,45 @@ public class ProcessingCardFragment extends DataBindingFragment {
}
private void initCheckCard() {
HashSet<CardSlotTypeEnum> allType = new HashSet<>();
allType.add(CardSlotTypeEnum.ICC1);
cardReadViewModel.startCheckXProcessNex(allType, 60, 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);
// delayFunctionCall(()->{
//
// });
handlePreEmvProcess();
}
@Override
public void onError(int code, String message) {
LogUtil.d(TAG,"on error:"+code+" - message :"+message);
showDeclineDialog(message);
routeId = R.id.action_processingCardFragment_to_errorFragment;
safeNavigateToRouteId();
}
@Override
public void onCommError() {
LogUtil.d(TAG,"on Comm Error...");
ecrActionCancel(getResourceString(R.string.txt_cancel_trans));
showDeclineDialog("Chip not detected!");
routeId = R.id.action_processingCardFragment_to_errorFragment;
safeNavigateToRouteId();
}
});
}
private void prepareEmvTransaction() {
sharedViewModel.isEmv.postValue(true);
cardReadViewModel.cardTypeData.observe(getViewLifecycleOwner(), cardType -> {
@ -254,5 +344,22 @@ public class ProcessingCardFragment extends DataBindingFragment {
payDetail.setCardType(cardType);
emvTransactionViewModel.setTradeData(tradeData);
});
// TradeData tradeData = Params.newTrade(false);
// PayDetail payDetail = tradeData.getPayDetail();
//
// payDetail.setCardType(cardReadViewModel.cardTypeData.getValue());
// emvTransactionViewModel.setTradeData(tradeData);
}
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

@ -9,7 +9,12 @@ import androidx.annotation.Nullable;
import androidx.navigation.NavController;
import androidx.navigation.NavDestination;
import com.utsmm.kbz.util.tms.TMSUtil;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptCardRequest;
import com.utsmm.kbz.util.EReceiptUtil;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
@ -25,6 +30,8 @@ import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmyanmar.paylibs.utils.LogUtil;
import java.text.DecimalFormat;
public class ProcessingFragment extends DataBindingFragment {
private static final String TAG = ProcessingFragment.class.getSimpleName();
@ -168,14 +175,20 @@ public class ProcessingFragment extends DataBindingFragment {
} else {
LogUtil.d(TAG,"Updated sharedViewmodel payDetail for non emv");
sharedViewModel.payDetail.setValue(transProcessViewModel.payDetailResult.getValue());
}
// if(sharedViewModel.payDetail.getValue() != null) {
// EReceiptRequest request = EReceiptUtil.getInstance().generateMPUReceipt(sharedViewModel.payDetail.getValue());
// sharedViewModel.pushReceipt(request);
// }
// transProcessViewModel.payDetailResult.observe(getViewLifecycleOwner(), payDetail -> sharedViewModel.payDetail.postValue(payDetail));
}
private void callNextScreen(){
updateData();
// updateData();
if (requiresSignature()) {
routeId = R.id.action_processingFragment_to_signatureFragment;
} else {
@ -203,7 +216,7 @@ public class ProcessingFragment extends DataBindingFragment {
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());
boolean isSuccessful = "00".equals(payDetail.getTradeAnswerCode()) || "000".equals(payDetail.getTradeAnswerCode());
// You can customize this logic based on your business requirements
return isSuccessful && !isEmvTrans(); // Require signature for successful non-EMV transactions
@ -248,13 +261,23 @@ public class ProcessingFragment extends DataBindingFragment {
private void observeData(ProcessingTransaction processingTransaction) {
processingTransaction.getTransStatus().observe(getViewLifecycleOwner(), transResultStatus -> {
LogUtil.d(TAG,"Transaction RESULT :"+transResultStatus);
PayDetail payDetail = isEmvTrans()
? emvTransactionProcessViewModel.payDetailResult.getValue()
: transProcessViewModel.payDetailResult.getValue();
LogUtil.d(TAG, "PayDetail from VM: " + payDetail);
switch (transResultStatus) {
case FAIL:
sharedViewModel.pushReceipt(buildEReceiptCardReceipt(payDetail, false, "FAILED"));
case SUCCESS:
sharedViewModel.pushReceipt(buildEReceiptCardReceipt(payDetail, true, "SUCCESS"));
case OFFLINE_SUCCESS:
LogUtil.d(TAG,"This was called!");
if(SystemParamsOperation.getInstance().getDemoStatus()) {
delayFunctionCall(()->{
// updateData();
@ -263,6 +286,7 @@ public class ProcessingFragment extends DataBindingFragment {
},1500);
} else {
// updateData();
sharedViewModel.dismissLoadingMsg();
callNextScreen();
}
@ -366,4 +390,108 @@ public class ProcessingFragment extends DataBindingFragment {
});
}
private String mapDE3ToShortCode(String de3) {
if (de3 == null) return "UNK";
switch (de3) {
case "000000": return "S"; // Sale
case "020000": return "V"; // Void
case "200000": return "R"; // Refund
case "030000": return "P"; // Preauth
case "310000": return "PC"; // Preauth Complete
}
return "UNK"; // Unknown
}
public static String mapTransactionType(int type) {
switch (type) {
case 1: // SALE
return "S";
case 2: // VOID SALE
return "V";
case 4: // REFUND
return "R";
case 5: // PRE-AUTH
return "P";
case 6: // PRE-AUTH VOID
return "PV";
case 7: // PRE-AUTH COMPLETE
return "PC";
case 8: // PRE-AUTH COMPLETE VOID
return "PCV";
case 9: // CASH OUT
return "CAV";
case 18: // TIP ADJUST
return "TA";
case 20: // QR PAYMENT
return "QR";
case 34: // QR REFUND
return "QRV";
default:
return "UNK";
}
}
private String mapCurrency(String currency) {
if (currency == null) return "MMK";
switch (currency) {
case "104": return "MMK";
case "840": return "USD";
case "764": return "THB";
case "702": return "SGD";
case "978": return "EUR";
default: return currency; // Already alphabetic? return as-is
}
}
private EReceiptCardRequest buildEReceiptCardReceipt(PayDetail payDetail, boolean isSuccess, String reason){
//current timestamp
String currentTimestamp = new java.text.SimpleDateFormat(
"MMddHHmmss", java.util.Locale.getDefault()
).format(new java.util.Date());
//DeviceInfo
String serial = TMSUtil.getInstance().getSerialNumber();
String appId = requireActivity().getPackageName();
//TerminalInfo
String terminalId = SystemParamsOperation.getInstance().getTerminalId();
String merchantId = SystemParamsOperation.getInstance().getMerchantId();
double realAmount = payDetail.getAmount() / 100.0;
DecimalFormat df = new DecimalFormat("0.00");
String amount = df.format(realAmount);
EReceiptCardRequest request = new EReceiptCardRequest();
request.setDE2(payDetail.getCardNo());
request.setDE3(mapDE3ToShortCode(payDetail.getProcessCode()));
request.setDE4(amount);
request.setDE7(currentTimestamp);
request.setDE11(payDetail.getVoucherNo());
request.setDE22(mapTransactionType(payDetail.getTransactionType()));
request.setDE37(payDetail.getReferNo());
request.setDE38(payDetail.getAuthNo());
request.setDE39(isSuccess ? "A" : "E");
request.setDE41(terminalId);
request.setDE42(merchantId);
request.setDE49(mapCurrency(payDetail.getCurrencyCode()));
request.setSerial(serial);
request.setInvoiceNumber(payDetail.getInvoiceNo());
request.setAppId(appId);
request.setDescription(reason);
return request;
}
}

View File

@ -16,7 +16,11 @@ import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.print.printx.PrintX;
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.print_utils.BitmapUtils;
public class SignatureFragment extends DataBindingFragment {
@ -80,14 +84,12 @@ public class SignatureFragment extends DataBindingFragment {
@Override
public void onSigned() {
LogUtil.d(TAG,"ON Signed !");
isSigned = true;
}
@Override
public void onClear() {
isSigned = false;
LogUtil.d(TAG,"ON Clear !");
}
});
}
@ -130,6 +132,12 @@ public class SignatureFragment extends DataBindingFragment {
safeNavigateToRouteId();
}
private void updateData() {
PayDetail payDetail = sharedViewModel.payDetail.getValue();
payDetail.setESignHexData(BitmapUtils.bitmapToHexString(mSignaturePad.getSignatureBitmap()));
sharedViewModel.payDetail.setValue(payDetail);
}
public class ClickEvent {
@ -138,6 +146,8 @@ public class SignatureFragment extends DataBindingFragment {
// Handle digital signature
if (isSigned) {
sharedViewModel.signBitmap = mSignaturePad.getSignatureBitmap();
updateData();
LogUtil.d(TAG, "Digital signature confirmed and stored");
callNextScreen();
} else {
@ -147,7 +157,6 @@ public class SignatureFragment extends DataBindingFragment {
// 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();
}
}

View File

@ -8,6 +8,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import com.google.gson.Gson;
import com.google.gson.JsonSyntaxException;
import com.google.gson.stream.MalformedJsonException;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
@ -26,6 +27,7 @@ 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.printx.PrintXStatus;
import com.utsmyanmar.paylibs.utils.PrintStatus;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
@ -42,12 +44,13 @@ import java.io.IOException;
import javax.inject.Inject;
import dagger.hilt.android.AndroidEntryPoint;
import retrofit2.HttpException;
import com.utsmyanmar.paylibs.utils.LogUtil;
// Temporarily disabled Hilt
// @AndroidEntryPoint
@AndroidEntryPoint
public class TransactionResultFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback {
private static final String TAG = TransactionResultFragment.class.getSimpleName();
@ -91,7 +94,6 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
@Override
public void onStart() {
super.onStart();
}
@Override
@ -111,7 +113,8 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
}
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(sharedViewModel.payDetail.getValue().getTransactionType() != TransactionsType.SETTLEMENT.value
&& sharedViewModel.payDetail.getValue().getTransactionType() != TransactionsType.MMQR_SETTLEMENT.value) {
if(SystemParamsOperation.getInstance().isAlertSound()) {
startSound(getResourceString(R.string.txt_audio_thank_you));
@ -119,7 +122,7 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
}
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_trans_result));
} else if(qrStatus == 1 || qrStatus == -1 || qrStatus == 2 || qrStatus == 3 ) {
/* WAVE QR STATUS */
/* QR STATUS */
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_qr_pay));
} else {
setToolBarTitleWithoutBackIcon(getResourceString(R.string.txt_title_error));
@ -146,6 +149,8 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
PayDetail payDetail = sharedViewModel.payDetail.getValue();
if (payDetail == null) {
navigateToMainScreen();
return;
@ -159,16 +164,21 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
TransactionsType transactionType = sharedViewModel.transactionsType.getValue();
if (isNonApprovedTrade(payDetail) && isNonWavepayTransaction(transactionType)) {
if (isNonApprovedTrade(payDetail) && isNonQRPayTransaction(transactionType)) {
startPrintProcess(false);
isCardInside();
} else if (transactionType == TransactionsType.SETTLEMENT) {
} else if (transactionType == TransactionsType.SETTLEMENT || transactionType == TransactionsType.MMQR_SETTLEMENT) {
handleSettlementTransaction(siriusReq);
} else if (isWavePayNonSuccessTransaction(transactionType, payDetail)) {
startPrintProcess(false);
} else if (isQRPayNonSuccessTransaction(transactionType, payDetail)) {
// startPrintProcess(false);
if(transactionType == TransactionsType.MMQR_REFUND){
showDeclineDialog("QR Refund Failed! \n" + payDetail.getTradeResultDes());
}else{
showDeclineDialog("QR Payment Failed! \n" + payDetail.getTradeResultDes());
}
navigateToMainScreen();
} else if (isWavePaySuccessTransaction(transactionType, payDetail)) {
handleWavePaySuccessTransaction(payDetail, siriusReq);
} else if (isQRPaySuccessTransaction(transactionType, payDetail)) {
handleQRPaySuccessTransaction(payDetail, siriusReq);
} else {
handleDefaultTransaction(payDetail, siriusReq);
}
@ -182,19 +192,19 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
!payDetail.getTradeAnswerCode().equals(Constant.ANSWER_CODE_ACCEPT);
}
private boolean isNonWavepayTransaction(TransactionsType transactionType) {
private boolean isNonQRPayTransaction(TransactionsType transactionType) {
return transactionType != TransactionsType.MMQR &&
transactionType != TransactionsType.MMQR_INQUIRY_STATUS &&
transactionType != TransactionsType.MMQR_REFUND;
}
private boolean isWavePayNonSuccessTransaction(TransactionsType transactionType, PayDetail payDetail) {
private boolean isQRPayNonSuccessTransaction(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) {
private boolean isQRPaySuccessTransaction(TransactionsType transactionType, PayDetail payDetail) {
return (transactionType == TransactionsType.MMQR || transactionType == TransactionsType.MMQR_REFUND) &&
payDetail.getQrTransStatus() == 1;
@ -203,11 +213,11 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
private void handleSettlementTransaction(SiriusRequest siriusReq) {
startPrintProcess(true);
downloadParameters(siriusReq, TMSUpdate.UPDATE);
showSuccessDialog(getResourceString(R.string.txt_configs_are_updated));
navigateToMainScreen();
// showSuccessDialog(getResourceString(R.string.txt_configs_are_updated));
// navigateToMainScreen();
}
private void handleWavePaySuccessTransaction(PayDetail payDetail, SiriusRequest siriusReq) {
private void handleQRPaySuccessTransaction(PayDetail payDetail, SiriusRequest siriusReq) {
SystemParamsOperation.getInstance().setLastSuccessTrnx(payDetail.getVoucherNo());
downloadParameters(siriusReq, TMSUpdate.CHECK);
navigateToPrintScreen();
@ -238,15 +248,12 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
try {
SiriusError siriusError = new Gson().fromJson(error.response().errorBody().string(), SiriusError.class);
LogUtil.d(TAG,siriusError.getMessage());
} catch (IOException ex) {
} catch (IOException | JsonSyntaxException ex) {
ex.printStackTrace();
}
} else {
LogUtil.d(TAG,getResourceString(R.string.txt_failure)+throwable.getMessage());
}
throwable.printStackTrace();
}
@ -314,7 +321,17 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
@Override
public void printerReady() {
if(isSettlement) {
sharedViewModel.startPrintProcessSettlement();
sharedViewModel.startPrintSettlement(new PrintXStatus() {
@Override
public void onSuccess() {
isCardInside();
}
@Override
public void onFailure() {
handleForEmptyPaperRoll(isSettlement);
}
});
return;
}
sharedViewModel.startPrintProcess();
@ -322,26 +339,7 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
@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));
}
handleForEmptyPaperRoll(isSettlement);
}
@Override
@ -368,6 +366,30 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
});
}
private void handleForEmptyPaperRoll(boolean isSettle) {
cancelTimeout();
showPrinterAlertDialog(getResourceString(R.string.txt_paper_roll_not_ready), new DialogCallback() {
@Override
public void onClickCancel() {
dismissPrinterAlertDialog();
isCardInside();
}
@Override
public void onClickRetry() {
dismissPrinterAlertDialog();
startPrintProcess(isSettle);
}
});
if(SystemParamsOperation.getInstance().isAlertSound()) {
startSound(getResourceString(R.string.txt_audio_printer_alert));
}
}
private void alertPaperRoll(String title, String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
builder.setTitle(title)

View File

@ -25,6 +25,8 @@ import java.util.HashSet;
import javax.inject.Inject;
import io.reactivex.rxjava3.core.Single;
public class CardReadViewModel extends ViewModel {
@ -46,7 +48,6 @@ public class CardReadViewModel extends ViewModel {
public SingleLiveEvent<Integer> cardTypeData = new SingleLiveEvent<>();
public SingleLiveEvent<PayDetail> payDetail = new SingleLiveEvent<>();
public SingleLiveEvent<CardReadStatus> readStatus = new SingleLiveEvent<>();
public SingleLiveEvent<String> checkCardAlertMsg = new SingleLiveEvent<>();
@ -95,96 +96,6 @@ public class CardReadViewModel extends ViewModel {
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;
}
@ -193,19 +104,43 @@ public class CardReadViewModel extends ViewModel {
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");
// }
// });
// }
/**
* Properly cleanup card reading operations with sequential steps
*/
public void performCompleteCleanup(Runnable onCleanupComplete) {
// Step 1: Cancel check card operations
NexGoSDK.getInstance().cancelCheckCard();
// Step 2: Cancel X process operations
cancelCheckXProcess();
// Step 3: Reset internal flags and state
resetOneTimeFlag();
resetUI();
// Step 4: Wait for SDK to be ready before proceeding
if (onCleanupComplete != null) {
waitForSDKReady(onCleanupComplete, 0);
}
}
/**
* Wait for SDK to be ready with timeout
*/
private void waitForSDKReady(Runnable callback, int retryCount) {
final int MAX_RETRIES = 10; // Max 2 seconds (10 * 200ms)
if (NexGoSDK.getInstance().isSDKReady() || retryCount >= MAX_RETRIES) {
// SDK is ready or we've reached max retries
if (retryCount >= MAX_RETRIES) {
// Log warning if we reached max retries
android.util.Log.w(TAG, "SDK readiness check timed out after " + (MAX_RETRIES * 200) + "ms");
}
callback.run();
} else {
// Wait a bit more and check again
mainThreadHandler.postDelayed(() -> waitForSDKReady(callback, retryCount + 1), 200);
}
}
}

View File

@ -1,460 +0,0 @@
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

@ -16,6 +16,7 @@ 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.checkxread.util.CardTypeX;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.model.enums.TransCVM;
@ -288,6 +289,8 @@ public class EmvTransactionProcessViewModel extends EmvBaseViewModel implements
if(isCardLessTrans()) {
transResult.setValue(TransResultStatus.SUCCESS);
} else if(payDetailRes.getCardType() == CardTypeX.MANUAL.value) {
transResult.setValue(TransResultStatus.SUCCESS);
}
} else {
@ -295,6 +298,8 @@ public class EmvTransactionProcessViewModel extends EmvBaseViewModel implements
if(isCardLessTrans()) {
transResult.setValue(TransResultStatus.FAIL);
} else if(payDetailRes.getCardType() == CardTypeX.MANUAL.value) {
transResult.setValue(TransResultStatus.FAIL);
}
/*
* @Note
@ -492,9 +497,9 @@ public class EmvTransactionProcessViewModel extends EmvBaseViewModel implements
private void handleTransactionProcess() {
String cardNo = mPayDetail.getCardNo();
if (cardNo == null || TextUtils.equals(cardNo, "")) {
// 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 ) {

View File

@ -101,33 +101,19 @@ public class InputAmountViewModel extends ViewModel {
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) {
String currentValue = inputAmountView.getValue();
if(inputAmount.toString().contains(",")) {
int commaIndex = inputAmount.indexOf(",");
inputAmount.deleteCharAt(commaIndex);
} else {
inputAmount.deleteCharAt(inputAmount.length() - 1);
}
inputAmountView.setValue(inputAmount.toString());
String rawNumber = currentValue.replace(",", "");
if (rawNumber.length() > 1) {
rawNumber = rawNumber.substring(0, rawNumber.length() - 1);
// 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");
double amt = Double.parseDouble(rawNumber);
DecimalFormat formatter = new DecimalFormat("#,###");
inputAmountView.setValue(formatter.format(amt));
} else {
StringBuilder currentAmount = new StringBuilder();
currentAmount.append(inputAmountView.getValue());
currentAmount.deleteCharAt(currentAmount.length() - 1);
inputAmountView.setValue(currentAmount.toString());
inputAmountView.setValue("0");
}
}
}
}

View File

@ -1,18 +1,23 @@
package com.utsmm.kbz.ui.core_viewmodel;
import android.graphics.Bitmap;
import android.util.Log;
import dagger.hilt.android.lifecycle.HiltViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.google.gson.Gson;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptResponse;
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.util.TerminalUtil;
import com.utsmyanmar.ecr.data.TransType;
import com.utsmyanmar.ecr.data.model.Transactions;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.QRSettleData;
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
import com.utsmyanmar.paylibs.print.printx.PrintXStatus;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
@ -26,9 +31,15 @@ import com.utsmyanmar.paylibs.utils.enums.HostType;
import java.util.List;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import retrofit2.HttpException;
import com.utsmyanmar.paylibs.utils.LogUtil;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject;
@HiltViewModel
@ -54,14 +65,14 @@ public class SharedViewModel extends ViewModel {
public SingleLiveEvent<String> processCode = new SingleLiveEvent<>();
public SingleLiveEvent<PayDetail> payDetail = new SingleLiveEvent<>();
public SingleLiveEvent<List<PayDetail>> payDetails = 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<>();
@ -104,6 +115,7 @@ public class SharedViewModel extends ViewModel {
public SingleLiveEvent<HostType> hostType = new SingleLiveEvent<>();
public MutableLiveData<Integer> printReceiptButtons = new MutableLiveData<>(0);
public SingleLiveEvent<Boolean> printerDisabled = new SingleLiveEvent<>();
public SingleLiveEvent<String> printReceiptMsg = new SingleLiveEvent<>();
@ -157,6 +169,9 @@ public class SharedViewModel extends ViewModel {
private PayDetail mPayDetail = new PayDetail();
public MutableLiveData<String> serialNumber = new MutableLiveData<>();
// Updated constructor for Hilt ViewModel
@Inject
public SharedViewModel(Repository repository) {
@ -164,9 +179,12 @@ public class SharedViewModel extends ViewModel {
setPrintStatus(PrintStatus.FIRST_PRINT);
isReprint.setValue(false);
cardNo.setValue("");
String sn = TerminalUtil.getInstance().getSerialNo();
serialNumber.setValue(sn);
}
public void setEmvTrans(boolean status) {
isEmv.setValue(status);
}
@ -185,6 +203,23 @@ public class SharedViewModel extends ViewModel {
printReceiptButtons.postValue(value);
}
public void setTransactionsType(TransactionsType transactionsType) {
this.transactionsType.setValue(transactionsType);
}
public SingleLiveEvent<TransactionsType> getTransactionsType() {
return transactionsType;
}
public void setAmount(String amount) {
this.amount.setValue(amount);
}
public SingleLiveEvent<String> getAmount() {
return amount;
}
public void setPrintReceiptMsg(String msg) { this.printReceiptMsg.setValue(msg);}
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); }
@ -250,6 +285,7 @@ public class SharedViewModel extends ViewModel {
return repository.getParams(siriusRequest);
}
private void printReceipt(boolean isMerchantCopy) {
PrintXReceipt.getInstance().printSmileReceipt(payDetail.getValue(), isMerchantCopy, new PrintXStatus() {
@Override
@ -281,6 +317,7 @@ public class SharedViewModel extends ViewModel {
public void startPrintReceipt(boolean isFirstPrint) {
/*
* First Print is Merchant Copy..
@ -361,23 +398,29 @@ public class SharedViewModel extends ViewModel {
}
public void startPrintProcessSettlement() {
public void startPrintSettlement(PrintXStatus printXStatus) {
if(payDetail.getValue() == null) return;
if(payDetail.getValue().getTransactionType() == TransactionsType.SETTLEMENT.value) {
startPrintProcessSettlement(printXStatus);
} else {
startPrintProcessQRSettlement(printXStatus);
}
}
public void startPrintProcessSettlement(PrintXStatus printXStatus) {
if(payDetail.getValue() == null) return;
PrintXReceipt.getInstance().printSmileSettlementReport(payDetail.getValue(), new PrintXStatus() {
@Override
public void onSuccess() {
PrintXReceipt.getInstance().printSmileSettlementReport(payDetail.getValue(),printXStatus);
}
}
private void startPrintProcessQRSettlement(PrintXStatus printXStatus) {
@Override
public void onFailure() {
}
});
/*POS */
// PrintReceipt.getInstance().printSettlementReceiptPOS(settleData.getSaleCount(), settleData.getSaleAmount(), settleData.getRefundCount(), settleData.getRefundAmount(), settleData.getPreAuthCount(), settleData.getPreAuthAmount(), true);
if(payDetail.getValue() == null && payDetails.getValue() == null) return;
PrintXReceipt.getInstance().printQRSettlementReport(payDetail.getValue(), QRSettleData.convertFromPayDetail(payDetails.getValue()), printXStatus);
}
@ -406,4 +449,47 @@ public class SharedViewModel extends ViewModel {
}
public void pushReceipt(Object body){
Log.d("push receipt", new Gson().toJson(body));
repository.sendReceipt(body)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
response -> Log.d("E-Receipt", "Success =>"+ response.getMessage()),
error -> {
if (error instanceof HttpException) {
HttpException httpEx = (HttpException) error;
try {
String errorJson = httpEx.response().errorBody().string();
Log.e("E-Receipt", "Raw error JSON => " + errorJson);
// Parse JSON to model
EReceiptResponse res = new Gson().fromJson(errorJson, EReceiptResponse.class);
Log.e("E-Receipt", "Parsed Error => " + res.getMessage());
} catch (Exception e) {
e.printStackTrace();
}
} else {
Log.e("E-Receipt", "Unexpected error => " + error.getMessage());
}
}
);
}
public void printTerminalHostConfigs(){
PrintXReceipt.getInstance().printTerminalHostConfig(new PrintXStatus() {
@Override
public void onSuccess() {
Log.d("PrintConfig", "Print Terminal Config Success.");
}
@Override
public void onFailure() {
Log.e("PrintConfig", "Print Terminal Config Success.");
}
});
}
}

View File

@ -71,7 +71,7 @@ public class TMSProcessViewModel extends ViewModel {
}
public void loadEmvParameters() {
emvParamOperation.loadAidRids();
// emvParamOperation.loadAidRids();
emvParamOperation.loadEmvTerminalParam();
}

View File

@ -10,6 +10,8 @@ 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.LogUtil;
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;
@ -66,8 +68,60 @@ public class DashboardTransFragment extends DataBindingFragment {
initData();
}
// private void initData() {
// TMSUtil.getInstance().checkFeaturesList(requireActivity(),featuresList);
// mainAdapter.notifyDataSetChanged();
// }
Boolean isRefundEnabled = SystemParamsOperation.getInstance().getRefundStatus();
Boolean isVoidEnabled = SystemParamsOperation.getInstance().getVoidStatus();
Boolean isPreAuthEnabled = SystemParamsOperation.getInstance().getPreAuthStatus();
Boolean isCashAdvanceEnabled = SystemParamsOperation.getInstance().getCashAdvanceStatus();
private void initData() {
TMSUtil.getInstance().checkFeaturesList(requireActivity(),featuresList);
featuresList.clear();
ArrayList<Features> allFeatures = new ArrayList<>();
TMSUtil.getInstance().checkFeaturesList(requireActivity(), allFeatures);
for (Features feature : allFeatures) {
switch (feature.getFeaturesType()) {
case REFUND:
if (isRefundEnabled) {
featuresList.add(feature);
}
break;
case VOID:
if (isVoidEnabled) {
featuresList.add(feature);
}
break;
case PRE_AUTH_SALE:
case PRE_AUTH_COMPLETE_VOID:
case PRE_AUTH_VOID:
case PRE_AUTH_COMPLETE:
if (isPreAuthEnabled) {
featuresList.add(feature);
}
break;
case CASH_ADVANCE:
if(isCashAdvanceEnabled){
featuresList.add(feature);
}
break;
default:
featuresList.add(feature);
break;
}
}
mainAdapter.notifyDataSetChanged();
}
@ -106,6 +160,9 @@ public class DashboardTransFragment extends DataBindingFragment {
case HISTORY:
new DashboardTransFragment.ClickEvent().onClickHistory();
break;
case DEVICE_CONFIG:
new DashboardTransFragment.ClickEvent().onClickDeviceConfig();
break;
}
});
@ -125,7 +182,7 @@ public class DashboardTransFragment extends DataBindingFragment {
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Boolean demoStatus = SystemParamsOperation.getInstance().getDemoStatus();
}
public class ClickEvent {
@ -135,7 +192,7 @@ public class DashboardTransFragment extends DataBindingFragment {
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.VOID);
sharedViewModel.setTransactionsType(TransactionsType.VOID);
// sharedViewModel.transMenu.postValue(TransMenu.TRANSACTIONS);
sharedViewModel.setTransMenu(TransMenu.TRANSACTIONS);
@ -147,16 +204,15 @@ public class DashboardTransFragment extends DataBindingFragment {
public void onClickSettlement() {
sharedViewModel.settlementType.setValue(SettlementType.NORMAL);
sharedViewModel.transactionsType.setValue(TransactionsType.SETTLEMENT);
sharedViewModel.setTransMenu(TransMenu.SETTLEMENT);
sharedViewModel.setTransactionsType(TransactionsType.SETTLEMENT);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
public void onClickRefund() {
sharedViewModel.transactionsType.setValue(TransactionsType.REFUND);
sharedViewModel.setTransactionsType(TransactionsType.REFUND);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
}
@ -167,8 +223,7 @@ public class DashboardTransFragment extends DataBindingFragment {
} else if (checkTid()) {
showDeclineDialog("Please Download Config!");
} else {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_SALE);
sharedViewModel.setTransactionsType(TransactionsType.PRE_AUTH_SALE);
routeId = R.id.action_dashboardTransFragment_to_inputAmountFragment;
safeRouteTo(currentId,routeId,hostId);
}
@ -176,23 +231,24 @@ public class DashboardTransFragment extends DataBindingFragment {
}
public void onClickPreAuthCancel () {
sharedViewModel.transactionsType.setValue(TransactionsType.PRE_AUTH_VOID);
sharedViewModel.setTransactionsType(TransactionsType.PRE_AUTH_VOID);
sharedViewModel.setTransMenu(TransMenu.PRE_AUTH_FULL_VOID);
sharedViewModel.amount.postValue(null);
sharedViewModel.amount.postValue("0"); // null to 0
// 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);
sharedViewModel.setTransactionsType(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);
sharedViewModel.setTransactionsType(TransactionsType.PRE_AUTH_COMPLETE_VOID);
routeId = R.id.action_dashboardTransFragment_to_inputPasswordFragment;
safeRouteTo(currentId,routeId,hostId);
@ -200,7 +256,8 @@ public class DashboardTransFragment extends DataBindingFragment {
public void onClickCashAdvance() {
sharedViewModel.transactionsType.setValue(TransactionsType.CASH_OUT);
sharedViewModel.setTransactionsType(TransactionsType.CASH_OUT);
sharedViewModel.setTransMenu(TransMenu.CASH_OUT);
routeId = R.id.action_dashboardTransFragment_to_inputAmountFragment;
safeRouteTo(currentId,routeId,hostId);
@ -211,7 +268,10 @@ public class DashboardTransFragment extends DataBindingFragment {
safeRouteTo(currentId,routeId,hostId);
}
public void onClickDeviceConfig(){
routeId = R.id.action_dashboardTransFragment_to_deviceConfig;
safeRouteTo(currentId, routeId, hostId);
}
}
}

View File

@ -13,6 +13,7 @@ import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.kizzy.xpay.util.Sign;
import com.utsmm.kbz.ui.qr_pay.QRRefund;
import com.utsmyanmar.baselib.network.model.DemoQRRequest;
import com.utsmyanmar.baselib.network.model.DemoQRResponse;
import com.utsmyanmar.baselib.network.model.DemoQRReturnRequest;
@ -36,12 +37,16 @@ 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 com.utsmyanmar.paylibs.utils.core_utils.SystemParamsSettings;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.inject.Inject;
@ -52,7 +57,11 @@ public class KPayViewModel extends ViewModel {
private final Repository repository;
private final String appKey = "UTSMMuat@2025";
private final String appKey = SystemParamsOperation.getInstance().getAppKey();
// private final String appKey = "UTSMMuat@2025";
private final String appId = SystemParamsOperation.getInstance().getAppId();
// private final String appId = "kp9b0794b349ae85b00c51e0677484c7";
private final ExecutorService executor = Executors.newSingleThreadExecutor();
private final Handler mainHandler = new Handler(Looper.getMainLooper());
@ -61,10 +70,7 @@ public class KPayViewModel extends ViewModel {
private static final String NONCE_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
private static final int NONCE_LENGTH = 32;
private final SecureRandom secureRandom = new SecureRandom();
public MutableLiveData<Boolean> partialRefundEnabled = new MutableLiveData<>();
private String generateRandomTwoChars() {
// You can reuse the existing character set and SecureRandom instance
@ -114,7 +120,7 @@ public class KPayViewModel extends ViewModel {
bizContent.put("refund_request_no", refundOrderId);
bizContent.put("merch_order_id", origOrderId);
bizContent.put("merch_code", mid);
bizContent.put("appid", "kp9b0794b349ae85b00c51e0677484c7");
bizContent.put("appid", appId);
if(!refundAmount.equals("0")) {
bizContent.put("refund_amount", refundAmount);
}
@ -138,7 +144,7 @@ public class KPayViewModel extends ViewModel {
KPayRefund.RefundRequest.RequestBody.BizContent biz =
new KPayRefund.RefundRequest.RequestBody.BizContent(
"kp9b0794b349ae85b00c51e0677484c7",
appId,
mid,
origOrderId,
refundAmount, // This can be null for original refunds
@ -160,7 +166,7 @@ public class KPayViewModel extends ViewModel {
} else {
KPayRefund.RefundRequest.RequestBody.BizContent biz =
new KPayRefund.RefundRequest.RequestBody.BizContent(
"kp9b0794b349ae85b00c51e0677484c7",
appId,
mid,
origOrderId,
refundOrderId,
@ -187,20 +193,47 @@ public class KPayViewModel extends ViewModel {
return createQR(amount, String.valueOf(System.currentTimeMillis()),mid);
}
private int expireTime = 1;
private void calculateTimeoutMinutes() {
String data = SystemParamsOperation.getInstance().getWaveIntervalTime();
if (data == null || !data.contains("-")) {
data = "15-60"; // fallback
}
try {
String[] parts = data.split("-");
int waitingTimeSec = Integer.parseInt(parts[1]); // only take second part
// convert seconds minutes
expireTime = waitingTimeSec / 60;
// enforce limits 1120
if (expireTime < 1) expireTime = 1;
if (expireTime > 120) expireTime = 120;
} catch (Exception e) {
expireTime = 1; // safety fallback
LogUtil.d(TAG, "Invalid format for timeout config: " + data);
}
}
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
calculateTimeoutMinutes();
String timeoutExpress = expireTime + "m";
Map<String, Object> bizContent = new HashMap<>();
bizContent.put("merch_order_id", merchOrderId);
bizContent.put("merch_code", mid);
bizContent.put("appid", "kp9b0794b349ae85b00c51e0677484c7");
bizContent.put("appid", appId);
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("operator_id", serialNum);
bizContent.put("timeout_express", timeoutExpress);
bizContent.put("trans_currency", "MMK");
bizContent.put("callback_info", "callback");
@ -216,15 +249,16 @@ public class KPayViewModel extends ViewModel {
String sign = Sign.INSTANCE.generateSign(requestMap, appKey);
KPayQRRequest.QrRequest.RequestBody.BizContent biz = new KPayQRRequest.QrRequest.RequestBody.BizContent(
"kp9b0794b349ae85b00c51e0677484c7",
appId,
mid,
merchOrderId,
"PAY_BY_QRCODE",
"testing",
amount,
"MMK",
"100m",
"callback"
timeoutExpress,
"callback",
serialNum
);
KPayQRRequest.QrRequest.RequestBody body = new KPayQRRequest.QrRequest.RequestBody(
@ -243,6 +277,44 @@ public class KPayViewModel extends ViewModel {
return qrRequest;
}
public KPayQRRequest.CloseOrderRequest closeQrOrder(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", appId);
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("timestamp", currentTime);
requestMap.put("nonce_str", nonceStr);
requestMap.put("method", "kbz.payment.closeorder");
requestMap.put("version", "3.0");
requestMap.put("biz_content", bizContentMap);
String sign = Sign.INSTANCE.generateSign(requestMap, appKey);
KPayQRRequest.CloseOrderRequest.Request.BizContent bizContent = new KPayQRRequest.CloseOrderRequest.Request.BizContent(
merchOrderId,
mid,
appId
);
KPayQRRequest.CloseOrderRequest.Request requestBody = new KPayQRRequest.CloseOrderRequest.Request(
currentTime,
"kbz.payment.closeorder",
nonceStr,
"SHA256",
sign,
"3.0",
bizContent
);
KPayQRRequest.CloseOrderRequest request = new KPayQRRequest.CloseOrderRequest(requestBody);
return request;
}
public KPayQRQueryRequest.QRQueryRequest getQrStatus(String merchOrderId, String mid) {
@ -252,7 +324,7 @@ public class KPayViewModel extends ViewModel {
Map<String, Object> bizContentMap = new HashMap<>();
bizContentMap.put("merch_order_id", merchOrderId);
bizContentMap.put("merch_code", mid);
bizContentMap.put("appid", "kp9b0794b349ae85b00c51e0677484c7");
bizContentMap.put("appid", appId);
Map<String, Object> requestMap = new HashMap<>();
requestMap.put("timestamp", currentTime);
@ -264,7 +336,7 @@ public class KPayViewModel extends ViewModel {
String sign = Sign.INSTANCE.generateSign(requestMap, appKey);
KPayQRQueryRequest.QRQueryRequest.Request.BizContent bizContent = new KPayQRQueryRequest.QRQueryRequest.Request.BizContent(
"kp9b0794b349ae85b00c51e0677484c7",
appId,
mid,
merchOrderId
);
@ -284,13 +356,19 @@ public class KPayViewModel extends ViewModel {
return request;
}
@Inject
public KPayViewModel(Repository repository) {
this.repository = repository;
boolean enabled = SystemParamsOperation.getInstance().isQrPartialRefundEnable();
partialRefundEnabled.setValue(enabled);
}
private TradeData tradeData;
private PayDetail payDetail;
private QRRefund qrRefund;
public void setTradeData(TradeData tradeData){
this.tradeData = tradeData;
@ -304,6 +382,12 @@ public class KPayViewModel extends ViewModel {
public void setPayDetail(PayDetail payDetail) {
this.payDetail = payDetail;
}
public void setQrRefund(QRRefund qrRefund) {
this.qrRefund = qrRefund;
}
public QRRefund getQrRefund() {
return qrRefund;
}
public PayDetail getPayDetail() { return payDetail; }
@ -355,4 +439,11 @@ public class KPayViewModel extends ViewModel {
public Observable<KPayRefund.RefundResponse> kPayRefund(KPayRefund.RefundRequest refundRequest) {
return repository.kPayRefund(refundRequest);
}
public Observable<KPayQRRequest.CloseOrderResponse> closeQrOrderApi(
KPayQRRequest.CloseOrderRequest request
) {
return repository.qrCloseOrder(request);
}
}

View File

@ -25,6 +25,7 @@ import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.text.DecimalFormat;
import java.util.Locale;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
@ -135,10 +136,14 @@ public class QRConnectingFragment extends DataBindingFragment implements DataBin
}
private void generateQR() {
long originalAmount = payDetail.getAmount();
// String amount = String.format(Locale.getDefault(), "%.2f", payDetail.getAmount()/100.0);
String amount = String.format(Locale.getDefault(), "%d", (int)(payDetail.getAmount()/100.0));
// String amount = String.format(Locale.getDefault(), "%d", (int)(payDetail.getAmount()/100.0)); //this method have problem for 10055 to 100.00 auto convert (should convert to 100.55)
double realAmount = payDetail.getAmount() / 100.0;
DecimalFormat df = new DecimalFormat("0.00");
String amount = df.format(realAmount);
KPayQRRequest.QrRequest kPayQRRequest = KPayViewModel.createQR(amount, merchantId);
@ -163,7 +168,6 @@ public class QRConnectingFragment extends DataBindingFragment implements DataBin
LogUtil.d(TAG,"Ref Label :"+refLabel);
payDetail.setPayQRCode(response.getResponse().getQrCode());
payDetail.setQrReferNo(refLabel);
payDetail.setQrTransStatus(2);
payDetail.setReferNo(refLabel);

View File

@ -11,8 +11,10 @@ import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmm.kbz.util.tms.TMSUtil;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.KPayRefund;
//import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptQRRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
@ -34,6 +36,8 @@ import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import com.utsmyanmar.paylibs.utils.LogUtil;
import java.text.DecimalFormat;
public class QRRefundFragment extends DataBindingFragment {
private SharedViewModel sharedViewModel;
@ -192,16 +196,16 @@ public class QRRefundFragment extends DataBindingFragment {
payDetail.setAmount(refundAmount == null ? 0 : POSUtil.getInstance().convertAmount(refundAmount));
payDetail.setOriginalTransDate(dateTime);
payDetail.setQrTransStatus(1);
payDetail.setQrReferNo(referenceNo);
payDetail.setReferNo(referenceNo);
payDetail.setIsCanceled(true);
// sharedViewModel.pushReceipt(buildEReceiptQRReceipt(payDetail, true, "Refund success"));
retrievedUpdatePayDetail(referenceNo);
} else {
LogUtil.d(TAG, "Refund failed!");
payDetail.setQrTransStatus(-1);
payDetail.setQrReferNo(referenceNo);
payDetail.setReferNo(referenceNo);
String errorMsg = "Refund failed";
@ -210,6 +214,8 @@ public class QRRefundFragment extends DataBindingFragment {
}
payDetail.setTradeResultDes(errorMsg);
// sharedViewModel.pushReceipt(buildEReceiptQRReceipt(payDetail, true, "RESP CODE [68]\n Refund Failed"));
sharedViewModel.payDetail.setValue(payDetail);
navigateToNext();
}
@ -328,4 +334,6 @@ public class QRRefundFragment extends DataBindingFragment {
}
}
}
}

View File

@ -2,7 +2,6 @@ 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;
@ -10,9 +9,12 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmm.kbz.util.EReceiptUtil;
import com.utsmm.kbz.util.enums.TransResultStatus;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.DemoQRStatusRequest;
import com.utsmyanmar.baselib.network.model.KPayQRQueryRequest;
import com.utsmyanmar.baselib.network.model.KPayQRRequest;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.ecr.ECRHelper;
@ -123,6 +125,7 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
terminalId = TransactionUtil.getInstance().getQRTerminalId();
merchantId = TransactionUtil.getInstance().getQRMerchantId();
refLabel = sharedViewModel.qrRefNum.getValue();
// tradeData = waveViewModel.getTradeData();
@ -132,6 +135,7 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
sharedViewModel.insertPayDetail(payDetail);
}
@ -180,14 +184,25 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
initSetup();
calculateIntervalAndCount();
LogUtil.d(TAG,"intervalInSec: "+intervalInSec+" totalCount: "+totalCount);
setUpTimeout();
setUpCountDown();
requireActivity().getOnBackPressedDispatcher().addCallback(
getViewLifecycleOwner(),
new androidx.activity.OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
showExitConfirmation();
}
}
);
}
private void setUpCountDown() {
setupTimeout(10, new TimeoutCallback() {
int totalTime = intervalInSec * totalCount;
setupTimeout(totalTime, new TimeoutCallback() {
@Override
public void onTrick(long trickTime) {
sharedViewModel.countDownTxt.setValue((trickTime / 1000)+"");
@ -272,9 +287,6 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
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)
@ -297,17 +309,29 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
* trans is success !*/
// String transStatus = response.getTransactionStatus();
// String transTime = response.getResponse().;
if(response.getResponse().getWalletIdentifier() != null) {
payDetail.setCustomerMobile(response.getResponse().getWalletIdentifier());
} else {
payDetail.setCustomerMobile("KBZPay");
}
payDetail.setCustomerMobile("KBZ PAY");
payDetail.setQrReferNo(refLabel);
if(response.getResponse().getMmqrRef() != null) {
payDetail.setQrReferNo(response.getResponse().getMmqrRef());
}
payDetail.setTC(response.getResponse().getTradeStatus());
payDetail.setQrTransId(response.getResponse().getMmOrderId());
payDetail.setReferNo(refLabel);
payDetail.setApprovalCode(response.getResponse().getMmOrderId());
payDetail.setQrTransStatus(1);
payDetail.setOriginalTransDate(response.getResponse().getPaySuccessTime());
payDetail.setTradeDateAndTime(response.getResponse().getPaySuccessTime());
retrievedUpdatePayDetail(refLabel, payDetail,false);
EReceiptRequest request = EReceiptUtil.getInstance().generateQRReceipt(payDetail, TransResultStatus.SUCCESS);
sharedViewModel.pushReceipt(request);
return;
}
@ -317,6 +341,11 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
payDetail.setQrTransStatus(2);
}
EReceiptRequest request = EReceiptUtil.getInstance().generateQRReceipt(payDetail, TransResultStatus.FAIL);
sharedViewModel.pushReceipt(request);
sharedViewModel.insertPayDetail(payDetail);
sharedViewModel.payDetail.postValue(payDetail);
safeNavigateToRouteId();
@ -324,16 +353,24 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
} catch (Exception e) {
LogUtil.d(TAG, "On Exception::");
// sharedViewModel.pushReceipt(buildEReceiptQRReceipt(payDetail, false, "QR Failed! :" + e.getMessage()));
e.printStackTrace();
if (count == totalCount) {
if(payDetail.getQrTransStatus() != -1) {
payDetail.setQrTransStatus(2);
}
EReceiptRequest request = EReceiptUtil.getInstance().generateQRReceipt(payDetail, TransResultStatus.TIME_OUT);
sharedViewModel.pushReceipt(request);
sharedViewModel.insertPayDetail(payDetail);
sharedViewModel.payDetail.postValue(payDetail);
safeNavigateToRouteId();
}
}
@ -397,6 +434,48 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
popBackStack();
}
private void showExitConfirmation() {
new androidx.appcompat.app.AlertDialog.Builder(requireContext())
.setTitle("Exit QR Transaction?")
.setMessage("Are you sure you want to exit?")
.setCancelable(false)
.setPositiveButton("Yes", (dialog, which) -> {
dialog.dismiss();
if (sharedViewModel.isEcr.getValue() != null) {
if (sharedViewModel.isEcr.getValue()) {
finishECR();
}
}
closeOrder();
popBackStack();
})
.setNegativeButton("No", (dialog, which) -> dialog.dismiss())
.show();
}
private void closeOrder(){
String refNo = sharedViewModel.qrRefNum.getValue();
String mid = TransactionUtil.getInstance().getQRMerchantId();
if (refNo == null || mid == null) {
LogUtil.e("QR", "Missing ref or merchant ID. Cannot close order.");
return;
}
KPayQRRequest.CloseOrderRequest request = kPayViewModel.closeQrOrder(refNo, mid);
kPayViewModel.closeQrOrderApi(request)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
resp -> {
LogUtil.d("CloseOrder", "Result = " + resp.getResponse().getResult());
LogUtil.d("CloseOrder", "Msg = " + resp.getResponse().getMsg());
},
err -> {
LogUtil.e("CloseOrder", "Error = " + err.getMessage());
}
);
}
private String getECRResponseMessage() {
sharedViewModel.payDetail.setValue(payDetail);

View File

@ -7,7 +7,6 @@ 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;
@ -68,20 +67,6 @@ public class TestFragment extends DataBindingFragment {
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) {

View File

@ -27,6 +27,7 @@ public class ManagementViewModel extends ViewModel {
public SingleLiveEvent<String> processCodeText = new SingleLiveEvent<>();
public SingleLiveEvent<PayDetail> payDetail = new SingleLiveEvent<>();
public SingleLiveEvent<List<PayDetail>> payDetails = new SingleLiveEvent<>();
public SingleLiveEvent<String> panErrorMsg = new SingleLiveEvent<>();
@ -75,6 +76,10 @@ public class ManagementViewModel extends ViewModel {
return repository.getLastSettlement(voucherNo);
}
public LiveData<List<PayDetail>> getLastSettlementQR(String voucherNo){
return repository.getLastSettlementQR(voucherNo);
}
public LiveData<List<PayDetail>> getLastTransaction(String voucherNo){
return repository.getLastTransaction(voucherNo);
}

View File

@ -10,6 +10,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.utsmm.kbz.ui.kpay.KPayViewModel;
import com.utsmm.kbz.util.helper.KeyboardHelper;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.KPayQRQueryRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
@ -128,7 +129,7 @@ public class ReprintAnyTransactionFragment extends DataBindingFragment {
private void searchByTrace(String trace) {
for (PayDetail s : lists) {
if(s.getVoucherNo().equals(trace)) {
if(s.getVoucherNo().contains(trace)) {
searchedLists.add(s);
}
}
@ -151,19 +152,13 @@ public class ReprintAnyTransactionFragment extends DataBindingFragment {
String input = managementViewModel.txtRRNTrace.getValue();
if(input != null && !input.isEmpty()) {
if(input.length() == 6) {
searchByTrace(input);
} else if(input.length() == 12) {
searchByRRN(input);
}
searchByTrace(input);
} else {
searchedLists.addAll(lists);
}
cardViewAdapter.updateList(searchedLists);
KeyboardHelper.hide(requireActivity());
}
}
@ -296,13 +291,13 @@ public class ReprintAnyTransactionFragment extends DataBindingFragment {
// LogUtil.d(TAG,"Transaction settlement config : "+pay.isSettlementEnabled());
// LogUtil.d(TAG,"Transaction batch : "+pay.getBatchNo());
// LogUtil.d(TAG,"Current batch : "+SystemParamsOperation.getInstance().getCurrentBatchNum());
//
// LogUtil.d(TAG,"----------------------------------------------------------");
if(sharedViewModel.transactionsType.getValue() != null && sharedViewModel.transactionsType.getValue() == TransactionsType.MMQR_INQUIRY_STATUS) {
LogUtil.d(TAG,"----------------------------------------------------------");
if(sharedViewModel.transactionsType.getValue() != null && sharedViewModel.transactionsType.getValue() == TransactionsType.MMQR_HISTORY) {
// Wave Inquiry Status::
// April 2, 2024 QR Inquiry status check is for unsuccessful transactions.
if(yesterday.compareTo(transDate) <= 0 && pay.getTransactionType() == TransactionsType.MMQR.value && pay.getQrTransStatus() != 1) {
if(yesterday.compareTo(transDate) <= 0 && (pay.getTransactionType() == TransactionsType.MMQR.value || pay.getTransactionType() == TransactionsType.MMQR_REFUND.value) ) {
filteredLists.add(pay);
}
@ -367,7 +362,11 @@ public class ReprintAnyTransactionFragment extends DataBindingFragment {
* */
// sharedViewModel.transMenu.postValue(TransMenu.REPRINT);
sharedViewModel.setTransMenu(TransMenu.REPRINT);
payDetail.setTransType(payDetail.getTransType()+"(REPRINT)");
// payDetail.setTransType(payDetail.getTransType()+"(REPRINT)");
//tempo guarding the Reprint duplicate by kmk
if (!payDetail.getTransType().contains("REPRINT")) {
payDetail.setTransType(payDetail.getTransType() + "(REPRINT)");
}
sharedViewModel.payDetail.postValue(payDetail);
routeId = R.id.action_reprintAnyTransactionFragment_to_confirmTransactionFragment;

View File

@ -13,8 +13,8 @@ import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.DialogCallback;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.QRSettleData;
import com.utsmyanmar.paylibs.print.PrintHelper;
import com.utsmyanmar.paylibs.print.PrintReceipt;
import com.utsmyanmar.paylibs.print.printx.PrintXReceipt;
import com.utsmyanmar.paylibs.print.printx.PrintXStatus;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
@ -26,6 +26,7 @@ import com.utsmm.kbz.ui.core_viewmodel.TransProcessViewModel;
import java.util.List;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.enums.HostType;
public class ReprintReceiptFragment extends DataBindingFragment {
@ -34,7 +35,7 @@ public class ReprintReceiptFragment extends DataBindingFragment {
private ManagementViewModel managementViewModel;
private SharedViewModel sharedViewModel;
private static final String TAG = PrintReceipt.class.getSimpleName();
private static final String TAG = ReprintReceiptFragment.class.getSimpleName();
private PayDetail payDetail;
@ -108,7 +109,7 @@ public class ReprintReceiptFragment extends DataBindingFragment {
private void updateUIPrintReceiptFailure(PayDetail payDetail) {
sharedViewModel.printReceiptMsg.postValue(getString(R.string.txt_printing_settlement_report_failure));
sharedViewModel.reprintBtnLayout.postValue(0);
ReprintReceiptFragment.this.payDetail = payDetail;
// ReprintReceiptFragment.this.payDetail = payDetail;
}
private void checkPaperExists(PayDetail payDetail) {
@ -142,42 +143,56 @@ public class ReprintReceiptFragment extends DataBindingFragment {
}
private void observeLastSettlement() {
managementViewModel.getLastSettlement(SystemParamsOperation.getInstance().getCurrentSerialNum()).observe(getViewLifecycleOwner(), new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
if (payDetails != null) {
if (payDetails.size() != 0) {
PayDetail payDetail = payDetails.get(payDetails.size() - 1);
payDetail.setTransType( payDetail.getTransType()+"(REPRINT)");
checkPaperExists(payDetail);
} else {
showSingleInfoDialog(getString(R.string.txt_no_trans_to_print));
navigateMainScreen();
}
}
}
});
payDetail = sharedViewModel.payDetail.getValue();
payDetail.setTransType( payDetail.getTransType()+"(REPRINT)");
checkPaperExists(payDetail);
// managementViewModel.payDetail.observe(getViewLifecycleOwner(), new Observer<PayDetail>() {
// @Override
// public void onChanged(PayDetail pay) {
// if (pay != null) {
//
// payDetail = pay;
//
//
//
//
//
// } else {
// showSingleInfoDialog(getString(R.string.txt_no_trans_to_print));
// navigateMainScreen();
// }
// }
// });
}
private void printReceipt(PayDetail payDetail) {
PrintXReceipt.getInstance().printSmileSettlementReport(payDetail, new PrintXStatus() {
@Override
public void onSuccess() {
delayFunctionCall(ReprintReceiptFragment.this::navigateMainScreen);
}
@Override
public void onFailure() {
updateUIPrintReceiptFailure(payDetail);
if(sharedViewModel.hostType.getValue() == HostType.QR) {
PrintXReceipt.getInstance().printQRSettlementReport(payDetail, payDetail.getQrSettleData(), printXStatus);
} else {
PrintXReceipt.getInstance().printSmileSettlementReport(payDetail, printXStatus);
}
checkPaperExists(payDetail);
}
});
}
private PrintXStatus printXStatus = new PrintXStatus() {
@Override
public void onSuccess() {
delayFunctionCall(ReprintReceiptFragment.this::navigateMainScreen);
}
@Override
public void onFailure() {
updateUIPrintReceiptFailure(payDetail);
// checkPaperExists(payDetail);
}
};
@SuppressWarnings("ConstantConditions")
private void navigateMainScreen() {

View File

@ -72,6 +72,7 @@ public class SelectHostFragment extends DataBindingFragment implements DataBindi
}
}
checkQRButtonVisibility();
// try {
// int result = MyApplication.getInstance().basicOptBinder.setScreenMode(1);
// } catch (RemoteException e) {
@ -168,14 +169,16 @@ public class SelectHostFragment extends DataBindingFragment implements DataBindi
observerData();
isReturnTransactions();
}
private void isReturnTransactions() {
if(sharedViewModel.getTransMenu().getValue() == TransMenu.VOID || sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_COMPLETE_VOID || sharedViewModel.getTransMenu().getValue() == TransMenu.REVERSAL || sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_FULL_VOID) {
private void checkQRButtonVisibility() {
if(sharedViewModel.getTransMenu().getValue() == TransMenu.VOID || sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_COMPLETE_VOID || sharedViewModel.getTransMenu().getValue() == TransMenu.REVERSAL || sharedViewModel.getTransMenu().getValue() == TransMenu.PRE_AUTH_FULL_VOID ) {
sharedViewModel.qrPayVisibility.setValue(8);
} else {
sharedViewModel.qrPayVisibility.setValue(0);
}
}
@ -268,7 +271,20 @@ public class SelectHostFragment extends DataBindingFragment implements DataBindi
public void onChanged(List<PayDetail> payDetails) {
if (payDetails != null) {
if (!payDetails.isEmpty()) {
routeId = R.id.action_selectHostFragment_to_settlementTransactionFragment;
managementViewModel.payDetails.setValue(payDetails);
PayDetail payDetail = payDetails.get(payDetails.size() - 1);
if(sharedViewModel.hostType.getValue() == HostType.QR && payDetail.getTransactionType() == TransactionsType.MMQR_SETTLEMENT.value) {
routeId = R.id.action_selectHostFragment_to_QRSettlementTransactionFragment;
} else if(sharedViewModel.hostType.getValue() != HostType.MPU && payDetail.getTransactionType() == TransactionsType.SETTLEMENT.value) {
routeId = R.id.action_selectHostFragment_to_settlementTransactionFragment;
} else {
showSingleInfoDialog(getString(R.string.txt_no_trans_to_print));
routeId = R.id.action_selectHostFragment_to_nav_main;
}
} else {
showSingleInfoDialog(getString(R.string.txt_no_trans_to_print));
routeId = R.id.action_selectHostFragment_to_nav_main;
@ -283,6 +299,7 @@ public class SelectHostFragment extends DataBindingFragment implements DataBindi
});
}
private void observeRoute() {
switch (Objects.requireNonNull(sharedViewModel.getTransMenu().getValue())) {
case REVERSAL:
@ -296,13 +313,14 @@ public class SelectHostFragment extends DataBindingFragment implements DataBindi
clearBatch();
break;
case LAST_SETTLEMENT:
if(sharedViewModel.hostType.getValue() == HostType.MPU)
observeLastSettlement();
else {
showSingleInfoDialog(getString(R.string.txt_no_trans_to_print));
routeId = R.id.action_selectHostFragment_to_nav_main;
safeNavigateToRouteId();
}
observeLastSettlement();
// if(sharedViewModel.hostType.getValue() != HostType.QR) {
// observeLastSettlement();
// } else {
// showSingleInfoDialog(getString(R.string.txt_no_trans_to_print));
// routeId = R.id.action_selectHostFragment_to_nav_main;
// safeNavigateToRouteId();
// }
break;
case CLEAR_REVERSAL:
clearReversal();

View File

@ -5,6 +5,8 @@ import android.app.TimePickerDialog;
import androidx.lifecycle.Observer;
import com.google.android.material.timepicker.MaterialTimePicker;
import com.google.android.material.timepicker.TimeFormat;
import com.nexgo.oaf.apiv3.SdkResult;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
@ -153,11 +155,19 @@ public class TransactionSummaryFragment extends DataBindingFragment {
if (isStart) {
String selectedDate = dateFormat.format(myCalendar.getTime());
summaryViewModel.startDate.postValue(selectedDate);
LogUtil.d(TAG, "Start date updated: " + selectedDate);
// LogUtil.d(TAG, "Start date updated: " + selectedDate);
// STATIC START TIME
// summaryViewModel.startHr.setValue("00");
// summaryViewModel.startMin.setValue("00");
summaryViewModel.startDayOrNight.setValue(getString(R.string.txt_am));
} else {
String selectedDate = dateFormat.format(myCalendar2.getTime());
summaryViewModel.endDate.postValue(selectedDate);
LogUtil.d(TAG, "End date updated: " + selectedDate);
// STATIC END TIME
// summaryViewModel.endHr.setValue("23");
// summaryViewModel.endMin.setValue("59");
summaryViewModel.endDayOrNight.setValue(getString(R.string.txt_pm));
// LogUtil.d(TAG, "End date updated: " + selectedDate);
}
} catch (Exception e) {
LogUtil.e(TAG, "Error updating date label: " + e.getMessage());
@ -377,7 +387,7 @@ public class TransactionSummaryFragment extends DataBindingFragment {
private void printReceipt(PayDetail payDetail) {
try {
LogUtil.d(TAG, "Starting receipt print");
PrintXReceipt.getInstance().printSmileSummaryReport(payDetail, new PrintXStatus() {
PrintXReceipt.getInstance().printSmileSummaryReport(payDetail, sharedViewModel.hostType.getValue(), new PrintXStatus() {
@Override
public void onSuccess() {
LogUtil.d(TAG, "Receipt printed successfully");
@ -463,39 +473,92 @@ public class TransactionSummaryFragment extends DataBindingFragment {
}
public void onClickStartHr() {
showTimePicker(startTime, myCalendar);
// showTimePicker(startTime, myCalendar);
showMaterialTimePicker(myCalendar, true);
}
public void onClickEndHr() {
showTimePicker(endTime, myCalendar2);
// showTimePicker(endTime, myCalendar2);
showMaterialTimePicker(myCalendar2, false);
}
public void onClickStartMin() {
showTimePicker(startTime, myCalendar);
// showTimePicker(startTime, myCalendar);
showMaterialTimePicker(myCalendar, true);
}
public void onClickEndMin() {
showTimePicker(endTime, myCalendar2);
// showTimePicker(endTime, myCalendar2);
showMaterialTimePicker(myCalendar2, false);
}
public void onClickStartDayOrNight() {
showTimePicker(startTime, myCalendar);
// showTimePicker(startTime, myCalendar);
showMaterialTimePicker(myCalendar, true);
}
public void onClickEndDayOrNight() {
showTimePicker(endTime, myCalendar2);
// showTimePicker(endTime, myCalendar2);
showMaterialTimePicker(myCalendar2, false);
}
private void showTimePicker(TimePickerDialog.OnTimeSetListener listener, Calendar calendar) {
try {
TimePickerDialog timePickerDialog = new TimePickerDialog(requireContext(),
listener, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false);
TimePickerDialog timePickerDialog =
new TimePickerDialog(
requireContext(),
listener,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
false);
timePickerDialog.show();
} catch (Exception e) {
LogUtil.e(TAG, "Error showing time picker: " + e.getMessage());
}
}
private void showMaterialTimePicker(
Calendar calendar,
boolean isStart
) {
MaterialTimePicker timePicker = new MaterialTimePicker.Builder()
.setTimeFormat(TimeFormat.CLOCK_24H)
.setHour(calendar.get(Calendar.HOUR_OF_DAY))
.setMinute(calendar.get(Calendar.MINUTE))
.setInputMode(MaterialTimePicker.INPUT_MODE_KEYBOARD)
.setTitleText("Select Time")
.build();
timePicker.addOnPositiveButtonClickListener(v -> {
int hour = timePicker.getHour();
int minute = timePicker.getMinute();
calendar.set(Calendar.HOUR_OF_DAY, hour);
calendar.set(Calendar.MINUTE, minute);
String amPm = hour >= 12
? getString(R.string.txt_pm)
: getString(R.string.txt_am);
if (isStart) {
summaryViewModel.startHr.setValue(String.format(Locale.getDefault(), "%02d", hour));
summaryViewModel.startMin.setValue(String.format(Locale.getDefault(), "%02d", minute));
summaryViewModel.startDayOrNight.setValue(amPm);
} else {
summaryViewModel.endHr.setValue(String.format(Locale.getDefault(), "%02d", hour));
summaryViewModel.endMin.setValue(String.format(Locale.getDefault(), "%02d", minute));
summaryViewModel.endDayOrNight.setValue(amPm);
}
LogUtil.d(TAG, (isStart ? "Start" : "End") +
" time selected: " + hour + ":" + minute);
});
timePicker.show(getParentFragmentManager(), "material_time_picker");
}
public void onPrint() {
try {
if (summaryViewModel.validateField()) {

View File

@ -104,7 +104,7 @@ public class ManualEntryFragment extends DataBindingFragment {
payDetail.setAccountType(manualEntryViewModel.get_cardScheme().getValue().name);
}
payDetail.setICC55("");
payDetail.setAuthNo(manualEntryViewModel.cvv.getValue());
// payDetail.setAuthNo(manualEntryViewModel.cvv.getValue());
emvTransactionProcessViewModel.setTradeData(tradeData);
@ -166,7 +166,7 @@ public class ManualEntryFragment extends DataBindingFragment {
public void onConfirm() {
if(manualEntryViewModel.validateData()) {
if(sharedViewModel.transactionsType.getValue() == TransactionsType.REFUND || sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_SALE || sharedViewModel.transactionsType.getValue() == TransactionsType.SALE || sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_VOID) {
if(sharedViewModel.transactionsType.getValue() == TransactionsType.REFUND || sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_SALE || sharedViewModel.transactionsType.getValue() == TransactionsType.SALE || sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_VOID || sharedViewModel.transactionsType.getValue() == TransactionsType.PRE_AUTH_COMPLETE) {
if(manualEntryViewModel.get_cardScheme().getValue() != null && manualEntryViewModel.get_cardScheme().getValue() == CardScheme.MPU) {
processMPUCard();

View File

@ -90,6 +90,9 @@ public class ManualEntryViewModel extends ViewModel {
return expDate;
}
private boolean validateCard() {
return (cardFieldState.getValue() == EntryState.UNSELECTED && expFieldState.getValue() == EntryState.UNSELECTED && expDate.getValue() != null && !expDate.getValue().isEmpty()) ;
}
private boolean validateDataMPU() {
return (cardFieldState.getValue() == EntryState.UNSELECTED && expFieldState.getValue() == EntryState.UNSELECTED && expDate.getValue() != null && !expDate.getValue().isEmpty()) ;
}
@ -106,8 +109,9 @@ public class ManualEntryViewModel extends ViewModel {
}
public boolean validateData() {
if(_cardScheme.getValue() == CardScheme.MPU) return validateDataMPU();
else return validateDataEmv();
return validateCard();
// if(_cardScheme.getValue() == CardScheme.MPU) return validateDataMPU();
// else return validateDataEmv();
}
public void resetUI() {
@ -306,23 +310,23 @@ public class ManualEntryViewModel extends ViewModel {
if (pan.startsWith("4"))
{
_cardScheme.setValue(CardScheme.VISA);
cvvVisibility.setValue(0);
// cvvVisibility.setValue(0);
}
else if (pan.startsWith("51") || pan.startsWith("52") || pan.startsWith("53") || pan.startsWith("54") || pan.startsWith("55")) {
_cardScheme.setValue(CardScheme.MASTERCARD);
cvvVisibility.setValue(0);
// cvvVisibility.setValue(0);
}
else if (pan.startsWith("3528")) {
if(pan.length() > 4 && (Integer.parseInt(pan.substring(0, 4)) >= 3528 && Integer.parseInt(pan.substring(0, 4)) <= 3589)) {
_cardScheme.setValue(CardScheme.JCB);
cvvVisibility.setValue(0);
// cvvVisibility.setValue(0);
}
}
else if (pan.startsWith("60") || pan.startsWith("62") || pan.startsWith("65") || pan.startsWith("81"))
{
_cardScheme.setValue(CardScheme.UPI);
cvvVisibility.setValue(0);
// cvvVisibility.setValue(0);
}
else
{

View File

@ -2,8 +2,20 @@ package com.utsmm.kbz.ui.navigation;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import com.nexgo.oaf.apiv3.APIProxy;
import com.nexgo.oaf.apiv3.DeviceEngine;
import com.nexgo.oaf.apiv3.DeviceInfo;
import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.oaf.apiv3.device.printer.AlignEnum;
import com.nexgo.oaf.apiv3.device.printer.GrayLevelEnum;
import com.nexgo.oaf.apiv3.device.printer.LineOptionEntity;
import com.nexgo.oaf.apiv3.device.printer.Printer;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.sirius.SiriusHost;
import com.utsmyanmar.baselib.network.model.sirius.SiriusMerchant;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.sign_on.EchoTestProcess;
@ -13,6 +25,8 @@ import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import java.util.List;
public class NaviMainFragment extends DataBindingFragment {
private OnFragmentInteractionListener mListener;
@ -137,6 +151,7 @@ public class NaviMainFragment extends DataBindingFragment {
});
}
public void onClickLogOff() {
showLoadingDialog("Sending LogOff!");
@ -176,6 +191,34 @@ public class NaviMainFragment extends DataBindingFragment {
mListener.onClickFunction();
}
private GrayLevelEnum getGrayLevel() {
int gray = 2;
GrayLevelEnum grayLevelEnum = GrayLevelEnum.LEVEL_1;
switch (gray) {
case 0:
grayLevelEnum = GrayLevelEnum.LEVEL_0;
break;
case 1:
grayLevelEnum = GrayLevelEnum.LEVEL_1;
break;
case 2:
grayLevelEnum = GrayLevelEnum.LEVEL_2;
break;
case 3:
grayLevelEnum = GrayLevelEnum.LEVEL_3;
break;
case 4:
grayLevelEnum = GrayLevelEnum.LEVEL_4;
break;
default:
grayLevelEnum = GrayLevelEnum.LEVEL_1;
break;
}
return grayLevelEnum;
}
public void onClickVersion(){
mListener.onClickVersion();
}
@ -184,7 +227,6 @@ public class NaviMainFragment extends DataBindingFragment {
mListener.onClickExit();
}
}
public interface OnFragmentInteractionListener {
@ -195,5 +237,6 @@ public class NaviMainFragment extends DataBindingFragment {
void onClickVersion();
void onClickExit();
}
}

View File

@ -6,6 +6,8 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.nexgo.oaf.apiv3.DeviceEngine;
import com.nexgo.oaf.apiv3.DeviceInfo;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmm.kbz.BR;
@ -32,6 +34,7 @@ public class VersionFragment extends DataBindingFragment {
setToolBarTitleWithBackIcon(getString(R.string.title_version));
fetchVersions();
versionViewModel.loadDeviceInfo(requireContext());
}
@Override
@ -75,5 +78,4 @@ public class VersionFragment extends DataBindingFragment {
}

View File

@ -1,13 +1,13 @@
package com.utsmm.kbz.ui.navigation;
import android.os.RemoteException;
import android.content.Context;
import androidx.lifecycle.ViewModel;
import com.sunmi.pay.hardware.aidl.AidlConstants;
import com.nexgo.oaf.apiv3.APIProxy;
import com.nexgo.oaf.apiv3.DeviceEngine;
import com.nexgo.oaf.apiv3.DeviceInfo;
import com.utsmyanmar.paylibs.system.SingleLiveEvent;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.MyApplication;
public class VersionViewModel extends ViewModel {
@ -28,31 +28,25 @@ public class VersionViewModel extends ViewModel {
public VersionViewModel() {
initData();
// initData();
// loadDeviceInfo();
}
private void initData() {
String txtHardwareVersion = getParams(AidlConstants.SysParam.HARDWARE_VERSION);
hardwareVersion.setValue(txtHardwareVersion);
String txtFirmwareVersion = getParams(AidlConstants.SysParam.FIRMWARE_VERSION);
firmwareVersion.setValue(txtFirmwareVersion);
String txtSerialNo = getParams(AidlConstants.SysParam.SN);
serialNumber.setValue(txtSerialNo);
String txtDeviceModel = getParams(AidlConstants.SysParam.DEVICE_MODEL);
deviceModel.setValue(txtDeviceModel);
swFinalVersion.setValue(SystemParamsOperation.getInstance().getFinalVersion());
}
private String getParams(String name) {
String value = "";
try {
value = MyApplication.getInstance().basicOptBinder.getSysParam(name);
} catch (RemoteException e) {
e.printStackTrace();
public void loadDeviceInfo(Context context){
try{
DeviceEngine deviceEngine = APIProxy.getDeviceEngine(context);
DeviceInfo deviceInfo = deviceEngine.getDeviceInfo();
serialNumber.setValue(deviceInfo.getSn());
deviceModel.setValue(deviceInfo.getModel());
hardwareVersion.setValue(deviceInfo.getKernelVer());
firmwareVersion.setValue(deviceInfo.getFirmWareVer());
swFinalVersion.setValue(deviceInfo.getFirmWareFullVersion());
payHardwareVersion.setValue(deviceInfo.getSpCoreVersion());
romVersion.setValue(deviceInfo.getOsVer());
} catch (Exception e) {
throw new RuntimeException(e);
}
return value;
}

View File

@ -13,11 +13,11 @@ import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.oaf.apiv3.device.pinpad.AlgorithmModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.OnPinPadInputListener;
import com.nexgo.oaf.apiv3.device.pinpad.PinAlgorithmModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.PinKeyboardModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.PinKeyboardViewModeEnum;
import com.nexgo.oaf.apiv3.device.pinpad.PinPad;
import com.nexgo.oaf.apiv3.device.pinpad.PinPadKeyCode;
import com.nexgo.oaf.apiv3.device.pinpad.PinpadLayoutEntity;
import com.sunmi.pay.hardware.aidlv2.pinpad.PinPadOptV2;
import com.utsmyanmar.baselib.BaseApplication;
import com.utsmyanmar.baselib.ui.CustomPinPadKeyboard;
@ -37,7 +37,6 @@ public class PinPadViewModel extends ViewModel {
private static final String TAG = PinPadViewModel.class.getSimpleName();
private PinPadOptV2 mPinPadOptV2;
public SingleLiveEvent<String> pinText = new SingleLiveEvent<>();
public SingleLiveEvent<String> alertMsg = new SingleLiveEvent<>();
@ -119,7 +118,12 @@ public class PinPadViewModel extends ViewModel {
case ON_CONFIRM_CLICK:
LogUtil.d(TAG, "ON CLICK CONFIRM");
// increasedKSN();
pinStatus.postValue(PinPadStatus.ON_CONFIRM);
if(transType.getValue() == TransactionsType.PRE_AUTH_COMPLETE || transType.getValue() == TransactionsType.PRE_AUTH_VOID || transType.getValue() == TransactionsType.REFUND ) {
pinStatus.postValue(PinPadStatus.ON_NEXT_SCREEN);
} else {
pinStatus.postValue(PinPadStatus.ON_CONFIRM);
}
break;
case ON_CANCEL_CLICK:
LogUtil.d(TAG, "ON CLICK CANCEL");
@ -168,13 +172,13 @@ public class PinPadViewModel extends ViewModel {
}
public void cancelPinPad() {
try {
mPinPadOptV2.cancelInputPin();
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
// public void cancelPinPad() {
// try {
// mPinPadOptV2.cancelInputPin();
// } catch (RemoteException e) {
// throw new RuntimeException(e);
// }
// }
private void increasedKSN() {
pinPad.dukptKsnIncrease(pinIndex); //3
@ -317,6 +321,8 @@ public class PinPadViewModel extends ViewModel {
r.bottom = customPinPadKeyboard.getKey_ok().getHeight() + r.top;
pinpadLayout.setKeyConfirm(r);
pinPad.setPinKeyboardMode(PinKeyboardModeEnum.FIXED);
byte[] number = pinPad.setPinpadLayout(pinpadLayout);
if(number != null) {
@ -331,6 +337,8 @@ public class PinPadViewModel extends ViewModel {
byte[] panBytes = pan.substring(length - 13).getBytes(StandardCharsets.US_ASCII);
// byte[] panBytes = pan.substring(length - 13, length - 1).getBytes(StandardCharsets.US_ASCII);
pinPad.setPinKeyboardViewMode(PinKeyboardViewModeEnum.DEFAULT);
pinPad.setPinKeyboardMode(PinKeyboardModeEnum.FIXED);
// pinPad.setAlgorithmMode(AlgorithmModeEnum.DES);

View File

@ -8,6 +8,9 @@ import com.utsmyanmar.paylibs.model.PayDetail;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class PreAuthVoidViewModel extends ViewModel {
private Repository repository;

View File

@ -0,0 +1,61 @@
package com.utsmm.kbz.ui.qr_pay;
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.R;
import com.utsmm.kbz.databinding.ItemQrHistoryBinding;
import com.utsmyanmar.paylibs.model.PayDetail;
import java.util.ArrayList;
import java.util.List;
public class QRHistoryAdapter extends RecyclerView.Adapter<QRHistoryAdapter.ViewHolder> {
private List<PayDetail> items = new ArrayList<>();
public void setItems(List<PayDetail> data){
items = data;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemQrHistoryBinding binding = DataBindingUtil.inflate(
LayoutInflater.from(parent.getContext()),
R.layout.item_qr_history,
parent,
false
);
return new ViewHolder(binding);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
holder.bind(items.get(position));
}
@Override
public int getItemCount() {
return items.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
private final ItemQrHistoryBinding binding;
public ViewHolder(@NonNull ItemQrHistoryBinding binding){
super(binding.getRoot());
this.binding = binding;
}
public void bind(PayDetail item){
binding.setPayDetail(item);
binding.executePendingBindings();
}
}
}

View File

@ -0,0 +1,78 @@
package com.utsmm.kbz.ui.qr_pay;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import dagger.hilt.android.AndroidEntryPoint;
@AndroidEntryPoint
public class QRHistoryFragment extends DataBindingFragment {
private QRHistoryAdapter adapter;
private QRHistoryViewModel viewModel;
@Override
protected void initViewModel() {
viewModel = new ViewModelProvider(this).get(QRHistoryViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
DataBindingConfig bindingConfig = new DataBindingConfig(R.layout.fragment_qr_history, BR.viewModel, viewModel);
bindingConfig.addBindingParam(BR.adapter, adapter);
return bindingConfig;
}
@Override
protected int currentId() {
return 0;
}
@Override
protected int hostId() {
return 0;
}
@Override
protected int routeId() {
return 0;
}
@Override
public void onResume(){
super.onResume();
setToolBarTitleWithBackIcon("History");
observeData();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstance){
super.onViewCreated(view, savedInstance);
RecyclerView rvHistory = view.findViewById(R.id.qrRvHistory);
rvHistory.setLayoutManager(new LinearLayoutManager(getContext()));
adapter = new QRHistoryAdapter();
rvHistory.setAdapter(adapter);
observeData();
}
private void observeData(){
viewModel.getAllQrHistory().observe(getViewLifecycleOwner(), list -> {
adapter.setItems(list);
});
}
}

View File

@ -0,0 +1,35 @@
package com.utsmm.kbz.ui.qr_pay;
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;
import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class QRHistoryViewModel extends ViewModel {
private final Repository repository;
private final LiveData<List<PayDetail>> history;
private final LiveData<List<PayDetail>> refundList;
@Inject
public QRHistoryViewModel(Repository repository){
this.repository = repository;
this.history = repository.getAllQRHistory();
this.refundList = repository.getRefundableQRHistory();
}
public LiveData<List<PayDetail>> getAllQrHistory(){
return history;
}
public LiveData<List<PayDetail>> getRefundableQrHistory(){
return refundList;
}
}

View File

@ -0,0 +1,407 @@
package com.utsmm.kbz.ui.qr_pay;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;
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.adapters.QRPayAdapter;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmm.kbz.ui.management.ManagementViewModel;
import com.utsmm.kbz.ui.settlement.SettlementViewModel;
import com.utsmm.kbz.util.Connectivity;
import com.utsmm.kbz.util.tms.TMSUtil;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.utils.LogUtil;
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.HostType;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
public class QRPayFragment extends DataBindingFragment {
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.qrFragment;
private Observer<PayDetail> observeLastTrans;
private PayDetail lastPay;
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon("MMQR PAY");
}
@Override
protected void initViewModel() {
mainViewModel = new ViewModelProvider(requireActivity()).get(MainViewModel.class);
// sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
boolean isQrRefundEnable = SystemParamsOperation.getInstance().getQrRefundEnable();
List<QRPayItem> features = new ArrayList<>();
features.add(new QRPayItem("Sale", R.drawable.ic_qr_pay, true));
if(isQrRefundEnable){
features.add(new QRPayItem("Refund", R.drawable.ic_refund, true));
}
features.add(new QRPayItem("History", R.drawable.ic_history, true));
// List<QRPayItem> features = List.of(
// new QRPayItem("Sale", R.drawable.ic_qr_pay, true),
// new QRPayItem("Refund", R.drawable.ic_refund, false),
// new QRPayItem("History", R.drawable.ic_history, true)
// );
QRPayAdapter adapter = new QRPayAdapter(features, position -> {
QRPayItem selectedBtn = features.get(position);
switch (selectedBtn.title){
case "Sale":
onClickQRPay();
break;
case "Refund":
onClickRefund();
break;
case "History":
onClickHistory();
break;
}
});
DataBindingConfig config = new DataBindingConfig(R.layout.fragment_qr_pay, BR.mainViewModel, mainViewModel);
config.addBindingParam(BR.sharedViewModel,sharedViewModel);
config.addBindingParam(BR.adapter, adapter);
return config;
}
@Override
protected int currentId() {
return currentId;
}
@Override
protected int hostId() {
return hostId;
}
@Override
protected int routeId() {
return routeId;
}
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();
}
}
private void onClickHistory(){
sharedViewModel.hostType.setValue(HostType.QR);
sharedViewModel.setTransactionsType(TransactionsType.MMQR_HISTORY);
routeId = R.id.action_qrFragment_to_qrHistory;
safeNavigateToRouteId();
}
private void onClickRefund(){
// sharedViewModel.setTransactionsType(TransactionsType.MMQR_REFUND);
routeId = R.id.action_qrFragment_to_qr_refund_list;
// routeId = R.id.action_qrFragment_to_inputPasswordFragment;
safeNavigateToRouteId();
}
private void navigateToAmount() {
routeId = R.id.action_qrFragment_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);
}
}
}

View File

@ -0,0 +1,14 @@
package com.utsmm.kbz.ui.qr_pay;
public class QRPayItem {
public String title;
public int icon;
public boolean isActive;
public QRPayItem(String title, int icon, boolean isActive) {
this.title = title;
this.icon = icon;
this.isActive = isActive;
}
}

View File

@ -0,0 +1,51 @@
package com.utsmm.kbz.ui.qr_pay;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.paylibs.model.PayDetail;
import java.util.List;
import javax.inject.Inject;
import dagger.hilt.android.lifecycle.HiltViewModel;
@HiltViewModel
public class QRPayViewModel extends ViewModel {
private final Repository repository;
private final LiveData<List<PayDetail>> refundableHistory;
private final RefundCertificateManager refundCertificateManager;
private final MutableLiveData<PayDetail> _payDetail = new MutableLiveData<>();
public LiveData<PayDetail> payDetail = _payDetail;
@Inject
public QRPayViewModel(
Repository repository,
RefundCertificateManager refundCertificateManager
){
this.repository = repository;
this.refundableHistory = repository.getRefundableQRHistory();
this.refundCertificateManager = refundCertificateManager;
}
public LiveData<List<PayDetail>> getRefundableQrHistory(){
return refundableHistory;
}
public void setPayDetail(PayDetail payDetail){
_payDetail.setValue(payDetail);
}
public void checkCertificateFiles(){
refundCertificateManager.updateCertificateFiles();
}
public Runnable onCancel;
public Runnable onConfirm;
}

View File

@ -0,0 +1,49 @@
package com.utsmm.kbz.ui.qr_pay;
public class QRRefund {
private String referenceNo;
private String refundAmount;
private String originalAmount;
private String reason;
public QRRefund(String referenceNo, String refundAmount, String originalAmount, String reason) {
this.referenceNo = referenceNo;
this.refundAmount = refundAmount;
this.originalAmount = originalAmount;
this.reason = reason;
}
public String getReferenceNo() {
return referenceNo;
}
public void setReferenceNo(String referenceNo) {
this.referenceNo = referenceNo;
}
public String getRefundAmount() {
return refundAmount;
}
public void setRefundAmount(String refundAmount) {
this.refundAmount = refundAmount;
}
public String getOriginalAmount() {
return originalAmount;
}
public void setOriginalAmount(String originalAmount) {
this.originalAmount = originalAmount;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
}

View File

@ -0,0 +1,235 @@
package com.utsmm.kbz.ui.qr_pay;
import android.os.Bundle;
import android.text.InputFilter;
import android.util.Log;
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.utsmm.kbz.ui.kpay.KPayViewModel;
import com.utsmm.kbz.util.helper.KeyboardHelper;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
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 java.text.DecimalFormat;
public class QRRefundDetailFragment 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 String originalRefundAmount;
private boolean isPartialRefund = false;
private static final String TAG = com.utsmm.kbz.ui.kpay.QRRefundFragment.class.getSimpleName();
private static final int hostId = Constants.NAV_HOST_ID;
private static final int currentId = R.id.qrRefundDetail;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
kPayViewModel = getFragmentScopeViewModel(KPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_qr_refund_detail, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.kPayViewModel, kPayViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return currentId;
}
@Override
protected int hostId() {
return hostId;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState){
super.onCreate(savedInstanceState);
if(getArguments() != null){
payDetail = (PayDetail) getArguments().getSerializable("payDetail");
}
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon("QR Refund");
kPayViewModel.invalidAmountMsg.setValue("");
}
@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() {
double realAmount = payDetail.getAmount() / 100.0;
DecimalFormat df = new DecimalFormat("0.00");
originalRefundAmount = df.format(realAmount);
payDetail = TransactionUtil.getInstance().initWalletTransaction(TransactionsType.MMQR_REFUND);
payDetail.setInvoiceNo(SystemParamsOperation.getInstance().getIncrementInvoiceNum());
if(getArguments() != null){
PayDetail passData = (PayDetail) getArguments().getSerializable("payDetail");
if(passData != null && passData.getReferNo() != null){
etReferenceNo.setText(passData.getReferNo());
etReferenceNo.setEnabled(false);
}
}
}
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);
}
});
}
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;
}
QRRefund qrRefund = new QRRefund(referenceNo, refundAmountStr, originalAmountStr, refundReason);
kPayViewModel.setQrRefund(qrRefund);
} else {
// String originalAmountStr = etOriginalAmount.getText().toString().trim();
// String refundAmountStr = etRefundAmount.getText().toString().trim();
QRRefund qrRefund = new QRRefund(referenceNo, "0", originalRefundAmount, refundReason);
kPayViewModel.setQrRefund(qrRefund);
}
sharedViewModel.transactionsType.setValue(TransactionsType.MMQR_REFUND);
kPayViewModel.setPayDetail(payDetail);
// sharedViewModel.amount.setValue(refundAmountStr);
KeyboardHelper.hide(requireActivity());
routeId = R.id.action_qrRefundDetail_inputPasswordFragment;
safeNavigateToRouteId();
}
}
}

View File

@ -0,0 +1,147 @@
package com.utsmm.kbz.ui.qr_pay;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.RadioGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.fragment.NavHostFragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
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.kpay.KPayViewModel;
import com.utsmm.kbz.util.helper.KeyboardHelper;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import java.util.ArrayList;
import java.util.List;
public class QRRefundFragment extends DataBindingFragment {
private static final int hostId = Constants.NAV_HOST_ID;
private int routeId;
private static final int currentId = R.id.qrRefundList;
private QRPayViewModel qrPayViewModel;
private SharedViewModel sharedViewModel;
private QRRefundViewAdapter adapter;
private LinearLayout emptyStateView;
@Override
protected int currentId() {
return currentId;
}
@Override
protected int hostId() {return hostId;}
@Override
protected int routeId() {return routeId;}
@Override
protected void initViewModel() {
sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
qrPayViewModel = new ViewModelProvider(requireActivity()).get(QRPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
adapter = new QRRefundViewAdapter(this::onRefundItemClicked);
return new DataBindingConfig(R.layout.fragment_qr_refund, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.adapter, adapter)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
public void onResume(){
super.onResume();
setToolBarTitleWithBackIcon("QR Refund");
}
@Override
public void onCreate(@Nullable Bundle savedInstance){
super.onCreate(savedInstance);
adapter = new QRRefundViewAdapter(this::onRefundItemClicked);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
RecyclerView recyclerView = view.findViewById(R.id.qrRefundHistory);
recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
recyclerView.setAdapter(adapter);
emptyStateView = view.findViewById(R.id.emptyStateSectionRefund);
qrPayViewModel.checkCertificateFiles();
observeData();
}
private void observeData(){
qrPayViewModel.getRefundableQrHistory().observe(getViewLifecycleOwner(), this::updateList);
}
private void updateList(List<PayDetail> list){
if (adapter == null) {
return;
}
if(list == null || list.isEmpty()){
emptyStateView.setVisibility(View.VISIBLE);
getView().findViewById(R.id.qrRefundHistory).setVisibility(View.GONE);
}else{
emptyStateView.setVisibility(View.GONE);
getView().findViewById(R.id.qrRefundHistory).setVisibility(View.VISIBLE);
adapter.setData(list);
}
}
public class ClickEvent {
public void onCancel(){
safeNavigateToRouteId();
}
public void onSearch(){
searchByTrace();
KeyboardHelper.hide(requireActivity());
}
}
private void onRefundItemClicked(PayDetail payDetail) {
Bundle bundle = new Bundle();
bundle.putSerializable("payDetail", payDetail);
routeId = R.id.action_qrRefundList_to_qrRefundDetail;
NavHostFragment.findNavController(this).navigate(routeId, bundle);
}
private void searchByTrace(){
EditText editText = getView().findViewById(R.id.rnn_trace_id);
String keyword = editText.getText().toString().trim();
if(keyword.isEmpty()){
updateList(qrPayViewModel.getRefundableQrHistory().getValue());
return;
}
List<PayDetail> originalList = qrPayViewModel.getRefundableQrHistory().getValue();
if(originalList == null) return;
List<PayDetail> filteredList = new ArrayList<>();
for(PayDetail item: originalList){
boolean match = item.getVoucherNo() != null && item.getVoucherNo().contains(keyword);
if(match){
filteredList.add(item);
}
}
updateList(filteredList);
}
}

View File

@ -0,0 +1,257 @@
package com.utsmm.kbz.ui.qr_pay;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
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.kpay.KPayViewModel;
import com.utsmm.kbz.ui.kpay.QRRefundFragment;
import com.utsmm.kbz.util.EReceiptUtil;
import com.utsmm.kbz.util.TransactionUtil;
import com.utsmm.kbz.util.ecr.CoreUtils;
import com.utsmm.kbz.util.enums.TransResultStatus;
import com.utsmm.kbz.util.tms.TMSUtil;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.KPayRefund;
//import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptQRRequest;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.system.SystemDateTime;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.POSUtil;
import java.text.DecimalFormat;
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;
public class QRRefundProcessFragment extends DataBindingFragment {
private static final String TAG = QRRefundProcessFragment.class.getSimpleName();
private SharedViewModel sharedViewModel;
private KPayViewModel kPayViewModel;
private PayDetail payDetail;
private QRRefund qrRefund;
private static final int hostId = Constants.NAV_HOST_ID;
private int routeId;
private static final int currentId = R.id.QRRefundProcessFragment;
CompositeDisposable retrieveUpdateDisposable = new CompositeDisposable();
CompositeDisposable refundDisposable = new CompositeDisposable();
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
kPayViewModel = getFragmentScopeViewModel(KPayViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_qr_refund_process, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.kPayViewModel, kPayViewModel);
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithoutBackIcon("QR Refund Process");
}
@Override
public void onDestroyView() {
super.onDestroyView();
retrieveUpdateDisposable.dispose();
refundDisposable.dispose();
}
@Override
protected int currentId() {
return currentId;
}
@Override
protected int hostId() {
return hostId;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
initData();
processKPayRefund(qrRefund.getReferenceNo(), qrRefund.getRefundAmount(), qrRefund.getOriginalAmount(), qrRefund.getReason());
}
private void initData() {
payDetail = kPayViewModel.getPayDetail();
qrRefund = kPayViewModel.getQrRefund();
}
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";
// 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 -> {
handleRefundResponse(response, referenceNo, originalAmount);
},
throwable -> {
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, String orgAmount) {
if (response != null && response.getResponse() != null && "REFUND_SUCCESS".equalsIgnoreCase(response.getResponse().getRefundStatus())) {
LogUtil.d(TAG, "Refund successful!");
String refundAmount = response.getResponse().getRefundAmount();
long text = POSUtil.getInstance().convertAmount(refundAmount);
String dateTime = SystemDateTime.getTodayDateFormat() + " " + SystemDateTime.getTodayTimeFormat();
payDetail.setTC(response.getResponse().getRefundStatus());
payDetail.setAmount(refundAmount == null ? 0 : POSUtil.getInstance().convertAmount(refundAmount));
payDetail.setOriginalTransDate(dateTime);
payDetail.setQrTransStatus(1);
if(response.getResponse().getMmqrRef() != null) {
payDetail.setQrReferNo(response.getResponse().getMmqrRef());
}
payDetail.setReferNo(referenceNo);
payDetail.setIsCanceled(true);
payDetail.setCustomerMobile(response.getResponse().getWalletIdentifier());
payDetail.setTradeDateAndTime(response.getResponse().getRefundTime());
EReceiptRequest request = EReceiptUtil.getInstance().generateQRRefundReceipt(
refundAmount,
referenceNo,
payDetail != null ? payDetail.getInvoiceNo() : "",
payDetail != null ? payDetail.getVoucherNo() : "",
payDetail != null ? payDetail.getQrReferNo() != null ? payDetail.getQrReferNo() : "" : "" ,
payDetail != null ? payDetail.getCustomerMobile() : "",
TransResultStatus.SUCCESS
);
sharedViewModel.pushReceipt(request);
sharedViewModel.amount.setValue(refundAmount);
retrievedUpdatePayDetail(referenceNo);
} else {
LogUtil.d(TAG, "Refund failed!");
payDetail.setQrTransStatus(-1);
payDetail.setReferNo(referenceNo);
String errorMsg = "Refund failed";
if (response != null && response.getResponse() != null && response.getResponse().getMsg() != null) {
errorMsg = response.getResponse().getMsg();
}
payDetail.setTradeResultDes(errorMsg);
EReceiptRequest request = EReceiptUtil.getInstance().generateQRRefundReceipt(
"0",
referenceNo,
payDetail != null ? payDetail.getInvoiceNo() : "",
payDetail != null ? payDetail.getVoucherNo() : "",
payDetail != null ? payDetail.getQrReferNo() != null ? payDetail.getQrReferNo() : "" : "" ,
payDetail != null ? payDetail.getCustomerMobile() : "",
TransResultStatus.FAIL
);
sharedViewModel.pushReceipt(request);
sharedViewModel.amount.setValue(orgAmount);
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 navigateToNext() {
routeId = R.id.action_QRRefundProcessFragment_to_transactionResultFragment;
safeNavigateToRouteId();
}
private void navigateToMain() {
routeId = R.id.action_QRRefundProcessFragment_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,84 @@
package com.utsmm.kbz.ui.qr_pay;
import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.databinding.ItemQrRefundBinding;
import com.utsmm.kbz.ui.adapters.QRPayAdapter;
import com.utsmyanmar.paylibs.model.PayDetail;
import java.util.ArrayList;
import java.util.List;
public class QRRefundViewAdapter extends RecyclerView.Adapter<QRRefundViewAdapter.ViewHolder> {
private List<PayDetail> payDetailList = new ArrayList<>();
private final OnRefundItemClick listener;
public interface OnRefundItemClick {
void onClick(PayDetail payDetail);
}
public QRRefundViewAdapter(OnRefundItemClick listener){
this.listener = listener;
}
// public QRRefundViewAdapter(List<PayDetail> payDetailList, OnRefundItemClick listener){
// this.payDetailList = payDetailList;
// this.listener = listener;
// }
public void setData(List<PayDetail> data){
this.payDetailList = data != null ? data : new ArrayList<>();
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
ItemQrRefundBinding binding = DataBindingUtil.inflate(
LayoutInflater.from(parent.getContext()),
R.layout.item_qr_refund,
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 == null ? 0 : payDetailList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
private final ItemQrRefundBinding binding;
public ViewHolder(ItemQrRefundBinding binding){
super(binding.getRoot());
this.binding = binding;
}
public void bind(PayDetail payDetail, OnRefundItemClick listener){
binding.setVariable(BR.payDetail, payDetail);
binding.executePendingBindings();
binding.getRoot().setOnClickListener( v -> {
if(listener != null) listener.onClick(payDetail);
});
}
}
}

View File

@ -0,0 +1,107 @@
package com.utsmm.kbz.ui.qr_pay;
import com.utsmm.kbz.util.DownloadUtil;
import com.utsmyanmar.baselib.util.EReceiptHelper;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public class RefundCertificateManager {
private static final String TAG = RefundCertificateManager.class.getSimpleName();
private static final String E_RECEIPT_SECRET =
com.utsmyanmar.baselib.BuildConfig.ERECEIPT_SECRET;
// Prevent duplicate parallel downloads
private final AtomicBoolean isUpdating = new AtomicBoolean(false);
@Inject
public RefundCertificateManager() {
}
/**
* Download & refresh refund certificates.
* Safe to call multiple times.
*/
public void updateCertificateFiles() {
if (!isUpdating.compareAndSet(false, true)) {
LogUtil.d(TAG, "Certificate update already in progress");
return;
}
try {
String tmsAddress = SystemParamsOperation.getInstance().getTmsAddress();
if (tmsAddress == null || tmsAddress.trim().isEmpty()) {
LogUtil.e(TAG, "TMS address is empty");
return;
};
String downloadBase = tmsAddress.trim() + "/api/v1/file/download?filePath="; //local
// String downloadBase = tmsAddress.trim() + "/file/download?filePath="; // uat and prod
String certUrl = SystemParamsOperation.getInstance().getCertificateUrl();
String clientCertUrl = SystemParamsOperation.getInstance().getCertificateClientUrl();
if (certUrl == null || clientCertUrl == null) {
LogUtil.e(TAG, "Certificate URLs are missing");
return;
}
String timestamp = String.valueOf(System.currentTimeMillis());
String signature = generateSignature(timestamp);
// LogUtil.d(TAG, "Download base => " + downloadBase);
// LogUtil.d(TAG, "Cert URL => " + certUrl);
// LogUtil.d(TAG, "Client Cert URL => " + clientCertUrl);
// ---------- CA CERT ----------
DownloadUtil.downloadCertificateRx(
downloadBase + certUrl,
"refund_ca_" + "file", // IMPORTANT: unique filename
timestamp,
signature,
path -> {
if (path != null) {
SystemParamsOperation.getInstance()
.setCertFilePath(path);
LogUtil.d(TAG, "CA cert saved => " + path);
} else {
LogUtil.e(TAG, "Failed to download CA cert");
}
}
);
// ---------- CLIENT CERT ----------
DownloadUtil.downloadCertificateRx(
downloadBase + clientCertUrl,
"refund_client_" + "file", // IMPORTANT: unique filename
timestamp,
signature,
path -> {
if (path != null) {
SystemParamsOperation.getInstance()
.setCertClientFilePath(path);
LogUtil.d(TAG, "Client cert saved => " + path);
} else {
LogUtil.e(TAG, "Failed to download client cert");
}
}
);
} finally {
isUpdating.set(false);
}
}
private static String generateSignature(String timestamp) {
String bodyString = "{}";
String dataToHash = bodyString + E_RECEIPT_SECRET + timestamp;
return EReceiptHelper.sha256(dataToHash);
}
}

View File

@ -2,8 +2,6 @@ package com.utsmm.kbz.ui.settings;
import android.os.RemoteException;
import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
import com.sunmi.pay.hardware.aidlv2.security.SecurityOptV2;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmm.kbz.BR;
@ -19,7 +17,7 @@ public class DeleteKeyFragment extends DataBindingFragment {
private InputKeyViewModel inputKeyViewModel;
private final SecurityOptV2 securityOptV2 = MyApplication.getInstance().mSecurityOptV2;
// private final SecurityOptV2 securityOptV2 = MyApplication.getInstance().mSecurityOptV2;
@Override
protected void initViewModel() {
@ -65,9 +63,9 @@ public class DeleteKeyFragment extends DataBindingFragment {
int keyIndex = Integer.parseInt(inputKeyViewModel.keyIndex.getValue());
try {
int result = securityOptV2.deleteKey(AidlConstantsV2.Security.SEC_MKSK,keyIndex);
// int result = securityOptV2.deleteKey(AidlConstantsV2.Security.SEC_MKSK,keyIndex);
int result = -1;
LogUtil.d(TAG,"Delete Key result :"+ result);
if( result == 0) {
showSuccessDialog(keyIndex + " was deleted successfully!");
@ -77,9 +75,6 @@ public class DeleteKeyFragment extends DataBindingFragment {
showDeclineDialog(keyIndex + " delete process failure \nError Code : "+result);
inputKeyViewModel.keyIndex.setValue("");
}
} catch (RemoteException e) {
throw new RuntimeException(e);
}
}
public void onCancel() {

View File

@ -0,0 +1,81 @@
package com.utsmm.kbz.ui.settings;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProvider;
import android.view.View;
import com.nexgo.oaf.apiv3.device.printer.Printer;
import com.utsmm.kbz.BR;
import com.utsmm.kbz.R;
import com.utsmm.kbz.config.Constants;
import com.utsmm.kbz.databinding.FragmentHostConfigBinding;
import com.utsmm.kbz.ui.core_viewmodel.SharedViewModel;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
public class HostConfigFragment extends DataBindingFragment {
private HostConfigViewModel viewModel;
private SharedViewModel sharedViewModel;
protected Printer printer;
int FONT_NORMAL = 20;
int FONT_HEADER = 24;
@Override
protected void initViewModel() {
viewModel = new ViewModelProvider(this).get(HostConfigViewModel.class);
sharedViewModel = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_host_config, BR.viewModel, viewModel)
.addBindingParam(BR.click, new ClickHandler());
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
FragmentHostConfigBinding binding = (FragmentHostConfigBinding) this.binding;
viewModel.loadConfig();
}
@Override
public void onResume(){
super.onResume();
setToolBarTitleWithBackIcon("Host Configs");
}
@Override
protected int currentId() {
return R.id.hostConfigFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return 0;
}
public class ClickHandler {
public void onCancel(){
safePopBack(R.id.hostConfigFragment, Constants.NAV_HOST_ID);
}
public void onPrint(){
sharedViewModel.printTerminalHostConfigs();
}
}
}

View File

@ -0,0 +1,33 @@
package com.utsmm.kbz.ui.settings;
public class HostConfigItem {
public String name;
public String ip;
public String mid;
public String tid;
public String secHostName;
public String secHostIp;
public String secHostMid;
public String secHostTid;
public HostConfigItem(
String name,
String ip,
String mid,
String tid,
String secHostName,
String secHostIp,
String secHostMid,
String secHostTid
){
this.name = name;
this.ip = ip;
this.mid = mid;
this.tid = tid;
this.secHostName = secHostName;
this.secHostIp = secHostIp;
this.secHostMid = secHostMid;
this.secHostTid = secHostTid;
}
}

View File

@ -0,0 +1,152 @@
package com.utsmm.kbz.ui.settings;
import static com.utsmyanmar.paylibs.print.printx.BaseXPrint.wrapAddressText;
import android.text.TextUtils;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.utsmm.kbz.BuildConfig;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import java.util.ArrayList;
import java.util.List;
public class HostConfigViewModel extends ViewModel {
public String appVersion = BuildConfig.VERSION_NAME;
public MutableLiveData<String> merchantName = new MutableLiveData<>();
public MutableLiveData<String> merchantPhone = new MutableLiveData<>();
public MutableLiveData<String> merchantAddress1 = new MutableLiveData<>();
public MutableLiveData<String> merchantAddress2 = new MutableLiveData<>();
// Primary Host
public MutableLiveData<String> hostName = new MutableLiveData<>();
public MutableLiveData<String> tid = new MutableLiveData<>();
public MutableLiveData<String> mid = new MutableLiveData<>();
public MutableLiveData<String> primaryIp = new MutableLiveData<>();
public MutableLiveData<String> primaryPort = new MutableLiveData<>();
public MutableLiveData<String> secondaryIp = new MutableLiveData<>();
public MutableLiveData<String> secondaryPort = new MutableLiveData<>();
public MutableLiveData<String> currencyCode = new MutableLiveData<>();
// Secondary Host
public MutableLiveData<String> secHostName = new MutableLiveData<>();
// public MutableLiveData<String> secHostTid = new MutableLiveData<>();
// public MutableLiveData<String> secHostMid = new MutableLiveData<>();
public MutableLiveData<String> shortCode = new MutableLiveData<>();
public MutableLiveData<String> secHostPrimaryIp = new MutableLiveData<>();
public MutableLiveData<String> secHostPrimaryPort = new MutableLiveData<>();
public MutableLiveData<String> secHostSecondaryIp = new MutableLiveData<>();
public MutableLiveData<String> secHostSecondaryPort = new MutableLiveData<>();
public MutableLiveData<String> terminalName = new MutableLiveData<>();
public void loadConfig() {
SystemParamsOperation sp = SystemParamsOperation.getInstance();
// Merchant Info
merchantName.setValue(sp.getMerchantName());
merchantPhone.setValue(sp.getMerchantPhoneNo());
merchantAddress1.setValue(wrapForUi(sp.getMerchantAddress()));
merchantAddress2.setValue(sp.getMerchantAddress2());
terminalName.setValue(sp.getTerminalName());
// PRIMARY HOST
hostName.setValue(sp.getHostName());
tid.setValue(sp.getTerminalId());
mid.setValue(sp.getMerchantId());
String[] pri = split(sp.getIpAddress());
primaryIp.setValue(pri[0]);
primaryPort.setValue(pri[1]);
String[] sec = split(sp.getSecIpAddress());
secondaryIp.setValue(sec[0]);
secondaryPort.setValue(sec[1]);
currencyCode.setValue(sp.getCurrencyType() != null ? sp.getCurrencyType().toString() : "");
if (sp.getSecHostName() != null && !sp.getSecHostName().isEmpty()) {
secHostName.setValue(sp.getSecHostName());
// secHostTid.setValue(sp.getSecHostTerminalId());
// secHostMid.setValue(sp.getSecHostMerchantId());
shortCode.setValue(sp.getShortCode());
String[] shp = split(sp.getSecHostIpAddress());
secHostPrimaryIp.setValue(shp[0]);
secHostPrimaryPort.setValue(shp[1]);
String[] shs = split(sp.getSecHostSecIpAddress());
secHostSecondaryIp.setValue(shs[0]);
secHostSecondaryPort.setValue(shs[1]);
}
}
public static String wrapForUi(String text) {
if (text == null || text.isEmpty()) return "";
List<String> result = new ArrayList<>();
String[] paragraphs = text.split("\\n");
for (String paragraph : paragraphs) {
List<String> wrappedLines = wrapAddressText(paragraph.trim(), 29);
result.addAll(wrappedLines);
}
return TextUtils.join("\n", result);
}
private String[] split(String raw) {
if (raw == null || raw.trim().isEmpty()) {
return new String[]{"", ""};
}
raw = raw.trim();
// If starts with http/https
if (raw.startsWith("http://") || raw.startsWith("https://")) {
// Attempt to extract host + port via URL
try {
java.net.URL url = new java.net.URL(raw);
String host = url.getHost(); // hostname or IP
int port = url.getPort(); // -1 if no port
String path = url.getPath(); // /api or /
// If port exists split normally
if (port != -1) {
return new String[]{
host, // e.g. 10.10.10.10
String.valueOf(port) // e.g. 5000
};
}
// No port do NOT split
return new String[]{ raw, "" };
} catch (Exception e) {
// fail-safe: do not split
return new String[]{ raw, "" };
}
}
// Normal "IP:Port" split
int idx = raw.lastIndexOf(":");
if (idx == -1) {
return new String[]{ raw, "" };
}
return new String[]{
raw.substring(0, idx),
raw.substring(idx + 1)
};
}
}

View File

@ -0,0 +1,193 @@
package com.utsmm.kbz.ui.settings;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.nexgo.downloadkey.downloadflow.DownloadFEntity;
import com.nexgo.downloadkey.downloadflow.DownloadFlow;
import com.nexgo.downloadkey.downloadflow.DownloadFlowProcessListener;
import com.nexgo.downloadkey.downloadflow.DownloadFlowResultEntity;
import com.nexgo.downloadkey.downloadflow.DownloadResult;
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.databinding.FragmentInjectKeyBinding;
import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmm.kbz.util.tms.TMSUtil;
public class InjectKeyFragment extends DataBindingFragment {
private static final String TAG = InjectKeyFragment.class.getSimpleName();
// Data binding will handle view access automatically
private FragmentInjectKeyBinding binding;
// Key injection variables
private DownloadFlow mDownloadFlow;
private int keyIndexTmp = 8; // Default key index
@Override
protected void initViewModel() {
// No specific viewmodels needed for this fragment
}
@Override
protected DataBindingConfig getDataBindingConfig() {
// This is the key method that links the XML and fragment properly
return new DataBindingConfig(R.layout.fragment_inject_key, 0, null)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.injectKeyFragment;
}
@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 {
// Get the binding from the base class - this is automatically created
binding = (FragmentInjectKeyBinding) mBinding;
updateConfigurationInfo();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon("Inject Key");
}
private void updateConfigurationInfo() {
String terminalId = SystemParamsOperation.getInstance().getTerminalId();
binding.terminalIdValue.setText(terminalId != null && !terminalId.isEmpty() ?
terminalId : "Not configured");
// Update Merchant ID
String merchantId = SystemParamsOperation.getInstance().getMerchantId();
binding.merchantIdValue.setText(merchantId != null && !merchantId.isEmpty() ?
merchantId : "Not configured");
// Update Serial Number
String serialNo = TMSUtil.getInstance().getSerialNumber();
binding.serialNumberValue.setText(serialNo != null && !serialNo.isEmpty() ?
serialNo : "Not configured");
}
private void loadKeyFromKeyPOS() {
try {
if (TextUtils.isEmpty(binding.etKeyIndex.getText())) {
Toast.makeText(getContext(), "Please input key index", Toast.LENGTH_SHORT).show();
return;
}
String keyIndexText = binding.etKeyIndex.getText().toString().trim();
try {
keyIndexTmp = Integer.parseInt(keyIndexText);
} catch (NumberFormatException e) {
Toast.makeText(getContext(), "Invalid key index format", Toast.LENGTH_SHORT).show();
return;
}
showLoadingDialog("Loading key...");
mDownloadFlow = DownloadFlow.getInstance();
String terminalId = SystemParamsOperation.getInstance().getTerminalId();
String merchantId = SystemParamsOperation.getInstance().getMerchantId();
String serialNo = TMSUtil.getInstance().getSerialNumber();
// Validate configuration
if (TextUtils.isEmpty(terminalId) || TextUtils.isEmpty(merchantId) || TextUtils.isEmpty(serialNo)) {
dismissLoadingDialog();
showDeclineDialog("Please configure Terminal ID, Merchant ID first in TMS Configuration");
return;
}
final DownloadFEntity downloadFEntity = new DownloadFEntity();
downloadFEntity.setSn(serialNo.getBytes());
downloadFEntity.setMid(merchantId.getBytes());
downloadFEntity.setTid(terminalId.getBytes());
downloadFEntity.setTmkIndex(keyIndexTmp);
downloadFEntity.setPort(0);
downloadFEntity.setTimeOut(10);
int result = mDownloadFlow.startLoadKey(getActivity(), downloadFEntity, onDownloadFlowProcessListener);
if (result != DownloadResult.Success) {
dismissLoadingDialog();
showDeclineDialog("Failed to start key injection process");
LogUtil.e(TAG, "Failed to start key injection, result: " + result);
}
} catch (Exception e) {
dismissLoadingDialog();
LogUtil.e(TAG, "Error in key injection: " + e.getMessage());
showDeclineDialog("Error occurred during key injection: " + e.getMessage());
}
}
private DownloadFlowProcessListener onDownloadFlowProcessListener = new DownloadFlowProcessListener() {
@Override
public void onFinish(int ret, DownloadFlowResultEntity downloadFlowResultEntity) {
try {
dismissLoadingDialog();
if (ret == DownloadResult.Success) {
// Show success dialog with key index
showSuccessDialog("Key injection successful!\nKey Index: " + keyIndexTmp);
LogUtil.d(TAG, "Key injection successful for index: " + keyIndexTmp);
} else {
// Show decline dialog
showDeclineDialog("Key injection failed!\nError code: " + ret);
LogUtil.e(TAG, "Key injection failed with error code: " + ret);
}
} catch (Exception e) {
LogUtil.e(TAG, "Error handling injection result: " + e.getMessage());
showDeclineDialog("Error processing injection result");
}
}
};
// ClickEvent class for data binding - this is the proper pattern
public class ClickEvent {
public void onInjectKeyClick() {
try {
LogUtil.d(TAG, "Inject key button clicked");
loadKeyFromKeyPOS();
} catch (Exception e) {
LogUtil.e(TAG, "Error in inject key click: " + e.getMessage());
showDeclineDialog("Error occurred: " + e.getMessage());
}
}
}
}

View File

@ -0,0 +1,388 @@
package com.utsmm.kbz.ui.settlement;
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.utsmm.kbz.util.EReceiptUtil;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.QRSettleData;
import com.utsmyanmar.paylibs.model.SettleData;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.utils.LogUtil;
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.HostType;
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.SharedViewModel;
import com.utsmm.kbz.ui.management.ManagementViewModel;
import com.utsmm.kbz.util.ecr.CoreUtils;
import java.util.ArrayList;
import java.util.List;
public class QRSettlementTransactionFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback {
private static final String TAG = QRSettlementTransactionFragment.class.getSimpleName();
private SharedViewModel sharedViewModel;
private ManagementViewModel managementViewModel;
private SettlementViewModel settlementViewModel;
ArrayList<PayDetail> qrTransactionsList = new ArrayList<>();
ArrayList<PayDetail> qrTransListAll = new ArrayList<>();
SettleData settleData;
private int routeId;
private int count = 0;
private long totalAmount = 0;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
managementViewModel = getFragmentScopeViewModel(ManagementViewModel.class);
settlementViewModel = getFragmentScopeViewModel(SettlementViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_qr_settlement_screen, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.manageViewModel, managementViewModel)
.addBindingParam(BR.settleViewModel, settlementViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.QRSettlementTransactionFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getString(R.string.title_qr_settlement));
String merchantName = SystemParamsOperation.getInstance().getMerchantName();
if (!TextUtils.equals(merchantName, "")) {
sharedViewModel.merchantName.postValue(merchantName);
} else {
sharedViewModel.merchantName.postValue("Default Value");
}
if(sharedViewModel.getTransMenu().getValue() == TransMenu.LAST_SETTLEMENT) {
setToolBarTitleWithBackIcon(getString(R.string.txt_subtitle_reprint_last_settle_report));
delayFunctionCall(this::observeQRLastSettlementTransactions);
} else {
setToolBarTitleWithBackIcon(getString(R.string.title_view_batch));
delayFunctionCall(this::observeQRTransactions);
}
showLoadingView();
// setupQRSettlementData();
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setupBackButtonPressDetection(this);
setupQRSettlementData();
}
private void showLoadingView() {
managementViewModel.detailReportLayoutLoadingVisibility.setValue(0);
managementViewModel.detailReportLayoutVisibility.setValue(8);
managementViewModel.detailReportLayoutViewVisibility.setValue(8);
managementViewModel.detailReportBottomLayoutVisibility.setValue(8);
}
private void showDataView() {
managementViewModel.detailReportLayoutLoadingVisibility.setValue(8);
managementViewModel.detailReportLayoutVisibility.setValue(8);
managementViewModel.detailReportLayoutViewVisibility.setValue(0);
managementViewModel.detailReportBottomLayoutVisibility.setValue(0);
}
private void showEmptyDataView() {
managementViewModel.detailReportLayoutLoadingVisibility.setValue(8);
managementViewModel.detailReportLayoutVisibility.setValue(0);
managementViewModel.detailReportLayoutViewVisibility.setValue(8);
managementViewModel.detailReportBottomLayoutVisibility.setValue(8);
}
private void setupQRSettlementData() {
managementViewModel.hostTypeDR.setValue("PAYMENT");
managementViewModel.cardTypeDR.setValue("QR PAY");
}
private void observeQRTransactions() {
managementViewModel.getTransactionHistory().observe(getViewLifecycleOwner(), payDetailList -> {
if (payDetailList != null) {
qrTransactionsList.clear();
qrTransListAll.clear();
count = 0;
totalAmount = 0;
try {
for (PayDetail payDetail : payDetailList) {
// Filter for QR transactions only
if ((payDetail.getTransactionType() == TransactionsType.MMQR.value
|| payDetail.getTransactionType() == TransactionsType.MMQR_REFUND.value)
&& payDetail.getQrTransStatus() == 1) {
boolean isNeedMinusSign = payDetail.getTransactionType() == TransactionsType.MMQR_REFUND.value;
qrTransactionsList.add(payDetail);
count++;
if (isNeedMinusSign) {
totalAmount -= payDetail.getAmount();
} else {
totalAmount += payDetail.getAmount();
}
}
else if(payDetail.getTransactionType() == TransactionsType.MMQR.value || payDetail.getTransactionType() == TransactionsType.MMQR_REFUND.value) {
qrTransListAll.add(payDetail);
}
}
} catch (IllegalStateException e) {
LogUtil.e(TAG,"QRSettlement : Database cursor error - likely due to large data size:"+ e);
showEmptyDataView();
settlementViewModel.isNoData.setValue(true);
return;
}
if (qrTransactionsList.isEmpty()) {
showEmptyDataView();
settlementViewModel.isNoData.setValue(true);
} else {
showDataView();
settlementViewModel.isNoData.setValue(false);
setupSettlementDisplayData();
}
} else {
showEmptyDataView();
settlementViewModel.isNoData.setValue(true);
}
});
}
private void observeQRLastSettlementTransactions() {
List<PayDetail> payDetailList = managementViewModel.payDetails.getValue();
if( payDetailList != null) {
PayDetail payDetail = payDetailList.get(payDetailList.size() - 1);
int qrSaleCount = 0;
long qrSaleAmount = 0;
int qrRefundCount = 0;
long qrRefundAmount = 0;
count = 0;
totalAmount = 0;
SettleData settleData = payDetail.getSettleDataObj();
qrSaleCount = settleData.getSaleCount();
qrSaleAmount = settleData.getSaleAmount();
qrRefundAmount = settleData.getRefundAmount();
qrRefundCount = settleData.getRefundCount();
totalAmount = qrSaleAmount - qrRefundAmount;
count = qrSaleCount + qrRefundCount;
settlementViewModel.sale_count.setValue(qrSaleCount);
settlementViewModel.sale_amount.setValue(qrSaleAmount);
settlementViewModel.refund_count.setValue(qrRefundCount);
settlementViewModel.refund_amount.setValue(qrRefundAmount);
managementViewModel.totalAmountDR.setValue(totalAmount);
managementViewModel.trnxCountDR.setValue(String.valueOf(count));
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(totalAmount));
sharedViewModel.payDetail.setValue(payDetail);
showDataView();
settlementViewModel.isNoData.setValue(false);
// if (qrTransactionsList.isEmpty()) {
// showEmptyDataView();
// settlementViewModel.isNoData.setValue(true);
// } else {
// showDataView();
// settlementViewModel.isNoData.setValue(false);
// }
} else {
showEmptyDataView();
settlementViewModel.isNoData.setValue(true);
}
}
private void setupSettlementDisplayData() {
// Calculate QR sale and refund counts/amounts
int qrSaleCount = 0;
long qrSaleAmount = 0;
int qrRefundCount = 0;
long qrRefundAmount = 0;
totalAmount = 0;
for (PayDetail payDetail : qrTransactionsList) {
if (payDetail.getTransactionType() == TransactionsType.MMQR.value) {
qrSaleCount++;
qrSaleAmount += payDetail.getAmount();
} else if (payDetail.getTransactionType() == TransactionsType.MMQR_REFUND.value) {
qrRefundCount++;
qrRefundAmount += payDetail.getAmount();
}
}
totalAmount = qrSaleAmount - qrRefundAmount;
// Set values in settlement view model for display
settlementViewModel.sale_count.setValue(qrSaleCount);
settlementViewModel.sale_amount.setValue(qrSaleAmount);
settlementViewModel.refund_count.setValue(qrRefundCount);
settlementViewModel.refund_amount.setValue(qrRefundAmount);
managementViewModel.totalAmountDR.setValue(totalAmount);
managementViewModel.trnxCountDR.setValue(String.valueOf(count));
// Create settlement data for transaction result
settleData = new SettleData(qrSaleCount, qrSaleAmount, 0, 0L, qrRefundCount, qrRefundAmount, 0, 0L);
}
private void finishECRProcess() {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getString(R.string.txt_cancel_trans));
sharedViewModel.isEcrFinished.postValue(true);
sharedViewModel.isEcr.postValue(false);
}
private void navigateToResult() {
routeId = R.id.action_QRSettlementTransactionFragment_to_transactionResultFragment;
safeNavigateToRouteId();
}
private void processData() {
TradeData tradeData = Params.newTrade(false);
PayDetail payDetail = tradeData.getPayDetail();
payDetail.setSettleDataObj(settleData);
payDetail.setTransactionType(TransactionsType.MMQR_SETTLEMENT.value);
payDetail.setTransType(TransactionsType.MMQR_SETTLEMENT.name);
payDetail.setAmount(totalAmount);
payDetail.setTradeAnswerCode("000");
payDetail.setBatchNo(SystemParamsOperation.getInstance().getCurrentBatchNum());
payDetail.setQrSettleData(QRSettleData.convertFromPayDetail(qrTransactionsList));
if(sharedViewModel.getTransMenu().getValue() != TransMenu.LAST_SETTLEMENT) {
sharedViewModel.insertPayDetail(payDetail);
}
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(totalAmount));
sharedViewModel.payDetails.setValue(qrTransactionsList);
sharedViewModel.payDetail.setValue(payDetail);
for (PayDetail pay : qrTransactionsList) {
settlementViewModel.deletePayDetail(pay);
}
for (PayDetail pay : qrTransListAll) {
settlementViewModel.deletePayDetail(pay);
}
}
private void updateData() {
// EReceiptRequest request = EReceiptUtil.getInstance().generateMPUReceipt(sharedViewModel.payDetail.getValue());
EReceiptRequest request = EReceiptUtil.getInstance().generateQRSettlement(sharedViewModel.payDetail.getValue(), QRSettleData.convertFromPayDetail(qrTransactionsList));
sharedViewModel.pushReceipt(request);
}
@Override
public void onBackPress() {
if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) {
finishECRProcess();
}
popBackStack();
}
private void navigateToMain() {
routeId = R.id.action_QRSettlementTransactionFragment_to_nav_main;
safeNavigateToRouteId();
}
public class ClickEvent {
public void onCancel() {
if(sharedViewModel.getTransMenu().getValue() == TransMenu.SETTLEMENT) {
if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) {
finishECRProcess();
}
popBackStack();
} else if(sharedViewModel.getTransMenu().getValue() == TransMenu.LAST_SETTLEMENT) {
navigateToMain();
}
}
public void onConfirm() {
if(sharedViewModel.getTransMenu().getValue() == TransMenu.SETTLEMENT) {
if (!qrTransactionsList.isEmpty()) {
SystemParamsOperation.getInstance().getIncrementBatchNo();
processData();
updateData();
navigateToResult();
}
} else if(sharedViewModel.getTransMenu().getValue() == TransMenu.LAST_SETTLEMENT) {
routeId = R.id.action_QRSettlementTransactionFragment_to_reprintReceiptFragment;
safeNavigateToRouteId();
}
}
}
}

View File

@ -0,0 +1,113 @@
package com.utsmm.kbz.ui.settlement;
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.utsmyanmar.paylibs.utils.enums.HostType;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
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;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.util.tms.TMSUtil;
import com.utsmm.kbz.util.Connectivity;
import com.utsmm.kbz.config.data.model.ValidityStatus;
public class SelectSettlementFragment extends DataBindingFragment implements DataBindingFragment.BackPressCallback {
private SharedViewModel sharedViewModel;
private int routeId;
@Override
protected void initViewModel() {
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_select_settlement_screen, BR.sharedViewModel, sharedViewModel)
.addBindingParam(BR.click, new ClickEvent());
}
@Override
protected int currentId() {
return R.id.selectSettlementFragment;
}
@Override
protected int hostId() {
return Constants.NAV_HOST_ID;
}
@Override
protected int routeId() {
return routeId;
}
@Override
public void onResume() {
super.onResume();
setToolBarTitleWithBackIcon(getString(R.string.title_select_settlement_type));
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setupBackButtonPressDetection(this);
}
private void finishECRProcess() {
CoreUtils.getInstance(sharedViewModel).responseRejectMsg(getString(R.string.txt_cancel_trans));
sharedViewModel.isEcrFinished.postValue(true);
sharedViewModel.isEcr.postValue(false);
}
@Override
public void onBackPress() {
if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) {
finishECRProcess();
}
popBackStack();
}
public class ClickEvent {
public void onCardSettlement() {
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{
routeId = R.id.action_selectSettlementFragment_to_settlementTransactionFragment;
safeNavigateToRouteId();
}
}
public void onQRSettlement() {
if (TMSUtil.getInstance().checkQRParams().isStatus() == ValidityStatus.FAILURE) {
showDeclineDialog(getResourceString(R.string.txt_please_download_config)+"\n"+TMSUtil.getInstance().checkQRParams().getMessage());
} else if (!Connectivity.isConnectedWifi(getContext()) && !Connectivity.isConnectedMobile(getContext())) {
showSingleInfoDialog(getResourceString(R.string.txt_please_enable_internet));
} else {
sharedViewModel.hostType.setValue(HostType.QR);
routeId = R.id.action_selectSettlementFragment_to_QRSettlementTransactionFragment;
safeNavigateToRouteId();
}
}
public void onCancel() {
if (sharedViewModel.isEcr.getValue() != null && sharedViewModel.isEcr.getValue()) {
finishECRProcess();
}
popBackStack();
}
}
}

View File

@ -8,12 +8,17 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.Observer;
import com.utsmm.kbz.ui.management.ManagementViewModel;
import com.utsmm.kbz.util.EReceiptUtil;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.print.printx.PrintXStatus;
import com.utsmyanmar.paylibs.sign_on.EchoTestProcess;
import com.utsmyanmar.paylibs.sign_on.SignOnListener;
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.TransactionType;
@ -36,6 +41,8 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
private SettlementViewModel settlementViewModel;
private SharedViewModel sharedViewModel;
private ManagementViewModel managementViewModel;
private int routeId;
int saleCount = 0;
@ -51,12 +58,14 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
protected void initViewModel() {
settlementViewModel = getFragmentScopeViewModel(SettlementViewModel.class);
sharedViewModel = getFragmentScopeViewModel(SharedViewModel.class);
managementViewModel = getFragmentScopeViewModel(ManagementViewModel.class);
}
@Override
protected DataBindingConfig getDataBindingConfig() {
return new DataBindingConfig(R.layout.fragment_view_batch_screen, BR.settleViewModel,settlementViewModel)
.addBindingParam(BR.sharedViewModel,sharedViewModel)
.addBindingParam(BR.managementViewModel,managementViewModel)
.addBindingParam(BR.click,new ClickEvent());
}
@ -154,6 +163,9 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
setSettlementViewModelData(saleCount, saleAmount, preCount, preAmount, refundCount, refundAmount, caCount, caAmount);
settlementViewModel.setPayDetails(payDetails);
managementViewModel.payDetail.setValue(payDetail);
}
} else {
@ -212,6 +224,7 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
}
long totalAmount = saleAmount + preAmount + caAmount;
sharedViewModel.totalAmount.postValue(totalAmount);
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(totalAmount));
settlementViewModel.isNoData.setValue(false);
@ -232,6 +245,8 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
settlementViewModel.isNoData.setValue(true);
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(0));
setSettlementViewModelData(saleCount,saleAmount,preCount,preAmount,refundCount,refundAmount,caCount,caAmount);
}
});
@ -316,7 +331,9 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
dismissLoadingDialog();
updateData();
if (!SystemParamsOperation.getInstance().getDemoStatus()) {
networkCutOver();
networkCutOver(); // bpc
navigateToNext();
} else {
navigateToNext();
}
@ -336,6 +353,10 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
private void updateData() {
sharedViewModel.payDetail.setValue(settlementViewModel.getPayDetail());
EReceiptRequest request = EReceiptUtil.getInstance().generateMPUReceipt(sharedViewModel.payDetail.getValue());
sharedViewModel.pushReceipt(request);
}
@Override
@ -378,12 +399,23 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
}
public void onConfirm(){
if(sharedViewModel.getTransMenu().getValue() == TransMenu.SETTLEMENT) {
/* April 10 , 2024 Smile requested not to send to host even settlement button was clicked */
settlementViewModel.startSettlementProcess();
showLoadingDialog("Sending ...");
} else if(sharedViewModel.getTransMenu().getValue() == TransMenu.REVIEW_BATCH) {
sharedViewModel.startPrintProcessSettlement();
sharedViewModel.startPrintSettlement(new PrintXStatus() {
@Override
public void onSuccess() {
}
@Override
public void onFailure() {
}
});
} else if(sharedViewModel.getTransMenu().getValue() == TransMenu.LAST_SETTLEMENT) {
routeId = R.id.action_settlementTransactionFragment_to_reprintReceiptFragment;
safeNavigateToRouteId();

View File

@ -7,6 +7,8 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.utsmm.kbz.util.EReceiptUtil;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.repo.Repository;
import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.batch_upload.BatchListener;
@ -14,6 +16,7 @@ import com.utsmyanmar.paylibs.batch_upload.BatchUploadProcess;
import com.utsmyanmar.paylibs.isobuilder.ISOMode;
import com.utsmyanmar.paylibs.isobuilder.builderx.ISOMsgX;
import com.utsmyanmar.paylibs.isobuilder.builderx.ISOVersion;
import com.utsmyanmar.paylibs.model.CardSettleData;
import com.utsmyanmar.paylibs.model.MsgField;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.SettleData;
@ -209,16 +212,21 @@ public class SettlementViewModel extends ViewModel {
repository.updatePayDetail(payDetail);
}
public void deletePayDetail(PayDetail payDetail){
repository.deletePayDetail(payDetail);
}
private void updateDB() {
if(payDetails != null && payDetails.size() > 0) {
for (PayDetail paydetail:payDetails) {
for (PayDetail pay:payDetails) {
// if(paydetail.getTransactionType() == TransactionsType.SALE.value) {
// paydetail.setIsSettle(true);
// updatePayDetail(paydetail);
// } else {
repository.deletePayDetail(paydetail);
deletePayDetail(pay);
// repository.deletePayDetail(paydetail);
// }
@ -228,7 +236,8 @@ public class SettlementViewModel extends ViewModel {
for (PayDetail pay:deleteTrans
) {
repository.deletePayDetail(pay);
// repository.deletePayDetail(pay);
deletePayDetail(pay);
}
if (payDetails != null) {
payDetails.clear();
@ -245,6 +254,8 @@ public class SettlementViewModel extends ViewModel {
repository.insertPayDetail(payDetail);
}
@SuppressWarnings("ConstantConditions")
public void startSettlementProcess() {
saleCount = sale_count.getValue();
@ -361,14 +372,26 @@ public class SettlementViewModel extends ViewModel {
payDetail = tradeData.getPayDetail();
bitmap = BitmapConfig.BPC_SETTLEMENT;
//
if(hostName == HostName.BPC) {
bitmap = BitmapConfig.BPC_SETTLEMENT;
} else {
bitmap = BitmapConfig.MPU_NEW_SETTLE;
}
payDetail.setTransType(TransactionsType.SETTLEMENT.name);
payDetail.setTransactionType(TransactionType.SETTLEMENT);
if (!flag) {
payDetail.setProcessCode(TransactionsType.SETTLEMENT.processCode);
} else {
bitmap = BitmapConfig.BPC_SETTLEMENT_TRAILER;
payDetail.setProcessCode("910000");
if(hostName == HostName.BPC) {
bitmap = BitmapConfig.BPC_SETTLEMENT_TRAILER;
payDetail.setProcessCode("910000");
} else {
bitmap = BitmapConfig.MPU_NEW_SETTLE;
payDetail.setProcessCode("960000");
}
}
// CA:CA - CD - FT
@ -380,6 +403,9 @@ public class SettlementViewModel extends ViewModel {
SettleData settleData = new SettleData(saleCount,saleAmount,preAuthCount,preAuthAmount,refundCount,refundAmount,caCount,caAmount);
payDetail.setSettleDataObj(settleData);
if(payDetails != null)
payDetail.setCardSettleData(CardSettleData.convertFromPayDetail(payDetails));
if(hostName == HostName.BPC) {
long totalAmount = saleAmount + preAuthAmount + refundAmount + caAmount;
@ -403,7 +429,8 @@ public class SettlementViewModel extends ViewModel {
payDetail.setSettleData(settlementData);
payDetail.setAmount(totalAmount);
} else {
payDetail.setSettleData(totalSaleCount + totalSaleAmount + totalRefundCount + totalRefundAmount + totalDebitSaleCount + totalDebitSaleAmount + totalERefundCount + totalERefundAmount); //field 63
// payDetail.setSettleData(totalSaleCount + totalSaleAmount + totalRefundCount + totalRefundAmount + totalDebitSaleCount + totalDebitSaleAmount + totalERefundCount + totalERefundAmount); //field 63 BPC
payDetail.setSettleData(totalSaleCount + totalSaleAmount + totalRefundCount + totalRefundAmount + totalDebitSaleCount + totalDebitSaleAmount ); //field 63
}
@ -486,8 +513,12 @@ public class SettlementViewModel extends ViewModel {
// to leave data for testing
// if (settlementType.getValue() == SettlementType.NORMAL) {
updateDB();
// }
insertPayDetail(payDetail);
if (errorFlag) {

View File

@ -1,5 +1,12 @@
package com.utsmm.kbz.ui.tms;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.PowerManager;
import android.provider.Settings;
import android.os.Bundle;
import android.view.View;
@ -8,6 +15,7 @@ import androidx.annotation.Nullable;
import com.google.gson.Gson;
import com.google.gson.stream.MalformedJsonException;
import com.utsmm.kbz.service.AutoAlarmReceiver;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.sirius.SiriusError;
import com.utsmyanmar.baselib.network.model.sirius.SiriusRequest;
@ -26,6 +34,8 @@ import com.utsmm.kbz.util.enums.TMSDownloadStatus;
import com.utsmm.kbz.util.tms.TMSUtil;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
@ -212,7 +222,12 @@ public class TMSProcessFragment extends DataBindingFragment {
}
CurrencyType currencyType = SystemParamsOperation.getInstance().getCurrencyType();
sharedViewModel.set_currencyText(currencyType.name);
// tmsProcessViewModel.loadEmvParameters();
tmsProcessViewModel.loadEmvParameters();
// Check and request battery optimization exemption before scheduling alarm
requestBatteryOptimizationExemption();
scheduleAutoSettlement();
navigateToMain();
}
});
@ -224,4 +239,135 @@ public class TMSProcessFragment extends DataBindingFragment {
}
private void scheduleAutoSettlement() {
String timeStr = SystemParamsOperation.getInstance().getClearBatchTime();
LogUtil.d(TAG,"timeStr:" + timeStr );
if(timeStr == null || timeStr.trim().isEmpty()) {
LogUtil.d(TAG, "Clear batch time is empty, skipping auto settlement scheduling");
return;
}
String[] parts = timeStr.trim().split(":");
if(parts.length != 2) {
LogUtil.d(TAG, "Invalid time format: " + timeStr + ", expected HH:MM");
return;
}
int hour;
int minute;
try {
hour = Integer.parseInt(parts[0]);
minute = Integer.parseInt(parts[1]);
// Validate time range
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
LogUtil.d(TAG, "Invalid time values - hour: " + hour + ", minute: " + minute);
return;
}
} catch (Exception e) {
LogUtil.d(TAG, "Error parsing time string: " + timeStr + ", error: " + e.getMessage());
return;
}
LogUtil.d(TAG, "Scheduling auto settlement for hour:" + hour + " minute:" + minute);
AlarmManager alarmManager = (AlarmManager) requireContext().getSystemService(Context.ALARM_SERVICE);
if (alarmManager == null) {
LogUtil.d(TAG, "AlarmManager is null, cannot schedule alarm");
return;
}
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(java.util.Calendar.HOUR_OF_DAY, hour);
calendar.set(java.util.Calendar.MINUTE, minute);
calendar.set(java.util.Calendar.SECOND, 0);
calendar.set(java.util.Calendar.MILLISECOND, 0);
long triggerAtMillis = calendar.getTimeInMillis();
long currentTime = System.currentTimeMillis();
LogUtil.d(TAG, "Current time: " + new java.util.Date(currentTime).toString());
LogUtil.d(TAG, "Initial trigger time: " + new java.util.Date(triggerAtMillis).toString());
if (triggerAtMillis <= currentTime) {
calendar.add(Calendar.DAY_OF_YEAR, 1);
triggerAtMillis = calendar.getTimeInMillis();
LogUtil.d(TAG, "Updated trigger time for NEXT DAY: " + new java.util.Date(triggerAtMillis).toString());
} else {
LogUtil.d(TAG, "Scheduling alarm for TODAY: " + new java.util.Date(triggerAtMillis).toString());
}
Intent intent = new Intent(requireContext(), AutoAlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
requireContext(),
1001,
intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
);
try {
alarmManager.cancel(pendingIntent);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
if (alarmManager.canScheduleExactAlarms()) {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
} else {
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
}
} else {
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
}
} else {
alarmManager.setExact(AlarmManager.RTC_WAKEUP, triggerAtMillis, pendingIntent);
}
long hoursUntilTrigger = (triggerAtMillis - currentTime) / 1000 / 60 / 60;
long minutesUntilTrigger = ((triggerAtMillis - currentTime) / 1000 / 60) % 60;
LogUtil.d(TAG, "Auto settlement alarm setup completed. Next occurrence: " + new Date(triggerAtMillis).toString());
LogUtil.d(TAG, "Time until next trigger: " + hoursUntilTrigger + " hours, " + minutesUntilTrigger + " minutes");
} catch (Exception e) {
LogUtil.e(TAG, "Error scheduling main alarm: " + e.getMessage());
e.printStackTrace();
LogUtil.e(TAG, "Alarm scheduling failed - Check if app has SCHEDULE_EXACT_ALARM permission");
LogUtil.e(TAG, "Failed alarm details - Target time: " + new Date(triggerAtMillis).toString());
}
}
private void requestBatteryOptimizationExemption() {
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
PowerManager powerManager = (PowerManager) requireContext().getSystemService(Context.POWER_SERVICE);
String packageName = requireContext().getPackageName();
if (!powerManager.isIgnoringBatteryOptimizations(packageName)) {
LogUtil.d(TAG, "Requesting battery optimization exemption for reliable alarms");
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
intent.setData(Uri.parse("package:" + packageName));
try {
startActivity(intent);
LogUtil.d(TAG, "Battery optimization exemption dialog opened");
} catch (Exception e) {
LogUtil.e(TAG, "Failed to open battery optimization dialog: " + e.getMessage());
// Fallback: Open battery optimization settings page
try {
Intent fallbackIntent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
startActivity(fallbackIntent);
LogUtil.d(TAG, "Battery optimization settings opened as fallback");
} catch (Exception fallbackException) {
LogUtil.e(TAG, "Fallback also failed: " + fallbackException.getMessage());
}
}
} else {
LogUtil.d(TAG, "App is already exempted from battery optimizations");
}
}
} catch (Exception e) {
LogUtil.e(TAG, "Error checking battery optimization status: " + e.getMessage());
}
}
}

View File

@ -0,0 +1,142 @@
package com.utsmm.kbz.util;
import com.utsmm.kbz.MyApplication;
import com.utsmyanmar.paylibs.utils.LogUtil;
import java.io.File;
import java.io.FileOutputStream;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class DownloadUtil {
private static final String TAG = DownloadUtil.class.getSimpleName();
public interface DownloadCallback {
void onDownloadSuccess(String path);
}
// ==============================
// RX ASYNC DOWNLOAD METHOD
// ==============================
public static void downloadCertificateRx(String url,
String dynamicFilename,
String timestamp,
String signature,
DownloadCallback callback) {
Observable.fromCallable(() ->
downloadCert(url, dynamicFilename, timestamp, signature)
)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(path -> {
if (callback != null) {
callback.onDownloadSuccess(path);
}
}, error -> {
LogUtil.e(TAG, "Download error : " + error);
if (callback != null) callback.onDownloadSuccess(null);
});
}
// ==============================
// ACTUAL DOWNLOAD LOGIC
// ==============================
private static String downloadCert(String url,
String dynamicFilename,
String timestamp,
String signature) {
// LogUtil.d(TAG, "cert timestamp => " + timestamp);
// LogUtil.d(TAG, "cert signature => " + signature);
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
.readTimeout(30, java.util.concurrent.TimeUnit.SECONDS)
.build();
Request request = new Request.Builder()
.url(url)
.addHeader("x-timestamp", timestamp)
.addHeader("x-api-key", signature)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful() || response.body() == null) {
LogUtil.e(TAG, "Download failed: " + response.code());
return null;
}
String contentType = response.header("Content-Type", "");
String ext = getExtensionFromContentType(contentType);
if (ext.isEmpty()) ext = getExtensionFromUrl(url);
if (ext.isEmpty()) ext = ".bin";
String filename = dynamicFilename + ext;
byte[] data = response.body().bytes();
return saveFile(filename, data);
} catch (Exception e) {
LogUtil.e(TAG, "Download exception : " + e);
return null;
}
}
// ==============================
// SAVE FILE
// ==============================
private static String saveFile(String filename, byte[] data) {
try {
File dir = MyApplication.getInstance().getFilesDir();
File file = new File(dir, filename);
try (FileOutputStream fos = new FileOutputStream(file)) {
fos.write(data);
fos.flush();
}
return file.getAbsolutePath();
} catch (Exception e) {
LogUtil.e(TAG, "File save failed : " + e);
return null;
}
}
// ==============================
// MIME EXTENSION
// ==============================
private static String getExtensionFromContentType(String contentType) {
if (contentType == null) return "";
switch (contentType) {
case "application/x-x509-ca-cert":
return ".crt";
case "application/pkix-cert":
return ".cer";
case "application/x-pem-file":
case "application/octet-stream":
return ".pem";
case "application/x-pkcs12":
return ".p12";
default:
return "";
}
}
private static String getExtensionFromUrl(String url) {
if (url == null) return "";
int lastDot = url.lastIndexOf('.');
if (lastDot == -1) return "";
return url.substring(lastDot);
}
}

View File

@ -0,0 +1,334 @@
package com.utsmm.kbz.util;
import com.utsmm.kbz.BuildConfig;
import com.utsmm.kbz.util.enums.TransResultStatus;
import com.utsmm.kbz.util.tms.TMSUtil;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.network.model.e_receipt.Transaction;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.QRSettleData;
import com.utsmyanmar.paylibs.model.SettleData;
import com.utsmyanmar.paylibs.system.BaseErrorCode;
import com.utsmyanmar.paylibs.utils.POSUtil;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
public class EReceiptUtil {
private static EReceiptUtil instance;
public static EReceiptUtil getInstance() {
instance = new EReceiptUtil();
return instance;
}
private String terminalId;
private String merchantId;
private String traceNo;
private String invoiceNo;
private String serialNum;
private String batchNumber;
private String packageName;
private String qrTerminalId;
private String qrMerchantId;
private EReceiptUtil() {
terminalId = SystemParamsOperation.getInstance().getTerminalId();
merchantId = SystemParamsOperation.getInstance().getMerchantId();
traceNo = SystemParamsOperation.getInstance().getCurrentSerialNum();
invoiceNo = SystemParamsOperation.getInstance().getCurrentInvoiceNum();
batchNumber = SystemParamsOperation.getInstance().getCurrentBatchNum();
serialNum = TMSUtil.getInstance().getSerialNumber();
packageName = BuildConfig.APPLICATION_ID;
qrTerminalId = SystemParamsOperation.getInstance().getSecHostTerminalId();
qrMerchantId = SystemParamsOperation.getInstance().getShortCode();
}
public EReceiptRequest generateQRReceipt(PayDetail payDetail, TransResultStatus status) {
String terminalIdForEreceipt = SystemParamsOperation.getInstance().getTerminalIdForEreceipt();
String hostId = SystemParamsOperation.getInstance().getSecHostId();
double realAmount = payDetail.getAmount() / 100.0;
DecimalFormat df = new DecimalFormat("0.00");
String amount = df.format(realAmount);
String currentTimeStamp = new java.text.SimpleDateFormat("MMddHHmmss", java.util.Locale.getDefault())
.format(new java.util.Date());
EReceiptRequest request = new EReceiptRequest();
request.setDE3("QR");
request.setDE7(currentTimeStamp);
request.setDE37(payDetail.getReferNo());
request.setDE49("MMK");
request.setDE38(payDetail.getQrTransId());
request.setSerial(serialNum);
request.setAppId(packageName);
request.setDE41(qrTerminalId);
request.setDE42(qrMerchantId);
request.setTerminalId(terminalIdForEreceipt);
request.setShortCode(qrMerchantId);
request.setMmqrRef(payDetail.getQrReferNo() == null ? "" : payDetail.getQrReferNo());
request.setHostId(hostId);
request.setPaymentIdentifier(payDetail.getCustomerMobile());
request.setInvoiceNumber(payDetail.getInvoiceNo());
request.setDE11(payDetail.getVoucherNo());
// need to add payment identifier field too
if (status == TransResultStatus.SUCCESS) {
request.setDE4(amount);
request.setDescription("qr pay success");
request.setDE39("A");
} else if (status == TransResultStatus.TIME_OUT) {
request.setDE4("0");
request.setDescription("qr timeout");
request.setDE39("D");
} else if (status == TransResultStatus.FAIL) {
request.setDE4("0");
request.setDescription("qr failed");
request.setDE39("E");
}
return request;
}
public EReceiptRequest generateQRRefundReceipt(
String refundAmount,
String referenceNo,
String invoiceNo,
String voucherNo,
String mmqrRef,
String paymentIdentifier,
TransResultStatus status
) {
long amt = POSUtil.getInstance().convertAmount(refundAmount);
double realAmount = amt / 100.0;
DecimalFormat df = new DecimalFormat("0.00");
String amount = df.format(realAmount);
String terminalIdForEreceipt = SystemParamsOperation.getInstance().getTerminalIdForEreceipt();
String hostId = SystemParamsOperation.getInstance().getSecHostId();
String currentTimeStamp = new java.text.SimpleDateFormat("MMddHHmmss", java.util.Locale.getDefault())
.format(new java.util.Date());
EReceiptRequest request = new EReceiptRequest();
request.setDE3("QRV");
request.setDE7(currentTimeStamp);
request.setDE37(referenceNo);
request.setDE49("MMK");
request.setSerial(serialNum);
request.setAppId(packageName);
request.setDE41(qrTerminalId);
request.setDE42(qrMerchantId);
request.setTerminalId(terminalIdForEreceipt);
request.setShortCode(qrMerchantId);
request.setInvoiceNumber(invoiceNo != null ? invoiceNo : "");
request.setDE11(voucherNo != null ? voucherNo : "");
request.setHostId(hostId);
request.setMmqrRef(mmqrRef);
request.setPaymentIdentifier(paymentIdentifier);
// need to add payment identifier field too
if (status == TransResultStatus.SUCCESS) {
request.setDE4(amount);
request.setDescription("qr refund success");
request.setDE39("A");
} else if (status == TransResultStatus.TIME_OUT) {
request.setDE4("0");
request.setDescription("qr refund timeout");
request.setDE39("D");
} else if (status == TransResultStatus.FAIL) {
request.setDE4("0");
request.setDescription("qr refund failed");
request.setDE39("E");
}
return request;
}
public EReceiptRequest generateMPUReceipt(PayDetail payDetail) {
double realAmount = payDetail.getAmount() / 100.0;
DecimalFormat df = new DecimalFormat("0.00");
String amount = df.format(realAmount);
String currentTimeStamp = new java.text.SimpleDateFormat("MMddHHmmss", java.util.Locale.getDefault())
.format(new java.util.Date());
EReceiptRequest request = new EReceiptRequest();
request.setDE3(convertTransactionType(payDetail.getTransactionType()));
request.setDE7(currentTimeStamp);
request.setDE11(payDetail.getVoucherNo());
if (payDetail.getTransactionType() == TransactionsType.SETTLEMENT.value) {
SettleData settleData = payDetail.getSettleDataObj();
long totalAmt = settleData.getSaleAmount() + settleData.getRefundAmount() + settleData.getPreAuthCompAmount() + settleData.getCashAdvanceAmount();
double realTotalAmount = totalAmt / 100.0;
String totalAmount = df.format(realTotalAmount);
request.setDE4(totalAmount);
request.setDE63_01(settleData.getSaleCount() + "");
request.setDE63_02(settleData.getSaleAmount() + "");
request.setDE63_03(settleData.getRefundCount() + "");
request.setDE63_04(settleData.getRefundAmount() + "");
request.setDE63_05(settleData.getPreAuthCompCount() + "");
request.setDE63_06(settleData.getPreAuthCompAmount() + "");
request.setDE63_07(settleData.getCashAdvanceCount() + "");
request.setDE63_08(settleData.getCashAdvanceAmount() + "");
invoiceNo = SystemParamsOperation.getInstance().getIncrementInvoiceNum();
request.setBatchNumber(batchNumber);
request.setInvoiceNumber(invoiceNo);
request.setDescription("success");
request.setDE39("A");
request.setDE37("0000");
request.setDE49("MMK");
} else {
request.setDE2(POSUtil.getInstance().getCardNumMasking(payDetail.getCardNo()));
request.setDE4(amount);
request.setDE37(payDetail.getReferNo());
request.setDE38(payDetail.getApprovalCode());
// will check it later for currency code
request.setDE49("MMK");
request.setInvoiceNumber(payDetail.getInvoiceNo());
request.setCardLabel("MPU");
if (payDetail.getTradeAnswerCode().equals("000") || payDetail.getTradeAnswerCode().equals("00")) {
request.setDescription("success");
request.setDE39("A");
} else {
request.setDescription(BaseErrorCode.getErrorMessage(payDetail.getTradeAnswerCode()));
request.setDE39("E");
}
}
request.setDE41(terminalId);
request.setDE42(merchantId);
request.setSerial(serialNum);
request.setAppId(packageName);
return request;
}
public EReceiptRequest generateQRSettlement(PayDetail payDetail, List<QRSettleData> transactions) {
double realAmount = payDetail.getAmount() / 100.0;
DecimalFormat df = new DecimalFormat("0.00");
String amount = df.format(realAmount);
String currentTimeStamp = new java.text.SimpleDateFormat("MMddHHmmss", java.util.Locale.getDefault())
.format(new java.util.Date());
String terminalId = SystemParamsOperation.getInstance().getTerminalIdForEreceipt();
EReceiptRequest request = new EReceiptRequest();
// request.setDE3(convertTransactionType(payDetail.getTransactionType()));
request.setDE3("QRST");
request.setDE7(currentTimeStamp);
request.setDE11(payDetail.getVoucherNo());
String hostId = SystemParamsOperation.getInstance().getSecHostId();
request.setHostId(hostId);
request.setTerminalId(terminalId);//terminalId is not tid
request.setShortCode(qrMerchantId);
request.setTransactions(buildTransactions(transactions));
SettleData settleData = payDetail.getSettleDataObj();
long totalAmt = settleData.getSaleAmount() + settleData.getRefundAmount();
double realTotalAmount = totalAmt / 100.0;
String totalAmount = df.format(realTotalAmount);
request.setDE4(totalAmount);
request.setDE63_01(settleData.getSaleCount() + "");
request.setDE63_02(settleData.getSaleAmount() + "");
request.setDE63_03(settleData.getRefundCount() + "");
request.setDE63_04(settleData.getRefundAmount() + "");
invoiceNo = SystemParamsOperation.getInstance().getIncrementInvoiceNum();
request.setBatchNumber(batchNumber);
request.setInvoiceNumber(invoiceNo);
request.setDescription("success");
request.setDE39("A");
request.setDE37("0000");
request.setDE49("MMK");
request.setDE41(terminalId);
request.setDE42(merchantId);
request.setSerial(serialNum);
request.setAppId(packageName);
return request;
}
private static List<Transaction> buildTransactions(List<QRSettleData> qrSettleData) {
List<Transaction> list = new ArrayList<>();
for (QRSettleData pay : qrSettleData) {
double realAmount = pay.getAmount() / 100.0;
DecimalFormat df = new DecimalFormat("0.00");
String amount = df.format(realAmount);
Transaction txn = new Transaction();
txn.setTran_id(pay.getTransId()); // or ref no
txn.setStatus(
pay.getTransactionType() == TransactionsType.MMQR_REFUND.value
? "REFUND_SUCCESS"
: "PAY_SUCCESS"
);
txn.setDate(pay.getDate()); // yyyyMMdd
txn.setTime(pay.getTime()); // HHmmss
txn.setAmount(amount);
list.add(txn);
}
return list;
}
public String convertTransactionType(int transactionType) {
if (transactionType == TransactionsType.SALE.value) {
return "S";
} else if (transactionType == TransactionsType.VOID.value) {
return "V";
} else if (transactionType == TransactionsType.PRE_AUTH_SALE.value) {
return "P";
} else if (transactionType == TransactionsType.PRE_AUTH_VOID.value) {
return "PV";
} else if (transactionType == TransactionsType.PRE_AUTH_COMPLETE.value) {
return "PC";
} else if (transactionType == TransactionsType.PRE_AUTH_COMPLETE_VOID.value) {
return "PCV";
} else if (transactionType == TransactionsType.CASH_OUT.value) {
return "CAV";
} else if (transactionType == TransactionsType.REFUND.value) {
return "R";
} else if (transactionType == TransactionsType.SETTLEMENT.value) {
return "ST";
} else if (transactionType == TransactionsType.MMQR_SETTLEMENT.value) {
return "ST";
}
return "E";
}
}

View File

@ -1,13 +1,15 @@
package com.utsmm.kbz.util;
import com.sunmi.pay.hardware.aidlv2.AidlConstantsV2;
import com.utsmyanmar.checkxread.model.CardDataX;
import com.utsmyanmar.paylibs.model.CardInfo;
import com.utsmyanmar.paylibs.model.ICCardInfo;
import com.utsmyanmar.paylibs.model.MAGCardInfo;
import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.model.enums.TransCVM;
import com.utsmyanmar.paylibs.system.SystemDateTime;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.enums.BaseCardType;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.config.Constants;
@ -42,15 +44,50 @@ public class MockData {
// .cardScheme("VISA")
// .cardHolderName("U AYE")
// .iccData("5F21BLAHBLAH")
// .build();
// mockCardData = new MockCardData.Builder()
// .cardNo("9503051034047056")
// .expDate("3002")
// .cardScheme("MPU")
// .cardHolderName("KBZ Debit")
// .iccData("9503051034047056=30021015930000000000")
// .build();
// 9505050178841157=28111011310000000000
// mockCardData = new MockCardData.Builder()
// .cardNo("9505050161133125")
// .expDate("2701")
// .cardScheme("MPU")
// .cardHolderName("KBZ Credit")
// .iccData("9505050161133125=27011017250000000000")
// .build();
mockCardData = new MockCardData.Builder()
.cardNo("9503190006079422")
.expDate("0725")
.cardNo("9505050178841157")
.expDate("2811")
.cardScheme("MPU")
.cardHolderName("YOMA VALUED CUSTOMER")
.cardHolderName("KBZ Preprod")
.iccData("9505050178841157=28111011310000000000")
.build();
// mockCardData = new MockCardData.Builder()
// .cardNo("9503712156912514")
// .expDate("2912")
// .cardScheme("MPU")
// .cardHolderName("Htin Kyaw Win")
// .iccData("9503712156912514=29121010000000000000")
// .build();
// mockCardData = new MockCardData.Builder()
// .cardNo("9503742975107251")
// .expDate("0629")
// .cardScheme("MPU")
// .cardHolderName("Bank Q")
// .iccData("9503742975107251=22081010000000000000")
// .build();
// mockCardData = new MockCardData.Builder()
// .phoneNo("9794452506")
// .expDate("0425")
@ -74,6 +111,15 @@ public class MockData {
return String.valueOf(randomNumber);
}
public CardDataX generateMPUCard() {
CardDataX cardDataX = new CardDataX();
cardDataX.setPan(mockCardData.getCardNo());
cardDataX.setExp(mockCardData.getExpDate());
cardDataX.setCardHolderName(mockCardData.getCardHolderName());
cardDataX.setTrack2(mockCardData.getIccData());
return cardDataX;
}
public TradeData generateMockDataWithTime(TransactionsType transType,int cardInputType,String transDate,String transTime) {
String strDate = SystemDateTime.getMMDD();
String strTime = SystemDateTime.getHHmmss();
@ -114,6 +160,7 @@ public class MockData {
payDetail.setOriginalTransDate(SystemDateTime.getMMDD()+SystemDateTime.getYYYY());
payDetail.setTransCVM(TransCVM.NO_CVM);
if(transType == TransactionsType.MMQR) {
payDetail.setCardType(cardInputType);
payDetail.setTransType(transType.name);
@ -121,7 +168,13 @@ public class MockData {
payDetail.setCardHolderName(mockCardData.getCardHolderName());
payDetail.setAccountType(mockCardData.getCardScheme());
payDetail.setCustomerMobile(mockCardData.getPhoneNo());
payDetail.setCustomerMobile("kbzpay");
payDetail.setOriginalTransDate("2024-09-16 15:57:10");
payDetail.setQrTransId("12345678");
payDetail.setQrTransStatus(1);
payDetail.setQrReferNo("123456789012");
payDetail.setReferNo("123456789012");
payDetail.setApprovalCode("12345678");
} else {
payDetail.setCardType(cardInputType);
@ -160,7 +213,7 @@ public class MockData {
// payDetail.setTransDate(strTransDate);
// payDetail.setTransTime(strTransTime);
payDetail.setAmount(10000);
payDetail.setAmount(100000);
payDetail.setTransactionType(transType.value);
tradeData.setPayDetail(payDetail);
@ -298,7 +351,7 @@ public class MockData {
String refundAmount = "1000";
int caCount = 0;
String caAmount = "0";
int cardInputType = AidlConstantsV2.CardType.IC.getValue();
int cardInputType = BaseCardType.IC.getValue();
TradeData tradeData = generateMockData(TransactionsType.SETTLEMENT,cardInputType);
PayDetail payDetail = tradeData.getPayDetail();
int totalAmount = Integer.parseInt(saleAmount) + Integer.parseInt(preAuthAmount) + Integer.parseInt(refundAmount);

View File

@ -13,6 +13,11 @@ import com.utsmm.kbz.config.Constants;
import com.utsmyanmar.paylibs.utils.LogUtil;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class TransactionUtil {
@ -36,7 +41,7 @@ public class TransactionUtil {
private TransactionUtil() {
qrTerminalId = SystemParamsOperation.getInstance().getSecHostTerminalId();
qrMerchantId = SystemParamsOperation.getInstance().getSecHostMerchantId();
qrMerchantId = SystemParamsOperation.getInstance().getShortCode();
}
public String getQRMerchantId() {
@ -66,6 +71,25 @@ public class TransactionUtil {
return tradeData;
}
public TradeData initEMVTransaction(CardDataX cardDataX,CardTypeX cardTypeX) {
LogUtil.d(TAG,"CardDataX : "+cardDataX.toString());
TradeData tradeData = Params.newTrade(false);
PayDetail payDetail = tradeData.getPayDetail();
payDetail.setCardNo(cardDataX.getPan());
payDetail.setEXPDate(cardDataX.getExp());
payDetail.setCardType(cardTypeX.value);
payDetail.setAccountType("VISA");
payDetail.setAmount(100000);
payDetail.setCardHolderName(cardDataX.getCardHolderName());
CardInfo cardInfo = new CardInfo();
MAGCardInfo magCardInfo = new MAGCardInfo();
magCardInfo.setTrack2Cipher(cardDataX.getTrack2());
cardInfo.setMAGCardInfo(magCardInfo);
payDetail.setCardInfo(cardInfo);
payDetail.setICC55("5F2A0201045F340100820218008407A0000000031010950580800080009A032601099C01009F02060000000500009F03060000000000009F090200209F100706011203A0B8009F1A0201049F1E0820202020202020209F26088D3992CD453684B69F2701809F3303E0E8C89F34031E03009B0268009F3501229F360200049F370416C252349F41030000019F530152");
return tradeData;
}
public TradeData initMagStripeTransaction(CardDataX cardDataX,boolean isFallback) {
@ -119,4 +143,25 @@ public class TransactionUtil {
return payDetail;
}
// public static List<String> binParser(String input) {
//
// if (input == null || input.trim().isEmpty()) {
// return new ArrayList<>();
// }
// String[] parts = input.split("[,/\\-]");
//
// return Arrays.stream(parts)
// .map(String::trim)
// .filter(s -> !s.isEmpty())
// .collect(Collectors.toList());
// }
//
// public List<String> getBinList() {
// if(SystemParamsOperation.getInstance().getBinValues() == null || SystemParamsOperation.getInstance().getBinValues().isEmpty())
// return new ArrayList<>();
// else
// return binParser(SystemParamsOperation.getInstance().getBinValues());
// }
}

View File

@ -21,5 +21,6 @@ public enum FeaturesType {
TEST,
QR_INQUIRY,
QR_REFUND,
LOG_OUT
LOG_OUT,
DEVICE_CONFIG
}

View File

@ -26,6 +26,7 @@ public enum TransResultStatus {
RETRY_AGAIN,
NEXT_SCREEN,
EMPTY_PIN,
NETWORK_ERROR
NETWORK_ERROR,
TIME_OUT
}

View File

@ -0,0 +1,44 @@
package com.utsmm.kbz.util.helper;
import android.app.Activity;
import android.content.Context;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
public class KeyboardHelper {
private KeyboardHelper() {
// no instance
}
/** Hide keyboard using a View (Fragment-safe) */
public static void hide(Context context, View view) {
if (context == null || view == null) return;
InputMethodManager imm =
(InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
view.clearFocus();
}
}
/** Hide keyboard using Activity (Activity-safe) */
public static void hide(Activity activity) {
if (activity == null) return;
View view = activity.getCurrentFocus();
if (view == null) {
view = activity.getWindow().getDecorView();
}
InputMethodManager imm =
(InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm != null) {
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
view.clearFocus();
}
}
}

View File

@ -4,12 +4,16 @@ import android.content.pm.PackageInfo;
import android.text.TextUtils;
import com.google.gson.Gson;
import com.utsmm.kbz.util.DownloadUtil;
import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.network.model.sirius.SiriusHost;
import com.utsmyanmar.baselib.network.model.sirius.SiriusMerchant;
import com.utsmyanmar.baselib.network.model.sirius.SiriusProperty;
import com.utsmyanmar.baselib.network.model.sirius.SiriusResponse;
import com.utsmyanmar.baselib.network.model.sirius.SiriusTerminal;
import com.utsmyanmar.baselib.util.EReceiptHelper;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsSettings;
import com.utsmyanmar.paylibs.utils.enums.CurrencyType;
import com.utsmm.kbz.BuildConfig;
@ -31,6 +35,9 @@ public class TMSSetupsImpl implements TMSSetups{
private static final String JCB = "JCB";
private static final String VISA = "VISA";
private static final String MASTERCARD = "MASTERCARD";
private static final String E_RECEIPT_SECRET = com.utsmyanmar.baselib.BuildConfig.ERECEIPT_SECRET;
String timestamp = String.valueOf(System.currentTimeMillis());
String signature = generateSignature(E_RECEIPT_SECRET, timestamp);
private CurrencyType currencyTextToCurrencyType(String currencyTxt) {
@ -129,6 +136,8 @@ public class TMSSetupsImpl implements TMSSetups{
SiriusMerchant siriusMerchant = siriusResponse.getMerchant();
SiriusTerminal siriusTerminal = siriusResponse.getTerminal();
List<SiriusHost> siriusHosts = siriusResponse.getHosts();
List<SiriusProperty> siriusProperties = siriusResponse.getProperties();
@ -147,6 +156,10 @@ public class TMSSetupsImpl implements TMSSetups{
SystemParamsOperation.getInstance().setMerchantAddress2("");
}
if(siriusResponse.getAddress3() != null && siriusResponse.getAddress3().isEmpty()){
SystemParamsOperation.getInstance().setMerchantAddress3("");
}
init();
if(siriusMerchant != null) {
@ -154,10 +167,17 @@ public class TMSSetupsImpl implements TMSSetups{
SystemParamsOperation.getInstance().setMerchantName(siriusMerchant.getName());
SystemParamsOperation.getInstance().setMerchantAddress(siriusMerchant.getAddress());
SystemParamsOperation.getInstance().setMerchantAddress2(siriusMerchant.getAddress2());
SystemParamsOperation.getInstance().setMerchantAddress3(siriusMerchant.getAddress3());
SystemParamsOperation.getInstance().setMerchantPhoneNo(siriusMerchant.getMobile());
SystemParamsOperation.getInstance().setTerminalName(siriusMerchant.getDescription());
SystemParamsOperation.getInstance().setTerminalIdForEreceipt(siriusTerminal.getId());
}
if(siriusTerminal != null){
SystemParamsOperation.getInstance().setTerminalName(siriusTerminal.getName());
}
if(siriusResponse.getAddress() != null && !siriusResponse.getAddress().isEmpty()) {
SystemParamsOperation.getInstance().setMerchantAddress(siriusResponse.getAddress());
}
@ -170,11 +190,13 @@ public class TMSSetupsImpl implements TMSSetups{
for (SiriusHost siriusHost: siriusHosts) {
if( siriusHost.getName().toLowerCase().contains("mmqr") || siriusHost.getName().toLowerCase().contains("kbzpay") || siriusHost.getDescription().toLowerCase().contains("mmqr") || siriusHost.getDescription().toLowerCase().contains("qr")) {
if( siriusHost.getTyp().equals("QR")) {
SystemParamsOperation.getInstance().setSecHostId(siriusHost.getId());
SystemParamsOperation.getInstance().setSecHostName(siriusHost.getName());
SystemParamsOperation.getInstance().setSecHostTerminalId(siriusHost.getTid());
SystemParamsOperation.getInstance().setSecHostMerchantId(extractDigits(siriusHost.getMid()));
SystemParamsOperation.getInstance().setShortCode(siriusHost.getShortCode());
if (siriusHost.getPrimaryIP().contains(":")) {
@ -212,15 +234,8 @@ public class TMSSetupsImpl implements TMSSetups{
// SystemParamsOperation.getInstance().setSecHostCurrency(currencyTextToCode(siriusHost.getCurrency()));
// }
}
if (siriusHost.getTid().isEmpty() || siriusHost.getMid().isEmpty() ) {
if(siriusHost.getTid().isEmpty()) {
SystemParamsOperation.getInstance().setSecHostTerminalId("");
}
if(siriusHost.getMid().isEmpty()) {
SystemParamsOperation.getInstance().setSecHostMerchantId("");
}
if (siriusHost.getShortCode() == null || siriusHost.getShortCode().isEmpty()) {
SystemParamsOperation.getInstance().setShortCode("");
}
} else {
@ -236,15 +251,21 @@ public class TMSSetupsImpl implements TMSSetups{
} else if(siriusHost.getPrimaryIP().trim().isEmpty()) {
SystemParamsOperation.getInstance().setIpAddress("");
}
if (siriusHost.getSecondaryIP().contains(":")) {
SystemParamsOperation.getInstance().setSecIpAddress(siriusHost.getSecondaryIP().trim());
} else if(siriusHost.getSecondaryIP().trim().isEmpty()){
String secondaryIp = siriusHost.getSecondaryIP();
if(secondaryIp == null || secondaryIp.trim().isEmpty()){
SystemParamsOperation.getInstance().setSecIpAddress("");
}else if(secondaryIp.contains(":")){
SystemParamsOperation.getInstance().setSecIpAddress(secondaryIp.trim());
}
// if (siriusHost.getSecondaryIP().contains(":")) {
//
// SystemParamsOperation.getInstance().setSecIpAddress(siriusHost.getSecondaryIP().trim());
//
// } else if(siriusHost.getSecondaryIP().trim().isEmpty()){
// SystemParamsOperation.getInstance().setSecIpAddress("");
// }
if (!siriusHost.getCurrency().isEmpty()) {
SystemParamsOperation.getInstance().setCurrencyType(currencyTextToCurrencyType(siriusHost.getCurrency()));
@ -412,15 +433,26 @@ public class TMSSetupsImpl implements TMSSetups{
} else if (TextUtils.equals(name,"ssl_enable")) {
SystemParamsOperation.getInstance().setSslSwitchStatus(parseBoolean(data));
} else if (TextUtils.equals(name,"wave_pay_inquiry_status_enable")) {
} else if (TextUtils.equals(name,"qrpay_inquiry_status_enable")) {
SystemParamsOperation.getInstance().setQRPayInquiryStatus(parseBoolean(data));
SystemParamsOperation.getInstance().setWavePayInquiryStatus(parseBoolean(data));
} else if (TextUtils.equals(name,"tips_adjustment_enable")) {
SystemParamsOperation.getInstance().setTipsAdjustmentStatus(parseBoolean(data));
} else if (TextUtils.equals(name,"wave_enable")) {
SystemParamsOperation.getInstance().setWavePayStatus(parseBoolean(data));
} else if (TextUtils.equals(name,"qrpay_enable")) {
SystemParamsOperation.getInstance().setQRPayStatus(parseBoolean(data));
} else if (TextUtils.equals(name, "qr_partial_refund_enable")){
SystemParamsOperation.getInstance().setQrPartialRefundEnable(parseBoolean(data));
} else if(TextUtils.equals(name, "mmqr_interval_waiting_time")){
SystemParamsOperation.getInstance().setWaveIntervalTime(data);
} else if (TextUtils.equals(name,"print_iso_enable")) {
SystemParamsOperation.getInstance().setPrintISOStatus(parseBoolean(data));
@ -454,9 +486,6 @@ public class TMSSetupsImpl implements TMSSetups{
} else if (TextUtils.equals(name,"manual_entry_enable")) {
SystemParamsOperation.getInstance().setManualEntyrStatus(parseBoolean(data));
} else if (TextUtils.equals(name,"mmqr_interval_waiting_time")) {
SystemParamsOperation.getInstance().setWaveIntervalTime(data);
} else if (TextUtils.equals(name,"full_void_preauth_enable")) {
SystemParamsOperation.getInstance().setFullVoidPreauthStatus(parseBoolean(data));
@ -582,18 +611,55 @@ public class TMSSetupsImpl implements TMSSetups{
}
} else if (TextUtils.equals(name,"speedup_contactless_enable")) {
SystemParamsOperation.getInstance().setSpeedUpContactless(parseBoolean(data));
}
else if (TextUtils.equals(name,"manual_entry_pin_enable")) {
} else if (TextUtils.equals(name,"manual_entry_pin_enable")) {
SystemParamsOperation.getInstance().setManualEntryPinEnable(parseBoolean(data));
} else if (TextUtils.equals(name,"decimal_enable")) {
SystemParamsOperation.getInstance().setDecimalEnable(parseBoolean(data));
} else if (TextUtils.equals(name,"app_key")) {
SystemParamsOperation.getInstance().setAppKey(data);
} else if (TextUtils.equals(name,"app_id")) {
SystemParamsOperation.getInstance().setAppId(data);
} else if (TextUtils.equals(name, "qr_decimal_enable")) {
SystemParamsOperation.getInstance().setQrDecimalEnable(parseBoolean(data));
} else if (TextUtils.equals(name, "qr_refund_enable")){
SystemParamsOperation.getInstance().setQrRefundEnable(parseBoolean(data));
} else if (TextUtils.equals(name, "tpdu_value")){
SystemParamsOperation.getInstance().setTpduValue(data);
}
else if(TextUtils.equals(name, "certificate_file")){
if (TextUtils.isEmpty(data)) {
LogUtil.e(TAG, "certificate_file value NULL from TMS");
continue;
}
SystemParamsOperation.getInstance().setCertificateUrl(data);
}
else if(TextUtils.equals(name, "certificate_client")){
if (TextUtils.isEmpty(data)) {
LogUtil.e(TAG, "certificate_file value NULL from TMS");
continue;
}
SystemParamsOperation.getInstance().setCertificateClientUrl(data);
}
else if (TextUtils.equals(name, "certificate_password")) {
SystemParamsOperation.getInstance().setCertificatePassword(data);
}
else if(TextUtils.equals(name,"bin_list")) {
SystemParamsOperation.getInstance().setBinValue(data);
}
else if(TextUtils.equals(name, "printer_enabled")){
SystemParamsOperation.getInstance().setPrinterEnabled(parseBoolean(data));
}
}
SystemParamsOperation.getInstance().setCarouselUrls(convertToString(imgUrls));
}
private static String generateSignature(String apiSecret, String timestamp) {
String bodyString = "{}";
String dataToHash = bodyString + apiSecret + timestamp;
return EReceiptHelper.sha256(dataToHash);
}
private String convertToString(ArrayList<String> list) {
@ -683,8 +749,8 @@ public class TMSSetupsImpl implements TMSSetups{
int value = Integer.parseInt(data);
return value == 1;
} catch (Exception e) {
e.printStackTrace();
return false;
// e.printStackTrace();
return Boolean.parseBoolean(data);
}
}
}

View File

@ -147,7 +147,8 @@ public class TMSUtil {
siriusRequest.setApplicationVersion(BuildConfig.VERSION_NAME);
siriusRequest.setCurrentNetwork(getNetworkType(context));
siriusRequest.setLastTransaction(lastTransName);
siriusRequest.setLastTranTime(lastTransTime);
siriusRequest.setLastTranTime(Long.parseLong(lastTransTime));
siriusRequest.setValue("YourValueHere");
return siriusRequest;
}
@ -176,7 +177,6 @@ public class TMSUtil {
LogUtil.d(TAG,"Receipt Footer: "+SystemParamsOperation.getInstance().getReceiptFooter());
LogUtil.d(TAG,"Manual Update: "+SystemParamsOperation.getInstance().getManualUpdate());
LogUtil.d(TAG,"Master Enabled: "+SystemParamsOperation.getInstance().isEmvEnabled());
}
@ -206,21 +206,20 @@ public class TMSUtil {
voidStatus = SystemParamsOperation.getInstance().getVoidStatus();
cashAdvanceStatus = SystemParamsOperation.getInstance().getCashAdvanceStatus();
refundStatus = SystemParamsOperation.getInstance().getRefundStatus();
wavePayInquiryStatus = SystemParamsOperation.getInstance().getWavePayInquiryStatus();
wavePayInquiryStatus = SystemParamsOperation.getInstance().getQRPayInquiryStatus();
tipAdjustmentStatus = SystemParamsOperation.getInstance().getTipsAdjustmentStatus();
settlementStatus = SystemParamsOperation.getInstance().getSettlementStatus();
featuresList.add(new Features(2, fragmentActivity.getString(R.string.menu_sale_void), R.drawable.ic_void_dash, FeaturesType.VOID, voidStatus));
featuresList.add(new Features(2, fragmentActivity.getString(R.string.menu_settlement), R.drawable.ic_settlement, FeaturesType.SETTLEMENT, settlementStatus));
// featuresList.add(new Features(2, fragmentActivity.getString(R.string.menu_settlement), R.drawable.ic_settlement, FeaturesType.SETTLEMENT, settlementStatus));
featuresList.add(new Features(4, fragmentActivity.getString(R.string.menu_refund), R.drawable.ic_refund, FeaturesType.REFUND, refundStatus));
featuresList.add(new Features(3, fragmentActivity.getString(R.string.menu_preauth), R.drawable.ic_pre_auth_dash, FeaturesType.PRE_AUTH_SALE, preAuthStatus));
featuresList.add(new Features(6, fragmentActivity.getString(R.string.menu_preauth_cancellation), R.drawable.ic_pre_auth_dash, FeaturesType.PRE_AUTH_VOID, preAuthCancelStatus));
featuresList.add(new Features(6, fragmentActivity.getString(R.string.menu_preauth_completion), R.drawable.ic_pre_auth_dash, FeaturesType.PRE_AUTH_COMPLETE, preAuthCompleteStatus));
featuresList.add(new Features(6, fragmentActivity.getString(R.string.menu_preauth_comp_cancellation), R.drawable.ic_pre_auth_dash, FeaturesType.PRE_AUTH_COMPLETE_VOID, preAuthCompleteCancelStatus));
// featuresList.add(new Features(5, fragmentActivity.getString(R.string.menu_wavepay_inquiry), R.drawable.ic_wave_status_dash, FeaturesType.WAVE_PAY_INQUIRY, wavePayInquiryStatus));
featuresList.add(new Features(1, fragmentActivity.getString(R.string.menu_cash_advance), R.drawable.ic_cash_advance, FeaturesType.CASH_ADVANCE, cashAdvanceStatus));
featuresList.add(new Features(9, fragmentActivity.getString(R.string.menu_history), R.drawable.ic_history, FeaturesType.HISTORY, true));
// featuresList.add(new Features(9, fragmentActivity.getString(R.string.menu_history), R.drawable.ic_history, FeaturesType.HISTORY, true));
featuresList.add(new Features(10, "Configs", R.drawable.ic_host, FeaturesType.DEVICE_CONFIG, true));
}
public TMSValidity checkParams() {
@ -232,17 +231,19 @@ public class TMSUtil {
String secHostIp = SystemParamsOperation.getInstance().getSecIpAddress();
String keyIndex = SystemParamsOperation.getInstance().getTMKIndex();
if(tid.length() == 8 && mid.length() == 15 && !hostIp.isEmpty() && !secHostIp.isEmpty() && !keyIndex.isEmpty()) {
if(tid.length() == 8 && (mid.length() == 11 || mid.length() == 15) && !hostIp.isEmpty() && !keyIndex.isEmpty()) {
tmsValidity = new TMSValidity(ValidityStatus.SUCCESS,"Success");
} else if(tid.length() != 8) {
tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"Tid is invalid!");
} else if(mid.length() != 15) {
} else if(mid.length() != 15 && mid.length() != 11 ) {
tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"Mid is invalid!");
} else if(hostIp.isEmpty()) {
tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"Pri-Ip is invalid!");
} else if(secHostIp.isEmpty()) {
tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"Sec-Ip is invalid!");
} else {
}
// else if(secHostIp.isEmpty()) {
// tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"Sec-Ip is invalid!");
// }
else {
tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"KeyIndex is invalid!");
}
@ -250,6 +251,28 @@ public class TMSUtil {
return tmsValidity;
}
public TMSValidity checkQRParams() {
TMSValidity tmsValidity;
String shortCode = SystemParamsOperation.getInstance().getShortCode();
String appId = SystemParamsOperation.getInstance().getAppId();
String appKey = SystemParamsOperation.getInstance().getAppKey();
if(shortCode.length() == 11 && !appId.isEmpty() && !appKey.isEmpty()) {
tmsValidity = new TMSValidity(ValidityStatus.SUCCESS,"Success");
} else if(shortCode.length() != 11) {
tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"Invalid Short Code!");
} else if(appId.isEmpty() ) {
tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"Invalid AppId!");
} else {
tmsValidity = new TMSValidity(ValidityStatus.FAILURE,"Invalid AppKey!");
}
return tmsValidity;
}
public TMSValidity checkSecHostParams() {
TMSValidity tmsValidity;
@ -296,6 +319,7 @@ public class TMSUtil {
Log.d(TAG,"Connected to Wifi");
return "WIFI";
}
}return "No Connection";
}
return "No Connection";
}
}

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