From 5d450e0a487d10f843cba30d10ffb8370ac2d387 Mon Sep 17 00:00:00 2001
From: MooN <56061215+MgKyawLay@users.noreply.github.com>
Date: Sun, 23 Nov 2025 01:35:04 +0630
Subject: [PATCH] qr-e-receipt
---
app/build.gradle | 4 +-
.../ui/core_viewmodel/SharedViewModel.java | 38 ++++++
.../kbz/ui/kpay/QRTransactionFragment.java | 29 +++++
.../main/res/xml/network_security_config.xml | 3 +
.../utsmyanmar/baselib/di/DatabaseModule.java | 7 +-
.../utsmyanmar/baselib/di/NetworkModule.java | 21 +++
.../baselib/network/EReceiptApiService.java | 20 +++
.../interceptor/SiriusInterceptor.java | 1 +
.../model/e_receipt/EReceiptQRRequest.java | 123 ++++++++++++++++++
.../model/e_receipt/EReceiptResponse.java | 14 ++
.../utsmyanmar/baselib/repo/Repository.java | 20 ++-
.../baselib/util/EReceiptHelper.java | 48 +++++++
12 files changed, 320 insertions(+), 8 deletions(-)
create mode 100644 baselib/src/main/java/com/utsmyanmar/baselib/network/EReceiptApiService.java
create mode 100644 baselib/src/main/java/com/utsmyanmar/baselib/network/model/e_receipt/EReceiptQRRequest.java
create mode 100644 baselib/src/main/java/com/utsmyanmar/baselib/network/model/e_receipt/EReceiptResponse.java
create mode 100644 baselib/src/main/java/com/utsmyanmar/baselib/util/EReceiptHelper.java
diff --git a/app/build.gradle b/app/build.gradle
index c7ed323..f7448e2 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -14,8 +14,8 @@ android {
applicationId "com.utsmm.kbz"
minSdk 24
targetSdk 33
- versionCode 7
- versionName "1.07"
+ versionCode 8
+ versionName "1.08"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/java/com/utsmm/kbz/ui/core_viewmodel/SharedViewModel.java b/app/src/main/java/com/utsmm/kbz/ui/core_viewmodel/SharedViewModel.java
index 496b73e..b58c0a7 100644
--- a/app/src/main/java/com/utsmm/kbz/ui/core_viewmodel/SharedViewModel.java
+++ b/app/src/main/java/com/utsmm/kbz/ui/core_viewmodel/SharedViewModel.java
@@ -1,12 +1,15 @@
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;
@@ -26,9 +29,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
@@ -415,4 +424,33 @@ public class SharedViewModel extends ViewModel {
}
+ public void pushReceipt(Object 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());
+ }
+ }
+ );
+ }
+
+
+
}
diff --git a/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java b/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java
index c81e0a5..11ed2d9 100644
--- a/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java
+++ b/app/src/main/java/com/utsmm/kbz/ui/kpay/QRTransactionFragment.java
@@ -1,6 +1,7 @@
package com.utsmm.kbz.ui.kpay;
import android.annotation.SuppressLint;
+import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
@@ -13,6 +14,7 @@ import androidx.annotation.Nullable;
import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.DemoQRStatusRequest;
import com.utsmyanmar.baselib.network.model.KPayQRQueryRequest;
+import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptQRRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.ecr.ECRHelper;
@@ -27,6 +29,10 @@ 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.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
@@ -308,6 +314,29 @@ public class QRTransactionFragment extends DataBindingFragment implements DataBi
retrievedUpdatePayDetail(refLabel, payDetail,false);
+ DecimalFormat df = new DecimalFormat("0.00");
+ String amount = df.format(payDetail.getAmount());
+
+ String currentTimeStamp = new java.text.SimpleDateFormat("MMddHHmmss", java.util.Locale.getDefault())
+ .format(new java.util.Date());
+ String serial = SystemParamsOperation.getInstance().getCurrentSerialNum();
+ String packageName = getActivity().getPackageName();
+ EReceiptQRRequest request = new EReceiptQRRequest();
+ request.setDE3("QR");
+ request.setDE4(amount);
+ request.setDE7(currentTimeStamp);
+ request.setDE37(payDetail.getReferNo());
+ request.setDE39("A");
+ request.setDE49("MMK");
+ request.setSerial(serial);
+ request.setAppId(packageName);
+ request.setDE41(terminalId);
+ request.setDE42(merchantId);
+ request.setInvoiceNumber(payDetail.getInvoiceNo());
+ request.setDE11(payDetail.getVoucherNo());
+ request.setDescription("qr pay success");
+ sharedViewModel.pushReceipt(request);
+
return;
}
diff --git a/app/src/main/res/xml/network_security_config.xml b/app/src/main/res/xml/network_security_config.xml
index 51044ab..53d56cc 100644
--- a/app/src/main/res/xml/network_security_config.xml
+++ b/app/src/main/res/xml/network_security_config.xml
@@ -6,6 +6,9 @@
128.199.170.203
152.42.199.193
api.kbzpay.com
+
+ receipt-nest.utsmyanmar.com
+
sirius-nest.utsmyanmar.com
\ No newline at end of file
diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java b/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java
index b932d00..c1a210b 100644
--- a/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java
+++ b/baselib/src/main/java/com/utsmyanmar/baselib/di/DatabaseModule.java
@@ -23,6 +23,7 @@ import com.utsmyanmar.baselib.db.dao.QuickPassDao;
import com.utsmyanmar.baselib.db.dao.RidDao;
import com.utsmyanmar.baselib.db.model.EmvDetail;
import com.utsmyanmar.baselib.network.DemoQRApiService;
+import com.utsmyanmar.baselib.network.EReceiptApiService;
import com.utsmyanmar.baselib.network.KPayApiService;
import com.utsmyanmar.baselib.network.KPayRefundApiService;
import com.utsmyanmar.baselib.network.SiriusApiService;
@@ -447,10 +448,12 @@ public class DatabaseModule {
com.utsmyanmar.baselib.repo.local.PayWaveRepository payWaveRepository,
DemoQRApiService demoQRApiService,
KPayApiService kPayApiService,
- KPayRefundApiService kPayRefundApiService) {
+ KPayRefundApiService kPayRefundApiService,
+ EReceiptApiService eReceiptApiService
+ ) {
return new com.utsmyanmar.baselib.repo.Repository(payDetailDao,
siriusApiService, emvDetailDao,
- payWaveRepository, demoQRApiService, kPayApiService, kPayRefundApiService);
+ payWaveRepository, demoQRApiService, kPayApiService, kPayRefundApiService, eReceiptApiService);
}
@Provides
diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/di/NetworkModule.java b/baselib/src/main/java/com/utsmyanmar/baselib/di/NetworkModule.java
index f57fbe2..989ee41 100644
--- a/baselib/src/main/java/com/utsmyanmar/baselib/di/NetworkModule.java
+++ b/baselib/src/main/java/com/utsmyanmar/baselib/di/NetworkModule.java
@@ -9,6 +9,7 @@ import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
//import com.utsmyanmar.baselib.BuildConfig;
import com.utsmyanmar.baselib.network.DemoQRApiService;
+import com.utsmyanmar.baselib.network.EReceiptApiService;
import com.utsmyanmar.baselib.network.KPayApiService;
import com.utsmyanmar.baselib.network.KPayRefundApiService;
import com.utsmyanmar.baselib.network.SiriusApiService;
@@ -386,5 +387,25 @@ public class NetworkModule {
return retrofit.create(KPayRefundApiService.class);
}
+ @Provides
+ @Singleton
+ public EReceiptApiService provideEReceiptApiService(){
+
+ HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+
+ OkHttpClient client = new OkHttpClient.Builder()
+ .addInterceptor(interceptor)
+ .build();
+
+ return new Retrofit.Builder()
+ .baseUrl("http://receipt-nest.utsmyanmar.com/") // base URL
+ .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
+ .addConverterFactory(GsonConverterFactory.create())
+ .client(client)
+ .build()
+ .create(EReceiptApiService.class);
+ }
+
}
diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/network/EReceiptApiService.java b/baselib/src/main/java/com/utsmyanmar/baselib/network/EReceiptApiService.java
new file mode 100644
index 0000000..b85e6c2
--- /dev/null
+++ b/baselib/src/main/java/com/utsmyanmar/baselib/network/EReceiptApiService.java
@@ -0,0 +1,20 @@
+package com.utsmyanmar.baselib.network;
+
+
+import com.google.gson.JsonElement;
+import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptResponse;
+
+import io.reactivex.rxjava3.core.Observable;
+import retrofit2.http.Body;
+import retrofit2.http.Header;
+import retrofit2.http.POST;
+
+public interface EReceiptApiService {
+
+ @POST("transaction")
+ Observable sendReceipt(
+ @Header("x-timestamp") String timestamp,
+ @Header("x-api-key") String apiKey,
+ @Body Object body
+ );
+}
diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/network/interceptor/SiriusInterceptor.java b/baselib/src/main/java/com/utsmyanmar/baselib/network/interceptor/SiriusInterceptor.java
index 3036279..7486d67 100644
--- a/baselib/src/main/java/com/utsmyanmar/baselib/network/interceptor/SiriusInterceptor.java
+++ b/baselib/src/main/java/com/utsmyanmar/baselib/network/interceptor/SiriusInterceptor.java
@@ -29,6 +29,7 @@ public class SiriusInterceptor implements Interceptor {
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
+
Request request = chain.request();
Request newRequest;
diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/network/model/e_receipt/EReceiptQRRequest.java b/baselib/src/main/java/com/utsmyanmar/baselib/network/model/e_receipt/EReceiptQRRequest.java
new file mode 100644
index 0000000..7350ff3
--- /dev/null
+++ b/baselib/src/main/java/com/utsmyanmar/baselib/network/model/e_receipt/EReceiptQRRequest.java
@@ -0,0 +1,123 @@
+package com.utsmyanmar.baselib.network.model.e_receipt;
+
+public class EReceiptQRRequest {
+ private String DE3;
+ private String DE39;
+ private String DE41;
+ private String DE42;
+ private String serial;
+ private String DE49;
+ private String DE37;
+ private String DE7;
+ private String DE4;
+ private String appId;
+ private String invoiceNumber;
+ private String DE11;
+ private String description;
+
+ public EReceiptQRRequest() {}
+
+ // GETTERS
+ public String getDE3() {
+ return DE3;
+ }
+
+ public String getDE39() {
+ return DE39;
+ }
+
+ public String getDE41() {
+ return DE41;
+ }
+
+ public String getDE42() {
+ return DE42;
+ }
+
+ public String getSerial() {
+ return serial;
+ }
+
+ public String getDE49() {
+ return DE49;
+ }
+
+ public String getDE37() {
+ return DE37;
+ }
+
+ public String getDE7() {
+ return DE7;
+ }
+
+ public String getDE4() {
+ return DE4;
+ }
+
+ public String getAppId(){
+ return appId;
+ }
+
+ public String getInvoiceNumber(){
+ return invoiceNumber;
+ }
+ public String getDE11(){
+ return DE11;
+ }
+
+ public String getDescription(){
+ return description;
+ }
+ // SETTERS
+ public void setDE3(String DE3) {
+ this.DE3 = DE3;
+ }
+
+ public void setDE39(String DE39) {
+ this.DE39 = DE39;
+ }
+
+ public void setDE41(String DE41) {
+ this.DE41 = DE41;
+ }
+
+ public void setDE42(String DE42) {
+ this.DE42 = DE42;
+ }
+
+ public void setSerial(String serial) {
+ this.serial = serial;
+ }
+
+ public void setDE49(String DE49) {
+ this.DE49 = DE49;
+ }
+
+ public void setDE37(String DE37) {
+ this.DE37 = DE37;
+ }
+
+ public void setDE7(String DE7) {
+ this.DE7 = DE7;
+ }
+
+ public void setDE4(String DE4) {
+ this.DE4 = DE4;
+ }
+
+ public void setAppId(String appId){
+ this.appId = appId;
+ }
+
+ public void setInvoiceNumber(String invoiceNumber){
+ this.invoiceNumber = invoiceNumber;
+ }
+
+ public void setDE11(String DE11){
+ this.DE11 = DE11;
+ }
+
+ public void setDescription(String description){
+ this.description = description;
+ }
+}
diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/network/model/e_receipt/EReceiptResponse.java b/baselib/src/main/java/com/utsmyanmar/baselib/network/model/e_receipt/EReceiptResponse.java
new file mode 100644
index 0000000..89be5a5
--- /dev/null
+++ b/baselib/src/main/java/com/utsmyanmar/baselib/network/model/e_receipt/EReceiptResponse.java
@@ -0,0 +1,14 @@
+package com.utsmyanmar.baselib.network.model.e_receipt;
+
+public class EReceiptResponse {
+ private String message;
+ private String code;
+
+ public String getMessage(){
+ return message;
+ }
+
+ public String getCode(){
+ return code;
+ }
+}
diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/repo/Repository.java b/baselib/src/main/java/com/utsmyanmar/baselib/repo/Repository.java
index 83fd706..b95370a 100644
--- a/baselib/src/main/java/com/utsmyanmar/baselib/repo/Repository.java
+++ b/baselib/src/main/java/com/utsmyanmar/baselib/repo/Repository.java
@@ -4,11 +4,14 @@ package com.utsmyanmar.baselib.repo;
import androidx.lifecycle.LiveData;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
import com.utsmyanmar.baselib.db.dao.EmvDetailDao;
import com.utsmyanmar.baselib.db.dao.PayDetailDao;
import com.utsmyanmar.baselib.db.model.EmvDetail;
import com.utsmyanmar.baselib.db.model.PayWaveEntity;
import com.utsmyanmar.baselib.network.DemoQRApiService;
+import com.utsmyanmar.baselib.network.EReceiptApiService;
import com.utsmyanmar.baselib.network.KPayApiService;
import com.utsmyanmar.baselib.network.KPayRefundApiService;
import com.utsmyanmar.baselib.network.SiriusApiService;
@@ -29,10 +32,12 @@ import com.utsmyanmar.baselib.network.model.WaveQRRequest;
import com.utsmyanmar.baselib.network.model.WaveQRResponse;
import com.utsmyanmar.baselib.network.model.WaveStatusRequest;
import com.utsmyanmar.baselib.network.model.WaveTokenResponse;
+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.network.model.KPayRefund;
import com.utsmyanmar.baselib.repo.local.PayWaveRepository;
+import com.utsmyanmar.baselib.util.EReceiptHelper;
import com.utsmyanmar.paylibs.model.PayDetail;
import java.util.List;
@@ -57,8 +62,9 @@ public class Repository {
private DemoQRApiService demoQRApiService;
private KPayRefundApiService kPayRefundApiService;
+ private EReceiptApiService eReceiptApiService;
@Inject
- public Repository(PayDetailDao payDetailDao, SiriusApiService siriusApiService, EmvDetailDao emvDetailDao, PayWaveRepository payWaveRepository, DemoQRApiService demoQRApiService, KPayApiService kPayApiService, KPayRefundApiService kPayRefundApiService) {
+ public Repository(PayDetailDao payDetailDao, SiriusApiService siriusApiService, EmvDetailDao emvDetailDao, PayWaveRepository payWaveRepository, DemoQRApiService demoQRApiService, KPayApiService kPayApiService, KPayRefundApiService kPayRefundApiService, EReceiptApiService eReceiptApiService) {
this.payDetailDao = payDetailDao;
this.siriusApiService = siriusApiService;
this.emvDetailDao = emvDetailDao;
@@ -66,6 +72,7 @@ public class Repository {
this.demoQRApiService = demoQRApiService;
this.kPayApiService = kPayApiService;
this.kPayRefundApiService = kPayRefundApiService;
+ this.eReceiptApiService = eReceiptApiService;
}
public Observable qrGenerate(KPayQRRequest.QrRequest request) {
@@ -98,9 +105,14 @@ public class Repository {
public Observable getParams(SiriusRequest siriusRequest) {
return siriusApiService.getParams(siriusRequest);
}
-
-
-
+ public Observable sendReceipt(Object body){
+ String apiSecret = "8f4df38d1001bcc4620b5c736c66a03eef4653eb3ba31105faa2f2ee294c4a46";
+ String timestamp = String.valueOf(System.currentTimeMillis());
+ String bodyString = new Gson().toJson(body);
+ String dataToHash = bodyString + apiSecret + timestamp;
+ String signature = EReceiptHelper.sha256(dataToHash);
+ return eReceiptApiService.sendReceipt(timestamp, signature, body);
+ }
public void insertPayDetail(PayDetail payDetail){ payDetailDao.insert(payDetail);}
diff --git a/baselib/src/main/java/com/utsmyanmar/baselib/util/EReceiptHelper.java b/baselib/src/main/java/com/utsmyanmar/baselib/util/EReceiptHelper.java
new file mode 100644
index 0000000..90a992c
--- /dev/null
+++ b/baselib/src/main/java/com/utsmyanmar/baselib/util/EReceiptHelper.java
@@ -0,0 +1,48 @@
+package com.utsmyanmar.baselib.util;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+
+public class EReceiptHelper {
+ public static String hmacSha256(String key, String data) {
+ try {
+ Mac mac = Mac.getInstance("HmacSHA256");
+ SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), "HmacSHA256");
+ mac.init(secretKey);
+
+ byte[] hash = mac.doFinal(data.getBytes());
+
+ StringBuilder hex = new StringBuilder();
+ for (byte b : hash) {
+ hex.append(String.format("%02x", b));
+ }
+ return hex.toString();
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public static String sha256(String input) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("SHA-256");
+ byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
+ StringBuilder hexString = new StringBuilder();
+
+ for (byte b : hash) {
+ String hex = Integer.toHexString(0xff & b);
+ if (hex.length() == 1) hexString.append('0');
+ hexString.append(hex);
+ }
+
+ return hexString.toString();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}