add expire time on QR
This commit is contained in:
parent
7d894116dd
commit
7452443a45
@ -14,8 +14,8 @@ android {
|
|||||||
applicationId "com.utsmm.kbz"
|
applicationId "com.utsmm.kbz"
|
||||||
minSdk 24
|
minSdk 24
|
||||||
targetSdk 33
|
targetSdk 33
|
||||||
versionCode 1
|
versionCode 2
|
||||||
versionName "1.0"
|
versionName "1.01"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
BIN
app/sit/release/baselineProfiles/0/app-sit-release.dm
Normal file
BIN
app/sit/release/baselineProfiles/0/app-sit-release.dm
Normal file
Binary file not shown.
BIN
app/sit/release/baselineProfiles/1/app-sit-release.dm
Normal file
BIN
app/sit/release/baselineProfiles/1/app-sit-release.dm
Normal file
Binary file not shown.
37
app/sit/release/output-metadata.json
Normal file
37
app/sit/release/output-metadata.json
Normal 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
|
||||||
|
}
|
||||||
@ -42,8 +42,11 @@ import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsSettings;
|
|||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.ExecutorService;
|
import java.util.concurrent.ExecutorService;
|
||||||
import java.util.concurrent.Executors;
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@ -190,10 +193,37 @@ public class KPayViewModel extends ViewModel {
|
|||||||
return createQR(amount, String.valueOf(System.currentTimeMillis()),mid);
|
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 1–120
|
||||||
|
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) {
|
public KPayQRRequest.QrRequest createQR(String amount, String time,String mid) {
|
||||||
String merchOrderId = "NEX"+SystemParamsOperation.getInstance().getCurrentSerialNum()+generateRandomTwoChars();
|
String merchOrderId = "NEX"+SystemParamsOperation.getInstance().getCurrentSerialNum()+generateRandomTwoChars();
|
||||||
String serialNum = TerminalUtil.getInstance().getSerialNo();
|
String serialNum = TerminalUtil.getInstance().getSerialNo();
|
||||||
String nonceStr = generateNonceStr(); // Generate random nonce_str
|
String nonceStr = generateNonceStr(); // Generate random nonce_str
|
||||||
|
calculateTimeoutMinutes();
|
||||||
|
String timeoutExpress = expireTime + "m";
|
||||||
|
|
||||||
Map<String, Object> bizContent = new HashMap<>();
|
Map<String, Object> bizContent = new HashMap<>();
|
||||||
bizContent.put("merch_order_id", merchOrderId);
|
bizContent.put("merch_order_id", merchOrderId);
|
||||||
@ -203,7 +233,7 @@ public class KPayViewModel extends ViewModel {
|
|||||||
bizContent.put("total_amount", amount);
|
bizContent.put("total_amount", amount);
|
||||||
bizContent.put("title", "testing");
|
bizContent.put("title", "testing");
|
||||||
// bizContent.put("operator_id", serialNum);
|
// bizContent.put("operator_id", serialNum);
|
||||||
bizContent.put("timeout_express", "100m");
|
bizContent.put("timeout_express", timeoutExpress);
|
||||||
bizContent.put("trans_currency", "MMK");
|
bizContent.put("trans_currency", "MMK");
|
||||||
bizContent.put("callback_info", "callback");
|
bizContent.put("callback_info", "callback");
|
||||||
|
|
||||||
@ -226,7 +256,7 @@ public class KPayViewModel extends ViewModel {
|
|||||||
"testing",
|
"testing",
|
||||||
amount,
|
amount,
|
||||||
"MMK",
|
"MMK",
|
||||||
"100m",
|
timeoutExpress,
|
||||||
"callback"
|
"callback"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,7 @@ public class QRPayFragment extends DataBindingFragment {
|
|||||||
List<QRPayItem> features = new ArrayList<>();
|
List<QRPayItem> features = new ArrayList<>();
|
||||||
features.add(new QRPayItem("Sale", R.drawable.ic_qr_pay, true));
|
features.add(new QRPayItem("Sale", R.drawable.ic_qr_pay, true));
|
||||||
if(isQrRefundEnable){
|
if(isQrRefundEnable){
|
||||||
features.add(new QRPayItem("Refund", R.drawable.ic_refund, false));
|
features.add(new QRPayItem("Refund", R.drawable.ic_refund, true));
|
||||||
}
|
}
|
||||||
features.add(new QRPayItem("History", R.drawable.ic_history, true));
|
features.add(new QRPayItem("History", R.drawable.ic_history, true));
|
||||||
|
|
||||||
|
|||||||
@ -6,34 +6,89 @@ import com.utsmyanmar.paylibs.utils.LogUtil;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
|
||||||
import okhttp3.OkHttp;
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
|
||||||
|
import io.reactivex.rxjava3.core.Observable;
|
||||||
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
import okhttp3.Response;
|
import okhttp3.Response;
|
||||||
|
|
||||||
public class DownloadUtil {
|
public class DownloadUtil {
|
||||||
|
|
||||||
final static String TAG = DownloadUtil.class.getSimpleName();
|
private static final String TAG = DownloadUtil.class.getSimpleName();
|
||||||
private void downloadFile(String url){
|
|
||||||
try{
|
// ==============================
|
||||||
OkHttpClient okHttpClient = new OkHttpClient();
|
// CALLBACK INTERFACE
|
||||||
|
// ==============================
|
||||||
|
public interface DownloadCallback {
|
||||||
|
void onDownloadSuccess(String path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
// RX ASYNC DOWNLOAD METHOD
|
||||||
|
// ==============================
|
||||||
|
public static void downloadCertificateRx(String url,
|
||||||
|
String dynamicFilename,
|
||||||
|
DownloadCallback callback) {
|
||||||
|
|
||||||
|
Observable.fromCallable(() -> downloadCert(url, dynamicFilename))
|
||||||
|
.subscribeOn(Schedulers.io()) // download on background thread
|
||||||
|
.observeOn(AndroidSchedulers.mainThread()) // callback on main thread
|
||||||
|
.subscribe(path -> {
|
||||||
|
if (path != null) {
|
||||||
|
LogUtil.d(TAG, "Certificate saved at: " + path);
|
||||||
|
if (callback != null) callback.onDownloadSuccess(path);
|
||||||
|
} else {
|
||||||
|
LogUtil.e(TAG, "Certificate download failed.");
|
||||||
|
if (callback != null) callback.onDownloadSuccess(null);
|
||||||
|
}
|
||||||
|
}, error -> {
|
||||||
|
error.printStackTrace();
|
||||||
|
if (callback != null) callback.onDownloadSuccess(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
// ACTUAL DOWNLOAD LOGIC
|
||||||
|
// ==============================
|
||||||
|
public static String downloadCert(String url, String dynamicFilename) {
|
||||||
|
try {
|
||||||
|
OkHttpClient client = new OkHttpClient();
|
||||||
Request request = new Request.Builder().url(url).build();
|
Request request = new Request.Builder().url(url).build();
|
||||||
Response response = okHttpClient.newCall(request).execute();
|
|
||||||
|
|
||||||
if(!response.isSuccessful()){
|
Response response = client.newCall(request).execute();
|
||||||
LogUtil.e(TAG, "file download failed");
|
|
||||||
return;
|
if (!response.isSuccessful()) {
|
||||||
|
LogUtil.e(TAG, "Download failed: " + response.code());
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
byte[] bytes = response.body().bytes();
|
|
||||||
saveFile("cert_file.ctr", bytes);
|
|
||||||
LogUtil.d(TAG, "file saved successfully.");
|
|
||||||
}catch (Exception e){
|
|
||||||
|
|
||||||
|
// Detect extension (MIME or URL fallback)
|
||||||
|
String contentType = response.header("Content-Type", "");
|
||||||
|
String ext = getExtensionFromContentType(contentType);
|
||||||
|
|
||||||
|
if (ext.isEmpty()) ext = getExtensionFromUrl(url);
|
||||||
|
if (ext.isEmpty()) ext = ".bin"; // final fallback
|
||||||
|
|
||||||
|
// build dynamic filename
|
||||||
|
String filename = dynamicFilename + ext;
|
||||||
|
|
||||||
|
byte[] data = response.body().bytes();
|
||||||
|
String savedPath = saveFile(filename, data);
|
||||||
|
|
||||||
|
return savedPath;
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveFile(String filename, byte[] data){
|
// ==============================
|
||||||
try{
|
// SAVE FILE TO INTERNAL STORAGE
|
||||||
|
// ==============================
|
||||||
|
private static String saveFile(String filename, byte[] data) {
|
||||||
|
try {
|
||||||
File dir = MyApplication.getInstance().getFilesDir();
|
File dir = MyApplication.getInstance().getFilesDir();
|
||||||
File file = new File(dir, filename);
|
File file = new File(dir, filename);
|
||||||
|
|
||||||
@ -42,9 +97,42 @@ public class DownloadUtil {
|
|||||||
fos.flush();
|
fos.flush();
|
||||||
fos.close();
|
fos.close();
|
||||||
|
|
||||||
LogUtil.d(TAG, "Saved file at => " + file.getAbsolutePath());
|
return file.getAbsolutePath();
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
// MIME TYPE → 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 "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==============================
|
||||||
|
// URL EXTENSION PARSER
|
||||||
|
// ==============================
|
||||||
|
private static String getExtensionFromUrl(String url) {
|
||||||
|
if (url == null) return "";
|
||||||
|
int lastDot = url.lastIndexOf('.');
|
||||||
|
if (lastDot == -1) return "";
|
||||||
|
return url.substring(lastDot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import android.content.pm.PackageInfo;
|
|||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.utsmm.kbz.util.DownloadUtil;
|
||||||
import com.utsmyanmar.baselib.emv.EmvParamOperation;
|
import com.utsmyanmar.baselib.emv.EmvParamOperation;
|
||||||
import com.utsmyanmar.baselib.network.model.sirius.SiriusHost;
|
import com.utsmyanmar.baselib.network.model.sirius.SiriusHost;
|
||||||
import com.utsmyanmar.baselib.network.model.sirius.SiriusMerchant;
|
import com.utsmyanmar.baselib.network.model.sirius.SiriusMerchant;
|
||||||
@ -608,6 +609,17 @@ public class TMSSetupsImpl implements TMSSetups{
|
|||||||
SystemParamsOperation.getInstance().setQrRefundEnable(parseBoolean(data));
|
SystemParamsOperation.getInstance().setQrRefundEnable(parseBoolean(data));
|
||||||
} else if (TextUtils.equals(name, "tpdu_value")){
|
} else if (TextUtils.equals(name, "tpdu_value")){
|
||||||
SystemParamsOperation.getInstance().setTpduValue(data);
|
SystemParamsOperation.getInstance().setTpduValue(data);
|
||||||
|
} else if (TextUtils.equals(name, "certificate_file")){
|
||||||
|
String tmsAddress = SystemParamsOperation.getInstance().getTmsAddress();
|
||||||
|
String url = tmsAddress+"/file/download?filePath="+data;
|
||||||
|
DownloadUtil.downloadCertificateRx(url, "certificate_file", path -> {
|
||||||
|
if(path != null){
|
||||||
|
SystemParamsOperation.getInstance().setCertFilePath(path);
|
||||||
|
LogUtil.d(TAG, "Cert file path saved in SystemParams => " + path);
|
||||||
|
}else{
|
||||||
|
LogUtil.e(TAG, "Failed to download certificate file");
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -285,8 +285,8 @@ public class NetworkModule {
|
|||||||
tmsAddress = getTMSUrlFromNative();
|
tmsAddress = getTMSUrlFromNative();
|
||||||
}
|
}
|
||||||
|
|
||||||
String baseUrl = tmsAddress.trim() + "/api/v1/";
|
// String baseUrl = tmsAddress.trim() + "/api/v1/";
|
||||||
// String baseUrl = tmsAddress.trim() + "/";
|
String baseUrl = tmsAddress.trim() + "/";
|
||||||
|
|
||||||
final Gson gson =
|
final Gson gson =
|
||||||
new GsonBuilder().create();
|
new GsonBuilder().create();
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
i/nexgo-sdk-dlkey-1.0.3-runtime_dex
|
||||||
@ -0,0 +1 @@
|
|||||||
|
i/jars/classes.jar
|
||||||
@ -0,0 +1 @@
|
|||||||
|
o/nexgo-sdk-dlkey-1.0.3-runtime
|
||||||
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
i/nexgo-sdk-dlkey-1.0.3-runtime_global-synthetics
|
||||||
@ -1605,4 +1605,15 @@ public class SystemParamsOperation {
|
|||||||
SystemParamsSettings params = getSystemParamsSettings();
|
SystemParamsSettings params = getSystemParamsSettings();
|
||||||
return params.getQrRefundEnable();
|
return params.getQrRefundEnable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCertFilePath(String path) {
|
||||||
|
SystemParamsSettings params = getSystemParamsSettings();
|
||||||
|
params.setCertFilePath(path);
|
||||||
|
saveSystemParamsSettings(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCertFilePath(){
|
||||||
|
SystemParamsSettings params = getSystemParamsSettings();
|
||||||
|
return params.getCertFilePath();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -42,8 +42,8 @@ public class SystemParamsSettings implements Serializable {
|
|||||||
|
|
||||||
// private String tmsAddress = "https://tms.smile-mm.com";
|
// private String tmsAddress = "https://tms.smile-mm.com";
|
||||||
// private String tmsAddress = "http://128.199.170.203";
|
// private String tmsAddress = "http://128.199.170.203";
|
||||||
private String tmsAddress = "http://sirius-nest.utsmyanmar.com";
|
// private String tmsAddress = "http://sirius-nest.utsmyanmar.com";
|
||||||
// private String tmsAddress = "https://api-tms-uat.kbzbank.com:8443/sirius";
|
private String tmsAddress = "https://api-tms-uat.kbzbank.com:8443/sirius";
|
||||||
private String ereceiptAddress = "http://receipt-nest.utsmyanmar.com";
|
private String ereceiptAddress = "http://receipt-nest.utsmyanmar.com";
|
||||||
|
|
||||||
private String terminalCapability = "E0E8C8";
|
private String terminalCapability = "E0E8C8";
|
||||||
@ -242,6 +242,7 @@ public class SystemParamsSettings implements Serializable {
|
|||||||
|
|
||||||
private boolean qrDecimalEnable = false;
|
private boolean qrDecimalEnable = false;
|
||||||
private boolean qrRefundEnable = false;
|
private boolean qrRefundEnable = false;
|
||||||
|
private String certFilePath = "";
|
||||||
|
|
||||||
public boolean isQrPartialRefundEnable(){
|
public boolean isQrPartialRefundEnable(){
|
||||||
return qrPartialRefundEnable;
|
return qrPartialRefundEnable;
|
||||||
@ -961,6 +962,14 @@ public class SystemParamsSettings implements Serializable {
|
|||||||
return qrRefundEnable;
|
return qrRefundEnable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setCertFilePath(String path) {
|
||||||
|
this.certFilePath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCertFilePath() {
|
||||||
|
return certFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
/* // 流水号起始
|
/* // 流水号起始
|
||||||
private String serialNum = Configs.getInstance().SERIAL_NUM();
|
private String serialNum = Configs.getInstance().SERIAL_NUM();
|
||||||
// 批次号起始
|
// 批次号起始
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user