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); + } + } + +}