Compare commits

..

18 Commits

Author SHA1 Message Date
moon
cdb7bb73c5 Merge branch 'ecr' into duel_settlement 2026-03-29 22:45:25 +06:30
moon
4f28f7a118 Update InjectKeyFragment.java 2026-03-29 22:43:15 +06:30
890b1c55a8 fixed sending multiple transaction if there has reversal 2026-03-26 17:23:23 +07:00
01043dbbca added auto reversal 2026-03-26 16:04:14 +07:00
c503b95027 void fixing 2026-03-26 10:38:18 +07:00
e10e10a793 void fixed 2026-03-25 16:48:54 +07:00
2cdfc7c34f pre auth cancel fixed 2026-03-25 12:20:25 +07:00
moon
99b9f4835c UPI fix for certification 2026-03-24 19:19:22 +06:30
dd265c1fa8 auto settlement completed 2026-03-16 18:00:02 +07:00
moon
b5f174ff54 fixed for upi 2026-03-13 16:04:00 +06:30
87a3b5da83 edited threshold value 2026-03-13 14:09:52 +07:00
moon
ef74f2cc82 toast for wrong password 2026-03-12 16:46:56 +06:30
moon
3e4b3e88a4 Merge branch 'ecr' of https://hub.utsmyanmar.com/Kyaw_Min_Khant/KBZ-POS into ecr 2026-03-12 14:58:04 +06:30
e60985b2ec fixed for pinpad retry 2026-03-12 15:23:45 +07:00
moon
8173e0fcfe mag fix 2026-03-12 14:33:14 +06:30
ffc3908446 fixed for mag stripe 2026-03-09 14:31:15 +07:00
05a91782b5 Merge remote-tracking branch 'origin/ecr' into ecr 2026-03-09 13:03:22 +07:00
898c8edea4 fixed for de 61 SF 11 2026-03-09 13:03:15 +07:00
34 changed files with 787 additions and 401 deletions

View File

@ -13,7 +13,6 @@
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/baselib" /> <option value="$PROJECT_DIR$/baselib" />
<option value="$PROJECT_DIR$/ecr" /> <option value="$PROJECT_DIR$/ecr" />
<option value="$PROJECT_DIR$/ecr-service" />
<option value="$PROJECT_DIR$/ecr-service-lib" /> <option value="$PROJECT_DIR$/ecr-service-lib" />
<option value="$PROJECT_DIR$/link-service-lib" /> <option value="$PROJECT_DIR$/link-service-lib" />
<option value="$PROJECT_DIR$/mpulib" /> <option value="$PROJECT_DIR$/mpulib" />

View File

@ -204,7 +204,7 @@ dependencies {
// ECR Dependencies - Modern ECR Client Library // ECR Dependencies - Modern ECR Client Library
// implementation project(path: ':ecr-client-lib') // implementation project(path: ':ecr-client-lib')
implementation project(path: ':ecr-service-lib') // implementation project(path: ':ecr-service-lib')
// Core Libraries // Core Libraries
implementation project(path: ':paylibs') implementation project(path: ':paylibs')

View File

@ -4,6 +4,7 @@ import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil; import androidx.databinding.DataBindingUtil;
import androidx.drawerlayout.widget.DrawerLayout; import androidx.drawerlayout.widget.DrawerLayout;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.NavController; import androidx.navigation.NavController;
import androidx.navigation.NavDestination; import androidx.navigation.NavDestination;
@ -472,27 +473,59 @@ public class MainActivity extends AppCompatActivity implements
private void handleAutoSettlementIntent(Intent intent) { private void handleAutoSettlementIntent(Intent intent) {
if (intent == null) return; if (intent == null) return;
// Handle regular auto settlement boolean hasPOS = intent.getBooleanExtra("AUTO_SETTLEMENT", false);
boolean auto = intent.getBooleanExtra("AUTO_SETTLEMENT", false); boolean hasQR = intent.getBooleanExtra("AUTO_QR_SETTLEMENT", false);
if (auto) {
if (hasPOS) {
PayDetail payDetail = (PayDetail) intent.getSerializableExtra("EXTRA_PAY_DETAIL"); PayDetail payDetail = (PayDetail) intent.getSerializableExtra("EXTRA_PAY_DETAIL");
if (payDetail != null) { if (payDetail != null) {
sharedViewModel.payDetail.setValue(payDetail); sharedViewModel.payDetail.setValue(payDetail);
sharedViewModel.transactionsType.setValue(TransactionsType.SETTLEMENT); sharedViewModel.transactionsType.setValue(TransactionsType.SETTLEMENT);
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(payDetail.getAmount())); sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(payDetail.getAmount()));
try { try {
navController.navigate(R.id.transactionResultFragment); navController.navigate(R.id.transactionResultFragment);
} catch (Exception e) { } catch (Exception e) {
LogUtil.e(TAG, "Navigation error: " + e.getMessage()); LogUtil.e(TAG, "Navigation error: " + e.getMessage());
} }
// If QR also exists, trigger it AFTER POS result is done
if (hasQR) {
navigateToQRSettlementAfterPOS(intent);
}
} else {
// POS had no data, go straight to QR if available
if (hasQR) {
handleQRSettlement(intent);
} }
return;
} }
// Handle QR auto settlement } else if (hasQR) {
boolean autoQR = intent.getBooleanExtra("AUTO_QR_SETTLEMENT", false); // Only QR settlement, no POS
if (autoQR) { handleQRSettlement(intent);
}
}
private void navigateToQRSettlementAfterPOS(Intent intent) {
// Observe transactionResultFragment's completion via ViewModel
// When POS result screen signals "done" (print complete / user dismissed),
// then navigate to QR result
sharedViewModel.onSettlementResultDone.observe(this, new Observer<Boolean>() {
@Override
public void onChanged(Boolean done) {
if (done != null && done) {
// Remove observer so it only fires once
sharedViewModel.onSettlementResultDone.removeObserver(this);
// Reset flag
sharedViewModel.onSettlementResultDone.postValue(false);
// Now navigate to QR
handleQRSettlement(intent);
}
}
});
}
private void handleQRSettlement(Intent intent) {
int qrSaleCount = intent.getIntExtra("QR_SALE_COUNT", 0); int qrSaleCount = intent.getIntExtra("QR_SALE_COUNT", 0);
long qrSaleAmount = intent.getLongExtra("QR_SALE_AMOUNT", 0L); long qrSaleAmount = intent.getLongExtra("QR_SALE_AMOUNT", 0L);
int qrRefundCount = intent.getIntExtra("QR_REFUND_COUNT", 0); int qrRefundCount = intent.getIntExtra("QR_REFUND_COUNT", 0);
@ -500,7 +533,6 @@ public class MainActivity extends AppCompatActivity implements
long totalAmount = intent.getLongExtra("QR_TOTAL_AMOUNT", 0L); long totalAmount = intent.getLongExtra("QR_TOTAL_AMOUNT", 0L);
List<PayDetail> qrTransList = (List<PayDetail>) intent.getSerializableExtra("QR_TRANS_LIST"); List<PayDetail> qrTransList = (List<PayDetail>) intent.getSerializableExtra("QR_TRANS_LIST");
// Create QR settlement PayDetail
SettleData settleData = new SettleData( SettleData settleData = new SettleData(
qrSaleCount, qrSaleAmount, 0, 0L, qrRefundCount, qrRefundAmount, 0, 0L); qrSaleCount, qrSaleAmount, 0, 0L, qrRefundCount, qrRefundAmount, 0, 0L);
@ -512,7 +544,6 @@ public class MainActivity extends AppCompatActivity implements
payDetail.setAmount(totalAmount); payDetail.setAmount(totalAmount);
payDetail.setTradeAnswerCode("000"); payDetail.setTradeAnswerCode("000");
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(totalAmount)); sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(totalAmount));
sharedViewModel.payDetails.setValue(qrTransList); sharedViewModel.payDetails.setValue(qrTransList);
sharedViewModel.payDetail.setValue(payDetail); sharedViewModel.payDetail.setValue(payDetail);
@ -524,7 +555,6 @@ public class MainActivity extends AppCompatActivity implements
LogUtil.e(TAG, "QR Auto Settlement navigation error: " + e.getMessage()); LogUtil.e(TAG, "QR Auto Settlement navigation error: " + e.getMessage());
} }
} }
}
@Override @Override
public void onDestroy() { public void onDestroy() {

View File

@ -29,9 +29,11 @@ import com.denzcoskun.imageslider.constants.ScaleTypes;
import com.denzcoskun.imageslider.models.SlideModel; import com.denzcoskun.imageslider.models.SlideModel;
import com.nexgo.oaf.apiv3.emv.AidEntity; import com.nexgo.oaf.apiv3.emv.AidEntity;
import com.nexgo.oaf.apiv3.emv.CapkEntity; import com.nexgo.oaf.apiv3.emv.CapkEntity;
import com.pos.connection.bridge.binder.ECRConstant; //import com.pos.connection.bridge.binder.ECRConstant;
import com.utsmm.kbz.util.MockData; import com.utsmm.kbz.util.MockData;
//import com.utsmm.kbz.util.ecr.ModernECRFactory;
//import com.utsmm.kbz.util.ecr.ModernECRManager;
import com.utsmyanmar.baselib.BaseApplication; import com.utsmyanmar.baselib.BaseApplication;
import com.utsmyanmar.baselib.emv.EmvParamOperation; import com.utsmyanmar.baselib.emv.EmvParamOperation;
import com.utsmyanmar.baselib.fragment.DataBindingFragment; import com.utsmyanmar.baselib.fragment.DataBindingFragment;
@ -316,8 +318,8 @@ public class MainFragment extends DataBindingFragment {
if (checkECRServiceAppExistOrNot()) { if (checkECRServiceAppExistOrNot()) {
// Initialize Modern ECR Manager // Initialize Modern ECR Manager
// modernECRManager.init(); // modernECRManager.init();
// ////
// // Observe navigation requests //// // Observe navigation requests
// modernECRManager.getNavigationRequest().observe(getViewLifecycleOwner(), destinationId -> { // modernECRManager.getNavigationRequest().observe(getViewLifecycleOwner(), destinationId -> {
// if (destinationId != null) { // if (destinationId != null) {
// delayFunctionCall(() -> isRouteValidAndNavigateToRoute(destinationId)); // delayFunctionCall(() -> isRouteValidAndNavigateToRoute(destinationId));

View File

@ -20,6 +20,7 @@ import com.google.gson.Gson;
import com.utsmm.kbz.MainActivity; import com.utsmm.kbz.MainActivity;
import com.utsmm.kbz.util.EReceiptUtil; import com.utsmm.kbz.util.EReceiptUtil;
import com.utsmm.kbz.util.enums.TransactionStatus;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest; import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.repo.Repository; import com.utsmyanmar.baselib.repo.Repository;
import com.utsmm.kbz.BuildConfig; import com.utsmm.kbz.BuildConfig;
@ -34,6 +35,8 @@ import io.reactivex.rxjava3.schedulers.Schedulers;
import retrofit2.HttpException; import retrofit2.HttpException;
import com.utsmyanmar.paylibs.Constant; import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.batch_upload.BatchListener;
import com.utsmyanmar.paylibs.batch_upload.BatchUploadProcess;
import com.utsmyanmar.paylibs.isobuilder.ISOMode; import com.utsmyanmar.paylibs.isobuilder.ISOMode;
import com.utsmyanmar.paylibs.isobuilder.builderx.ISOMsgX; import com.utsmyanmar.paylibs.isobuilder.builderx.ISOMsgX;
import com.utsmyanmar.paylibs.isobuilder.builderx.ISOVersion; import com.utsmyanmar.paylibs.isobuilder.builderx.ISOVersion;
@ -44,6 +47,8 @@ import com.utsmyanmar.paylibs.model.SettleData;
import com.utsmyanmar.paylibs.model.TradeData; import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.network.ISOCallback; import com.utsmyanmar.paylibs.network.ISOCallback;
import com.utsmyanmar.paylibs.network.ISOSocket; import com.utsmyanmar.paylibs.network.ISOSocket;
import com.utsmyanmar.paylibs.sign_on.EchoTestProcess;
import com.utsmyanmar.paylibs.sign_on.SignOnListener;
import com.utsmyanmar.paylibs.utils.LogUtil; import com.utsmyanmar.paylibs.utils.LogUtil;
import com.utsmyanmar.paylibs.utils.MessageType; import com.utsmyanmar.paylibs.utils.MessageType;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
@ -74,14 +79,25 @@ public class AutoSettleService extends Service {
private boolean regularSettlementCompleted = false; private boolean regularSettlementCompleted = false;
private boolean qrSettlementCompleted = false; private boolean qrSettlementCompleted = false;
// Observers to keep reference for cleanup private boolean posHasData = false; // true = POS actually ran and has result
private Observer<java.util.List<com.utsmyanmar.paylibs.model.PayDetail>> regularSettlementObserver; private boolean qrHasData = false; // true = QR actually ran and has result
private Observer<java.util.List<com.utsmyanmar.paylibs.model.PayDetail>> qrSettlementObserver;
// Observers to keep reference for cleanup
private Observer<List<PayDetail>> regularSettlementObserver;
private Observer<List<PayDetail>> qrSettlementObserver;
private int i = 0;
private boolean flag = false;
@Inject @Inject
Repository repository; Repository repository;
private PayDetail pendingPayDetail = null;
private Bundle pendingQrData = null;
private boolean posSettlementReady = false;
private boolean qrSettlementReady = false;
ArrayList<PayDetail> payDetails = new ArrayList<>();
public static final String NOTIFICATION_CHANNEL_ID = "10001"; public static final String NOTIFICATION_CHANNEL_ID = "10001";
private final static String default_notification_channel_id = "default"; private final static String default_notification_channel_id = "default";
@ -188,6 +204,10 @@ public class AutoSettleService extends Service {
if (regularSettlementCompleted) { if (regularSettlementCompleted) {
return; return;
} }
payDetails.clear();
payDetails.addAll(list);
regularSettlementCompleted = true; regularSettlementCompleted = true;
repository.getSettlementPOS().removeObserver(this); repository.getSettlementPOS().removeObserver(this);
@ -225,7 +245,13 @@ public class AutoSettleService extends Service {
String bitmap = BitmapConfig.BPC_SETTLEMENT; String bitmap = BitmapConfig.BPC_SETTLEMENT;
payDetail.setTransType(TransactionsType.SETTLEMENT.name); payDetail.setTransType(TransactionsType.SETTLEMENT.name);
payDetail.setTransactionType(TransactionType.SETTLEMENT); payDetail.setTransactionType(TransactionType.SETTLEMENT);
if(!flag) {
payDetail.setProcessCode(TransactionsType.SETTLEMENT.processCode); payDetail.setProcessCode(TransactionsType.SETTLEMENT.processCode);
} else {
bitmap = BitmapConfig.BPC_SETTLEMENT_TRAILER;
payDetail.setProcessCode("910000");
}
payDetail.setBatchNo(SystemParamsOperation.getInstance().getCurrentBatchNum()); payDetail.setBatchNo(SystemParamsOperation.getInstance().getCurrentBatchNum());
SettleData settleData = new SettleData( SettleData settleData = new SettleData(
@ -245,6 +271,14 @@ public class AutoSettleService extends Service {
} else { } else {
settlementData = "C" + String.format(Locale.getDefault(), "%012d", totalAmount); settlementData = "C" + String.format(Locale.getDefault(), "%012d", totalAmount);
} }
if(totalAmount == 0 && (saleCount == 0 || preCount == 0 || refundCount == 0 || caCount == 0)) {
posSettlementReady = true;
posHasData = false;
checkAndLaunch();
checkIfBothSettlementsComplete();
return;
}
payDetail.setSettleData(settlementData); payDetail.setSettleData(settlementData);
payDetail.setAmount(totalAmount); payDetail.setAmount(totalAmount);
@ -269,7 +303,7 @@ public class AutoSettleService extends Service {
if (TextUtils.equals(resultStr, Constant.ANSWER_CODE_ACCEPT) || TextUtils.equals(resultStr, Constant.ANSWER_CODE_APPROVED)) { if (TextUtils.equals(resultStr, Constant.ANSWER_CODE_ACCEPT) || TextUtils.equals(resultStr, Constant.ANSWER_CODE_APPROVED)) {
payDetail.setIsNeedReversal(false); payDetail.setIsNeedReversal(false);
} else if (TextUtils.equals(resultStr, "95") || TextUtils.equals(resultStr, "095")) { } else if (TextUtils.equals(resultStr, "95") || TextUtils.equals(resultStr, "095")) {
payDetail.setIsNeedReversal(true); payDetail.setIsNeedReversal(!flag);
} }
} }
} }
@ -284,34 +318,25 @@ public class AutoSettleService extends Service {
public void onComplete() { public void onComplete() {
LogUtil.d(TAG, "Auto settlement transaction completed successfully"); LogUtil.d(TAG, "Auto settlement transaction completed successfully");
if (list != null && !list.isEmpty()) { if(payDetail.getIsNeedReversal()) {
flag = true;
batchUploadProcess();
} else {
flag = false;
if (!list.isEmpty()) {
for (PayDetail p : list) { for (PayDetail p : list) {
repository.deletePayDetail(p); repository.deletePayDetail(p);
} }
} }
repository.insertPayDetail(payDetail); repository.insertPayDetail(payDetail);
try { networkCutOver(payDetail);
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();
}
}); });
} }
}; };
@ -319,6 +344,41 @@ public class AutoSettleService extends Service {
repository.getSettlementPOS().observeForever(regularSettlementObserver); repository.getSettlementPOS().observeForever(regularSettlementObserver);
} }
private void batchUploadProcess() {
if(payDetails == null || payDetails.isEmpty()){
regularSettlementCompleted = false;
performSettlement();
return;
}
PayDetail payDetail = payDetails.get(i);
TradeData tradeData = new TradeData();
tradeData.setPayDetail(payDetail);
BatchUploadProcess.getInstance().enqueue(tradeData).startBatchUpload(new BatchListener() {
@Override
public void onSuccessBatch() {
if (i < payDetails.size() - 1) {
LogUtil.d(TAG, "Pay detail Size:" + payDetails.size());
LogUtil.d(TAG, "Count value:" + i);
i++;
batchUploadProcess();
} else {
regularSettlementCompleted = false;
performSettlement();
}
LogUtil.e(TAG, "Batch Upload Success");
}
@Override
public void onFailBatch() {
LogUtil.e(TAG, "Batch Upload Fail");
}
});
}
private void performQRSettlement() { private void performQRSettlement() {
if (qrSettlementCompleted) { if (qrSettlementCompleted) {
return; return;
@ -365,6 +425,9 @@ public class AutoSettleService extends Service {
} }
} catch (IllegalStateException e) { } catch (IllegalStateException e) {
LogUtil.e(TAG, "QR Auto Settlement: Database cursor error - likely due to large data size: " + e); LogUtil.e(TAG, "QR Auto Settlement: Database cursor error - likely due to large data size: " + e);
qrSettlementReady = true;
qrHasData = false;
checkAndLaunch();
checkIfBothSettlementsComplete(); checkIfBothSettlementsComplete();
return; return;
} }
@ -422,19 +485,24 @@ public class AutoSettleService extends Service {
qrData.putLong("QR_TOTAL_AMOUNT", totalAmount); qrData.putLong("QR_TOTAL_AMOUNT", totalAmount);
qrData.putSerializable("QR_TRANS_LIST", qrTransactionsList); qrData.putSerializable("QR_TRANS_LIST", qrTransactionsList);
// Use notification-based approach to reliably launch the app // Use notification-based approach to reliably launch the app
launchAppWithSettlementResult("AUTO_QR_SETTLEMENT", null, qrData); pendingQrData = qrData;
qrHasData = true;
// launchAppWithSettlementResult("AUTO_QR_SETTLEMENT", null, qrData,false);
} catch (Exception e) { } catch (Exception e) {
LogUtil.e(TAG, "Error launching app for QR settlement: " + e.getMessage()); LogUtil.e(TAG, "Error launching app for QR settlement: " + e.getMessage());
qrHasData = false;
e.printStackTrace(); e.printStackTrace();
} }
LogUtil.d(TAG, "QR Auto Settlement completed successfully"); LogUtil.d(TAG, "QR Auto Settlement completed successfully");
} else { } else {
LogUtil.d(TAG, "No QR transactions found for auto settlement"); LogUtil.d(TAG, "No QR transactions found for auto settlement");
qrHasData = false;
} }
} }
qrSettlementReady = true;
checkAndLaunch();
checkIfBothSettlementsComplete(); checkIfBothSettlementsComplete();
} }
}; };
@ -480,19 +548,75 @@ public class AutoSettleService extends Service {
} }
private void launchAppWithSettlementResult(String settlementType, private void networkCutOver(PayDetail payDetail) {
PayDetail payDetail, EchoTestProcess.getInstance().enqueueCutOver().startSignOn(new SignOnListener() {
Bundle qrData) { @Override
public void onSuccessSignOn() {
pendingPayDetail = payDetail;
posHasData = true;
posSettlementReady = true;
checkAndLaunch();
checkIfBothSettlementsComplete();
}
@Override
public void onFailureSignOn(Integer resultCode) {
LogUtil.d(TAG,"Failure Cut Over message: "+resultCode);
// POS done but cutover failed still mark ready
posSettlementReady = true;
posHasData = false;
checkAndLaunch();
checkIfBothSettlementsComplete();
}
@Override
public void onNetworkFailSignOn(String message) {
LogUtil.d(TAG,"Network Fail Cut Over message: "+message);
posSettlementReady = true;
posHasData = false;
checkAndLaunch();
checkIfBothSettlementsComplete();
}
});
}
private void checkAndLaunch() {
// !!!! need to add flag, if don't want both at once
if (!posSettlementReady || !qrSettlementReady) {
LogUtil.d(TAG, "Waiting for both settlements... POS=" + posSettlementReady + " QR=" + qrSettlementReady);
return;
}
LogUtil.d(TAG, "Both settlements ready. POS has data=" + posHasData + ", QR has data=" + qrHasData);
if (!posHasData && !qrHasData) {
LogUtil.d(TAG, "No settlement data to display");
return;
}
launchMainActivity();
}
private void launchMainActivity() {
try { try {
Intent launchIntent = new Intent(this, MainActivity.class); Intent launchIntent = new Intent(this, MainActivity.class);
launchIntent.putExtra(settlementType, true); launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
if ("AUTO_SETTLEMENT".equals(settlementType) && payDetail != null) { if (posHasData && pendingPayDetail != null) {
launchIntent.putExtra("AUTO_SETTLEMENT", true);
launchIntent.putExtra("EXTRA_TRANSACTION_TYPE", TransactionsType.SETTLEMENT.value); launchIntent.putExtra("EXTRA_TRANSACTION_TYPE", TransactionsType.SETTLEMENT.value);
launchIntent.putExtra("EXTRA_PAY_DETAIL", payDetail); launchIntent.putExtra("EXTRA_PAY_DETAIL", pendingPayDetail);
} else if ("AUTO_QR_SETTLEMENT".equals(settlementType) && qrData != null) { }
launchIntent.putExtra("EXTRA_TRANSACTION_TYPE", TransactionsType.MMQR_SETTLEMENT.value);
launchIntent.putExtras(qrData); if (qrHasData && pendingQrData != null) {
launchIntent.putExtra("AUTO_QR_SETTLEMENT", true);
launchIntent.putExtra("EXTRA_QR_TRANSACTION_TYPE", TransactionsType.MMQR_SETTLEMENT.value);
launchIntent.putExtras(pendingQrData);
} }
PendingIntent pendingIntent = PendingIntent.getActivity( PendingIntent pendingIntent = PendingIntent.getActivity(
@ -503,13 +627,9 @@ public class AutoSettleService extends Service {
); );
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel( NotificationChannel channel = new NotificationChannel(
"SETTLEMENT_COMPLETE", "SETTLEMENT_COMPLETE", "Settlement Complete", NotificationManager.IMPORTANCE_HIGH);
"Settlement Complete",
NotificationManager.IMPORTANCE_HIGH
);
channel.setDescription("Auto settlement completion notifications"); channel.setDescription("Auto settlement completion notifications");
notificationManager.createNotificationChannel(channel); notificationManager.createNotificationChannel(channel);
} }
@ -524,25 +644,24 @@ public class AutoSettleService extends Service {
.setFullScreenIntent(pendingIntent, true); .setFullScreenIntent(pendingIntent, true);
notificationManager.notify(2001, builder.build()); notificationManager.notify(2001, builder.build());
LogUtil.d(TAG, " Settlement complete notification created - will launch app when tapped"); // Reset state
pendingPayDetail = null;
pendingQrData = null;
posSettlementReady = false;
qrSettlementReady = false;
posHasData = false;
qrHasData = false;
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); startActivity(launchIntent);
} catch (Exception directException) {
LogUtil.d(TAG, "Direct launch failed (expected on modern Android), notification approach will handle it");
}
} catch (Exception e) { } catch (Exception e) {
LogUtil.e(TAG, "Error creating settlement notification: " + e.getMessage()); LogUtil.e(TAG, "Error launching MainActivity: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
} }
} }
private void sendEReceipt(EReceiptRequest request) { private void sendEReceipt(EReceiptRequest request) {
try { try {
LogUtil.d(TAG, "Sending e-receipt: " + new Gson().toJson(request)); LogUtil.d(TAG, "Sending e-receipt: " + new Gson().toJson(request));

View File

@ -328,6 +328,17 @@ public class SettingsFragment extends DataBindingFragment {
} }
} }
public void onClearReversalClick() {
try {
sharedViewModel.transactionsType.postValue(TransactionsType.CLEAR_REVERSAL);
sharedViewModel.setTransMenu(TransMenu.CLEAR_REVERSAL);
Navigation.findNavController(requireActivity(), R.id.nav_host_fragment)
.navigate(R.id.inputPasswordFragment);
} catch (Exception e) {
LogUtil.e(TAG, "Error in clear reversal click: " + e.getMessage());
}
}
public void onTmsConfigClick() { public void onTmsConfigClick() {
try { try {
LogUtil.d(TAG, "TMS Config clicked"); LogUtil.d(TAG, "TMS Config clicked");

View File

@ -262,6 +262,7 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind
} else { } else {
allType.add(CardSlotTypeEnum.ICC1); allType.add(CardSlotTypeEnum.ICC1);
allType.add(CardSlotTypeEnum.RF); allType.add(CardSlotTypeEnum.RF);
allType.add(CardSlotTypeEnum.SWIPE);
} }
// int allType = AidlConstants.CardType.IC.getValue() | AidlConstants.CardType.MAGNETIC.getValue(); // int allType = AidlConstants.CardType.IC.getValue() | AidlConstants.CardType.MAGNETIC.getValue();
@ -289,7 +290,7 @@ public class CardWaitingFragment extends DataBindingFragment implements DataBind
} else if (isFallback && cardType == CardTypeX.MAG) { } else if (isFallback && cardType == CardTypeX.MAG) {
/* do fallback transactions */ /* do fallback transactions */
sharedViewModel.isEmv.setValue(false); sharedViewModel.isEmv.postValue(false);
cardReadViewModel.setCardTransactionType(CardTransactionType.FALLBACK); cardReadViewModel.setCardTransactionType(CardTransactionType.FALLBACK);
} else if (cardType == CardTypeX.IC || cardType == CardTypeX.NFC) { } else if (cardType == CardTypeX.IC || cardType == CardTypeX.NFC) {

View File

@ -3,6 +3,7 @@ package com.utsmm.kbz.ui.core_ui;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -158,6 +159,7 @@ public class EmvTransactionFragment extends DataBindingFragment {
} }
observeEmvResultStatus(); observeEmvResultStatus();
observePinWarning();
} }
private boolean isNotManualTransaction() { private boolean isNotManualTransaction() {
@ -244,7 +246,7 @@ public class EmvTransactionFragment extends DataBindingFragment {
isCardTaped("Please try again",new CardDetectCallback() { isCardTaped("Please try again",new CardDetectCallback() {
@Override @Override
public void onComplete() { public void onComplete() {
sharedViewModel.setIsSeePhone(true); sharedViewModel.setIsSeePhone(false);
navigateToCheckCard(); navigateToCheckCard();
} }
}); });
@ -349,6 +351,15 @@ public class EmvTransactionFragment extends DataBindingFragment {
}); });
} }
private void observePinWarning() {
emvTransactionViewModel.pinRemainingCount.observe(getViewLifecycleOwner(), msg -> {
if (!TextUtils.isEmpty(msg)) {
Toast.makeText(requireContext(), msg, Toast.LENGTH_SHORT).show();
emvTransactionViewModel.pinRemainingCount.setValue("");
}
});
}
private void observeEmvErrorCode() { private void observeEmvErrorCode() {
dismissLoadingDialog(); dismissLoadingDialog();
emvTransactionViewModel.errorCodeMsg.observe(getViewLifecycleOwner(), pair -> { emvTransactionViewModel.errorCodeMsg.observe(getViewLifecycleOwner(), pair -> {

View File

@ -6,6 +6,8 @@ import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.Observer;
import androidx.navigation.NavController; import androidx.navigation.NavController;
import androidx.navigation.NavDestination; import androidx.navigation.NavDestination;
@ -17,6 +19,9 @@ import com.utsmyanmar.baselib.fragment.DataBindingFragment;
import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest; import com.utsmyanmar.baselib.network.model.e_receipt.EReceiptRequest;
import com.utsmyanmar.baselib.util.DataBindingConfig; import com.utsmyanmar.baselib.util.DataBindingConfig;
import com.utsmyanmar.baselib.util.TimeoutCallback; import com.utsmyanmar.baselib.util.TimeoutCallback;
import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.reversal.ReversalAction;
import com.utsmyanmar.paylibs.reversal.ReversalListener;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmm.kbz.BR; import com.utsmm.kbz.BR;
import com.utsmm.kbz.R; import com.utsmm.kbz.R;
@ -104,6 +109,17 @@ public class ProcessingFragment extends DataBindingFragment {
setToolBarTitleWithoutBackIcon(getResourceString(R.string.title_processing)); setToolBarTitleWithoutBackIcon(getResourceString(R.string.title_processing));
checkReversal();
// disableNavigationBar();
getNavController(Constants.NAV_HOST_ID).addOnDestinationChangedListener(listener);
}
private void startTransactionProcess() {
if(isEmvTrans()) { if(isEmvTrans()) {
startTransactionProcess(emvTransactionProcessViewModel); startTransactionProcess(emvTransactionProcessViewModel);
} else { } else {
@ -111,13 +127,55 @@ public class ProcessingFragment extends DataBindingFragment {
} }
sharedViewModel.loadingMsg(getResourceString(R.string.txt_sending)); sharedViewModel.loadingMsg(getResourceString(R.string.txt_sending));
// disableNavigationBar();
getNavController(Constants.NAV_HOST_ID).addOnDestinationChangedListener(listener);
} }
private void checkReversal() {
observeOnce(sharedViewModel.getLastReversalTransaction(), payDetail -> {
if (payDetail != null) {
TradeData tradeData = new TradeData();
tradeData.setPayDetail(payDetail);
LogUtil.d(TAG, "Sending Reversal!");
sharedViewModel.loadingMsg(getResourceString(R.string.txt_sending_reversal));
ReversalAction.getInstance().setData(tradeData).enqueue().startReversal(new ReversalListener() {
@Override
public void onSuccessReversal() {
LogUtil.d(TAG, "Reversal Success!");
payDetail.setIsNeedReversal(false);
sharedViewModel.updatePayDetail(payDetail);
delayFunctionCall(()->startTransactionProcess());
}
@Override
public void onNetworkFail(String msg) {
LogUtil.d(TAG, "Reversal Network Fail!" + msg);
startTransactionProcess();
}
@Override
public void onFailReversal(String msg) {
LogUtil.d(TAG, "Reversal Fail!" + msg);
startTransactionProcess();
}
});
} else {
LogUtil.d(TAG,"No reversal found!");
startTransactionProcess();
}
});
}
private <T> void observeOnce(LiveData<T> liveData, Observer<T> observer) {
liveData.observe(getViewLifecycleOwner(), new Observer<T>() {
@Override
public void onChanged(T t) {
liveData.removeObserver(this);
observer.onChanged(t);
}
});
}
private boolean isEmvTrans() { private boolean isEmvTrans() {
return sharedViewModel.isEmv.getValue() != null && sharedViewModel.isEmv.getValue(); return sharedViewModel.isEmv.getValue() != null && sharedViewModel.isEmv.getValue();
} }

View File

@ -335,6 +335,7 @@ public class TransactionResultFragment extends DataBindingFragment implements Da
sharedViewModel.startPrintSettlement(new PrintXStatus() { sharedViewModel.startPrintSettlement(new PrintXStatus() {
@Override @Override
public void onSuccess() { public void onSuccess() {
sharedViewModel.onSettlementResultDone.postValue(true);
isCardInside(); isCardInside();
} }

View File

@ -2,6 +2,7 @@ package com.utsmm.kbz.ui.core_viewmodel;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.util.Log; import android.util.Log;
import android.widget.ListView;
import dagger.hilt.android.lifecycle.HiltViewModel; import dagger.hilt.android.lifecycle.HiltViewModel;
import androidx.lifecycle.LiveData; import androidx.lifecycle.LiveData;
@ -73,7 +74,8 @@ public class SharedViewModel extends ViewModel {
public SingleLiveEvent<String> transactionName = new SingleLiveEvent<>(); public SingleLiveEvent<String> transactionName = new SingleLiveEvent<>();
// In SharedViewModel
public MutableLiveData<Boolean> onSettlementResultDone = new MutableLiveData<>(false);
/*May 16 2022*/ /*May 16 2022*/
public SingleLiveEvent<Boolean> isEcr = new SingleLiveEvent<>(); public SingleLiveEvent<Boolean> isEcr = new SingleLiveEvent<>();
@ -446,6 +448,14 @@ public class SharedViewModel extends ViewModel {
return repository.getReversalTransaction(voucherNo); return repository.getReversalTransaction(voucherNo);
} }
public LiveData<PayDetail> getLastReversalTransaction() {
return repository.getLastReversalTransaction();
}
public LiveData<List<PayDetail>> getAllReversalTransaction() {
return repository.getAllReversalTransactions();
}
public void updatePayDetail(PayDetail payDetail){ public void updatePayDetail(PayDetail payDetail){
repository.updatePayDetail(payDetail); repository.updatePayDetail(payDetail);
} }

View File

@ -210,13 +210,35 @@ public class SelectHostFragment extends DataBindingFragment implements DataBindi
private void clearReversal() { private void clearReversal() {
checkPointReversal = false; checkPointReversal = false;
sharedViewModel.getReversalTransaction(SystemParamsOperation.getInstance().getCurrentSerialNum()).observe(getViewLifecycleOwner(), payDetail -> { // sharedViewModel.getReversalTransaction(SystemParamsOperation.getInstance().getCurrentSerialNum()).observe(getViewLifecycleOwner(), payDetail -> {
if (payDetail != null) { // if (payDetail != null) {
if (!checkPointReversal) { // if (!checkPointReversal) {
// payDetail.setIsNeedReversal(false);
// sharedViewModel.updatePayDetail(payDetail);
// checkPointReversal = true;
//
// showSuccessDialog("Clear reversal success!");
// }
// } else {
// if (!checkPointReversal) {
// showInfoDialog("Clear reversal", "No reversal found!");
// checkPointReversal = true;
// }
//
// }
// });
sharedViewModel.getAllReversalTransaction().observe(getViewLifecycleOwner(), new Observer<List<PayDetail>>() {
@Override
public void onChanged(List<PayDetail> payDetails) {
if(payDetails != null && !payDetails.isEmpty()) {
if(!checkPointReversal) {
for (PayDetail payDetail : payDetails) {
payDetail.setIsNeedReversal(false); payDetail.setIsNeedReversal(false);
sharedViewModel.updatePayDetail(payDetail); sharedViewModel.updatePayDetail(payDetail);
checkPointReversal = true;
}
checkPointReversal = true;
showSuccessDialog("Clear reversal success!"); showSuccessDialog("Clear reversal success!");
} }
} else { } else {
@ -224,7 +246,7 @@ public class SelectHostFragment extends DataBindingFragment implements DataBindi
showInfoDialog("Clear reversal", "No reversal found!"); showInfoDialog("Clear reversal", "No reversal found!");
checkPointReversal = true; checkPointReversal = true;
} }
}
} }
}); });
} }

View File

@ -359,7 +359,10 @@ public class PinPadViewModel extends ViewModel {
handler.obtainMessage(ON_ERROR_PIN_PAD,retCode).sendToTarget(); handler.obtainMessage(ON_ERROR_PIN_PAD,retCode).sendToTarget();
} }
LogUtil.d(TAG,"RetCode:"+retCode); LogUtil.d(TAG,"RetCode:"+retCode);
if(retCode != SdkResult.PinPad_No_Pin_Input) {
payDetail.setPINCipher(ByteUtil.bytes2HexStr(data)); payDetail.setPINCipher(ByteUtil.bytes2HexStr(data));
}
LogUtil.d(TAG,"data bytes:"+ByteUtil.bytes2HexStr(data)); LogUtil.d(TAG,"data bytes:"+ByteUtil.bytes2HexStr(data));
} }

View File

@ -37,6 +37,7 @@ public class InjectKeyFragment extends DataBindingFragment {
private DownloadFlow mDownloadFlow; private DownloadFlow mDownloadFlow;
private int keyIndexTmp = 8; // Default key index private int keyIndexTmp = 8; // Default key index
private final List<HostSelectionItem> hostSelectionItems = new ArrayList<>(); private final List<HostSelectionItem> hostSelectionItems = new ArrayList<>();
private HostSelectionItem selectedHostSelectionItem;
@Override @Override
protected void initViewModel() { protected void initViewModel() {
@ -128,6 +129,7 @@ public class InjectKeyFragment extends DataBindingFragment {
} }
private void applyHostSelection(@NonNull HostSelectionItem selectionItem) { private void applyHostSelection(@NonNull HostSelectionItem selectionItem) {
selectedHostSelectionItem = selectionItem;
binding.terminalIdValue.setText(getDisplayValue(selectionItem.terminalId)); binding.terminalIdValue.setText(getDisplayValue(selectionItem.terminalId));
binding.merchantIdValue.setText(getDisplayValue(selectionItem.merchantId)); binding.merchantIdValue.setText(getDisplayValue(selectionItem.merchantId));
} }
@ -156,14 +158,14 @@ public class InjectKeyFragment extends DataBindingFragment {
mDownloadFlow = DownloadFlow.getInstance(); mDownloadFlow = DownloadFlow.getInstance();
String terminalId = SystemParamsOperation.getInstance().getTerminalId(); String terminalId = selectedHostSelectionItem != null ? selectedHostSelectionItem.terminalId : null;
String merchantId = SystemParamsOperation.getInstance().getMerchantId(); String merchantId = selectedHostSelectionItem != null ? selectedHostSelectionItem.merchantId : null;
String serialNo = TMSUtil.getInstance().getSerialNumber(); String serialNo = TMSUtil.getInstance().getSerialNumber();
// Validate configuration // Validate configuration
if (TextUtils.isEmpty(terminalId) || TextUtils.isEmpty(merchantId) || TextUtils.isEmpty(serialNo)) { if (TextUtils.isEmpty(terminalId) || TextUtils.isEmpty(merchantId) || TextUtils.isEmpty(serialNo)) {
dismissLoadingDialog(); dismissLoadingDialog();
showDeclineDialog("Please configure Terminal ID, Merchant ID first in TMS Configuration"); showDeclineDialog("Please configure the selected Terminal ID and Merchant ID first in TMS Configuration");
return; return;
} }

View File

@ -462,11 +462,7 @@ public class SettlementViewModel extends ViewModel {
} else if (TextUtils.equals(resultStr, "95") || TextUtils.equals(resultStr, "095")) { } else if (TextUtils.equals(resultStr, "95") || TextUtils.equals(resultStr, "095")) {
//reversal //reversal
// if (!flag && isNoData.getValue()) { // if (!flag && isNoData.getValue()) {
if (!flag ) { payDetail.setIsNeedReversal(!flag);
payDetail.setIsNeedReversal(true);
} else {
payDetail.setIsNeedReversal(false);
}
} }
} else { } else {

View File

@ -6,6 +6,7 @@ import com.utsmyanmar.paylibs.model.CardInfo;
import com.utsmyanmar.paylibs.model.MAGCardInfo; import com.utsmyanmar.paylibs.model.MAGCardInfo;
import com.utsmyanmar.paylibs.model.PayDetail; import com.utsmyanmar.paylibs.model.PayDetail;
import com.utsmyanmar.paylibs.model.TradeData; import com.utsmyanmar.paylibs.model.TradeData;
import com.utsmyanmar.paylibs.model.enums.TransCVM;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation; import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType; import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmyanmar.paylibs.utils.params.Params; import com.utsmyanmar.paylibs.utils.params.Params;
@ -98,6 +99,7 @@ public class TransactionUtil {
PayDetail payDetail = tradeData.getPayDetail(); PayDetail payDetail = tradeData.getPayDetail();
payDetail.setCardNo(cardDataX.getPan()); payDetail.setCardNo(cardDataX.getPan());
payDetail.setEXPDate(cardDataX.getExp()); payDetail.setEXPDate(cardDataX.getExp());
payDetail.setTransCVM(TransCVM.SIGNATURE);
if(cardDataX.getPan().startsWith("4")) { if(cardDataX.getPan().startsWith("4")) {
payDetail.setAccountType(VISA_CARD_SCHEME); payDetail.setAccountType(VISA_CARD_SCHEME);

View File

@ -120,16 +120,17 @@
<TextView <TextView
android:id="@+id/txt_emv_remaining_count" android:id="@+id/txt_emv_remaining_count"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin_button" android:layout_marginTop="@dimen/margin_button"
android:fontFamily="@font/rubik_regular" android:fontFamily="@font/rubik_regular"
android:gravity="center"
android:text="@{emv.pinRemainingCount}" android:text="@{emv.pinRemainingCount}"
android:textColor="@color/white" android:textColor="@color/white"
android:textSize="@dimen/pan_size" android:textSize="@dimen/pan_size"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/textView3" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView20" app:layout_constraintTop_toBottomOf="@+id/txt_emv_pin_mode"
app:layout_goneMarginTop="@dimen/margin_button" app:layout_goneMarginTop="@dimen/margin_button"
tools:text="3 LEFT" /> tools:text="3 LEFT" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -969,6 +969,81 @@
</androidx.cardview.widget.CardView> </androidx.cardview.widget.CardView>
<!-- Clear Reversal Card -->
<androidx.cardview.widget.CardView
android:id="@+id/clearReversalCard"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:clickable="true"
android:foreground="?android:attr/selectableItemBackground"
android:onClick="@{()->click.onClearReversalClick()}"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="20dp">
<androidx.cardview.widget.CardView
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginEnd="16dp"
app:cardBackgroundColor="@color/colorPrimary"
app:cardCornerRadius="24dp"
app:cardElevation="0dp">
<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center"
android:src="@drawable/ic_clear_all"
app:tint="@color/white" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:fontFamily="@font/rubik_medium"
android:text="@string/title_clear_reversal"
android:textColor="@color/colorTextTitle"
android:textSize="18sp"
android:textStyle="bold"
tools:fontFamily="sans-serif-medium" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:fontFamily="@font/rubik_regular"
android:text="@string/clear_reversal_description"
android:textColor="@color/colorTextContent"
android:textSize="14sp"
tools:fontFamily="sans-serif" />
</LinearLayout>
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_right_arrow"
app:tint="@color/colorPrimary" />
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- TMS Server URL Card --> <!-- TMS Server URL Card -->
<!-- android:onClick="@{()->click.onTmsAddressClick()}"--> <!-- android:onClick="@{()->click.onTmsAddressClick()}"-->
<androidx.cardview.widget.CardView <androidx.cardview.widget.CardView

View File

@ -23,6 +23,7 @@ public final class TerminalKeyUtil {
public static final String TAG = TerminalKeyUtil.class.getSimpleName(); public static final String TAG = TerminalKeyUtil.class.getSimpleName();
private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("875f63741753d18811a3449090d1777b".toUpperCase()); // KBZ UAT private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("875f63741753d18811a3449090d1777b".toUpperCase()); // KBZ UAT
// private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("875f63741753d18811a3449090d1777b".toUpperCase());
// private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("e121249099a677e8b7d4f6a9d49fe8d1".toUpperCase()); // MPU // private static final byte[] main_key_data = ByteUtil.hexStr2Bytes("e121249099a677e8b7d4f6a9d49fe8d1".toUpperCase()); // MPU
private static final byte[] work_key_data = new byte[16]; private static final byte[] work_key_data = new byte[16];

View File

@ -97,6 +97,12 @@ public interface PayDetailDao {
@Query("SELECT * FROM paydetail WHERE transactionType = 10 AND isNeedReversal = 1 AND voucherNo IN(:voucherNo)") @Query("SELECT * FROM paydetail WHERE transactionType = 10 AND isNeedReversal = 1 AND voucherNo IN(:voucherNo)")
LiveData<PayDetail> getReversalTransaction(String voucherNo); LiveData<PayDetail> getReversalTransaction(String voucherNo);
@Query("SELECT * FROM PayDetail WHERE isNeedReversal = 1 ORDER BY PID DESC LIMIT 1")
LiveData<PayDetail> getLastReversalTransactionLive();
@Query("SELECT * FROM PayDetail WHERE isNeedReversal = 1 ORDER BY PID DESC")
LiveData<List<PayDetail>> getAllReversalTransactionsLive();
// @Query("SELECT * FROM paydetail WHERE transactionType != 10 ORDER BY PID DESC") // @Query("SELECT * FROM paydetail WHERE transactionType != 10 ORDER BY PID DESC")
@Query("SELECT * FROM paydetail ORDER BY PID DESC") @Query("SELECT * FROM paydetail ORDER BY PID DESC")
LiveData<List<PayDetail>> getTransactionHistory(); LiveData<List<PayDetail>> getTransactionHistory();

View File

@ -349,7 +349,7 @@ public class EmvParamHelper {
private AidEntity convertContactlessAIDNex(ContactlessAid contactlessAid) { private AidEntity convertContactlessAIDNex(ContactlessAid contactlessAid) {
AidEntity aidV2 = new AidEntity(); AidEntity aidV2 = new AidEntity();
aidV2.setTransType("FF"); aidV2.setTransType("FF"); // FF
aidV2.setOnlinePinCap(1); aidV2.setOnlinePinCap(1);
aidV2.setAsi(0); aidV2.setAsi(0);
aidV2.setThreshold(0); aidV2.setThreshold(0);
@ -412,7 +412,8 @@ public class EmvParamHelper {
aidV2.setTransType("FF"); aidV2.setTransType("FF");
aidV2.setOnlinePinCap(1); aidV2.setOnlinePinCap(1);
aidV2.setAsi(1); aidV2.setAsi(0); //1
// aidV2.setThreshold(99);
if (!(contactAid.getCvmLimit() < 0)) { if (!(contactAid.getCvmLimit() < 0)) {
aidV2.setContactlessCvmLimit(contactAid.getCvmLimit()); aidV2.setContactlessCvmLimit(contactAid.getCvmLimit());
@ -464,6 +465,10 @@ public class EmvParamHelper {
aidV2.setAppVerNum(contactAid.getApplicationVersion()); aidV2.setAppVerNum(contactAid.getApplicationVersion());
} }
if (contactAid.getThreshold() != null && !contactAid.getThreshold().isEmpty()) {
aidV2.setThreshold(Long.parseLong(contactAid.getThreshold()));
}
return aidV2; return aidV2;
} }

View File

@ -146,6 +146,8 @@ public class Repository {
public void updatePayDetail(PayDetail payDetail){payDetailDao.update(payDetail);} public void updatePayDetail(PayDetail payDetail){payDetailDao.update(payDetail);}
public LiveData<PayDetail> getReversalTransaction(String voucherNo) { return payDetailDao.getReversalTransaction(voucherNo);} public LiveData<PayDetail> getReversalTransaction(String voucherNo) { return payDetailDao.getReversalTransaction(voucherNo);}
public LiveData<PayDetail> getLastReversalTransaction() { return payDetailDao.getLastReversalTransactionLive();}
public LiveData<List<PayDetail>> getAllReversalTransactions() { return payDetailDao.getAllReversalTransactionsLive();}
public LiveData<List<PayDetail>> getTransactionHistory(){ return payDetailDao.getTransactionHistory();} public LiveData<List<PayDetail>> getTransactionHistory(){ return payDetailDao.getTransactionHistory();}

View File

@ -1,12 +1,15 @@
package com.utsmyanmar.baselib.viewModel; package com.utsmyanmar.baselib.viewModel;
import android.app.AlertDialog;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver; import android.view.ViewTreeObserver;
import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.MutableLiveData;
@ -105,6 +108,7 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
public MutableLiveData<Integer> pinPadVisibility = new MutableLiveData<>(8); public MutableLiveData<Integer> pinPadVisibility = new MutableLiveData<>(8);
protected int pinEnterCount; protected int pinEnterCount;
private int offlinePinIncorrectPromptCount;
public CustomPinPadKeyboard customPinPadKeyboard; public CustomPinPadKeyboard customPinPadKeyboard;
private int mWidth = 239; // Single item width of password keyboard private int mWidth = 239; // Single item width of password keyboard
@ -245,6 +249,7 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
transData.setTransTime(new SimpleDateFormat("hhmmss", Locale.getDefault()).format(new Date())); transData.setTransTime(new SimpleDateFormat("hhmmss", Locale.getDefault()).format(new Date()));
transData.setTraceNo(mPayDetail.getVoucherNo()); transData.setTraceNo(mPayDetail.getVoucherNo());
transData.setEmvProcessFlowEnum(EmvProcessFlowEnum.EMV_PROCESS_FLOW_STANDARD); transData.setEmvProcessFlowEnum(EmvProcessFlowEnum.EMV_PROCESS_FLOW_STANDARD);
if (mPayDetail.getCardType() == CardTypeX.NFC.value) { if (mPayDetail.getCardType() == CardTypeX.NFC.value) {
transData.setEmvEntryModeEnum(EmvEntryModeEnum.EMV_ENTRY_MODE_CONTACTLESS); transData.setEmvEntryModeEnum(EmvEntryModeEnum.EMV_ENTRY_MODE_CONTACTLESS);
@ -260,7 +265,8 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
unionPayTransDataEntity.setSupportCDCVM(true); unionPayTransDataEntity.setSupportCDCVM(true);
//if support QPS, please enable below lines //if support QPS, please enable below lines
unionPayTransDataEntity.setSupportContactlessQps(true); unionPayTransDataEntity.setSupportContactlessQps(true);
unionPayTransDataEntity.setContactlessQpsLimit("000090000000"); unionPayTransDataEntity.setContactlessQpsLimit("000000030000");
transData.setUnionPayTransDataEntity(unionPayTransDataEntity); transData.setUnionPayTransDataEntity(unionPayTransDataEntity);
@ -269,6 +275,8 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
emvHandler.contactlessAppendAidIntoKernel(EmvCardBrandEnum.EMV_CARD_BRAND_MASTER, (byte) 0x08, ByteUtils.hexString2ByteArray("A000000732100123")); emvHandler.contactlessAppendAidIntoKernel(EmvCardBrandEnum.EMV_CARD_BRAND_MASTER, (byte) 0x08, ByteUtils.hexString2ByteArray("A000000732100123"));
LogUtil.d(TAG, "TransData :" + transData.getTransAmount()); LogUtil.d(TAG, "TransData :" + transData.getTransAmount());
LogUtil.d(TAG, "start emv "); LogUtil.d(TAG, "start emv ");
// emvHandler.emvDebugLog(true);
emvHandler.emvProcess(transData, emvProcessListener); emvHandler.emvProcess(transData, emvProcessListener);
@ -308,8 +316,8 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
return; return;
} }
try { try {
LogUtil.d(TAG, "Selected :" + position); LogUtil.d(TAG, "Selected :" + position + 1);
emvHandler.onSetSelAppResponse(position); emvHandler.onSetSelAppResponse(position + 1);
} catch (Exception e) { } catch (Exception e) {
LogUtil.e(TAG, "Exception during app selection: " + e.getMessage()); LogUtil.e(TAG, "Exception during app selection: " + e.getMessage());
e.printStackTrace(); e.printStackTrace();
@ -425,126 +433,49 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
initKeyboard(isOnlinePin == 1); initKeyboard(isOnlinePin == 1);
} }
private void initKeyboard(boolean isOnlinePin) { private void initKeyboard(boolean isOnlinePin) {
LogUtil.d(TAG, "init keyboard!");
LogUtil.d(TAG,"init keyboard!");
pinPadVisibility.setValue(0); pinPadVisibility.setValue(0);
LogUtil.d(TAG,"pin pad is visible now!"); LogUtil.d(TAG, "pin pad is visible now!");
// Check if the view is already laid out
if (customPinPadKeyboard.getWidth() > 0 && customPinPadKeyboard.getHeight() > 0) {
// View already laid out call setup directly
setupPinPadLayout(isOnlinePin);
} else {
// View not yet laid out wait for layout
customPinPadKeyboard.getViewTreeObserver().addOnGlobalLayoutListener( customPinPadKeyboard.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener() { new ViewTreeObserver.OnGlobalLayoutListener() {
@Override @Override
public void onGlobalLayout() { public void onGlobalLayout() {
if (customPinPadKeyboard.getWidth() > 0 && customPinPadKeyboard.getHeight() > 0) {
customPinPadKeyboard.getViewTreeObserver().removeOnGlobalLayoutListener(this); customPinPadKeyboard.getViewTreeObserver().removeOnGlobalLayoutListener(this);
setupPinPadLayout(isOnlinePin);
}
}
}
);
}
}
LogUtil.d(TAG,"inside the global layout!"); private void setupPinPadLayout(boolean isOnlinePin) {
LogUtil.d(TAG, "inside the global layout!");
PinpadLayoutEntity pinpadLayout = new PinpadLayoutEntity(); PinpadLayoutEntity pinpadLayout = new PinpadLayoutEntity();
int[] location = new int[2];
Rect r;
customPinPadKeyboard.getKey_1().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_1().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_1().getHeight() + r.top;
pinpadLayout.setKey1(r);
customPinPadKeyboard.getKey_2().getLocationOnScreen(location); // Helper to avoid repetition
r = new Rect(); pinpadLayout.setKey1(getRectForView(customPinPadKeyboard.getKey_1()));
r.left = location[0]; pinpadLayout.setKey2(getRectForView(customPinPadKeyboard.getKey_2()));
r.top = location[1]; pinpadLayout.setKey3(getRectForView(customPinPadKeyboard.getKey_3()));
r.right = customPinPadKeyboard.getKey_2().getWidth() + r.left; pinpadLayout.setKey4(getRectForView(customPinPadKeyboard.getKey_4()));
r.bottom = customPinPadKeyboard.getKey_2().getHeight() + r.top; pinpadLayout.setKey5(getRectForView(customPinPadKeyboard.getKey_5()));
pinpadLayout.setKey2(r); pinpadLayout.setKey6(getRectForView(customPinPadKeyboard.getKey_6()));
pinpadLayout.setKey7(getRectForView(customPinPadKeyboard.getKey_7()));
customPinPadKeyboard.getKey_3().getLocationOnScreen(location); pinpadLayout.setKey8(getRectForView(customPinPadKeyboard.getKey_8()));
r = new Rect(); pinpadLayout.setKey9(getRectForView(customPinPadKeyboard.getKey_9()));
r.left = location[0]; pinpadLayout.setKey10(getRectForView(customPinPadKeyboard.getKey_0()));
r.top = location[1]; pinpadLayout.setKeyCancel(getRectForView(customPinPadKeyboard.getKey_cancel()));
r.right = customPinPadKeyboard.getKey_3().getWidth() + r.left; pinpadLayout.setKeyClear(getRectForView(customPinPadKeyboard.getKey_clear()));
r.bottom = customPinPadKeyboard.getKey_3().getHeight() + r.top; pinpadLayout.setKeyConfirm(getRectForView(customPinPadKeyboard.getKey_ok()));
pinpadLayout.setKey3(r);
customPinPadKeyboard.getKey_4().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_4().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_4().getHeight() + r.top;
pinpadLayout.setKey4(r);
customPinPadKeyboard.getKey_5().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_5().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_5().getHeight() + r.top;
pinpadLayout.setKey5(r);
customPinPadKeyboard.getKey_6().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_6().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_6().getHeight() + r.top;
pinpadLayout.setKey6(r);
customPinPadKeyboard.getKey_7().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_7().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_7().getHeight() + r.top;
pinpadLayout.setKey7(r);
customPinPadKeyboard.getKey_8().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_8().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_8().getHeight() + r.top;
pinpadLayout.setKey8(r);
customPinPadKeyboard.getKey_9().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_9().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_9().getHeight() + r.top;
pinpadLayout.setKey9(r);
customPinPadKeyboard.getKey_0().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_0().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_0().getHeight() + r.top;
pinpadLayout.setKey10(r);
customPinPadKeyboard.getKey_cancel().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_cancel().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_cancel().getHeight() + r.top;
pinpadLayout.setKeyCancel(r);
customPinPadKeyboard.getKey_clear().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_clear().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_clear().getHeight() + r.top;
pinpadLayout.setKeyClear(r);
customPinPadKeyboard.getKey_ok().getLocationOnScreen(location);
r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = customPinPadKeyboard.getKey_ok().getWidth() + r.left;
r.bottom = customPinPadKeyboard.getKey_ok().getHeight() + r.top;
pinpadLayout.setKeyConfirm(r);
byte[] number = pinPad.setPinpadLayout(pinpadLayout); byte[] number = pinPad.setPinpadLayout(pinpadLayout);
@ -628,10 +559,16 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
} }
} }
} // Reusable rect helper
); private Rect getRectForView(View view) {
int[] location = new int[2];
view.getLocationOnScreen(location);
Rect r = new Rect();
r.left = location[0];
r.top = location[1];
r.right = view.getWidth() + r.left;
r.bottom = view.getHeight() + r.top;
return r;
} }
private void increaseCount() { private void increaseCount() {
@ -676,11 +613,11 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
} }
} else { } else {
//contact terminal capability ; if different card brand(depend on aid) have different terminal capability //contact terminal capability ; if different card brand(depend on aid) have different terminal capability
if (ByteUtils.byteArray2HexString(aid).toUpperCase().contains("A000000004")) { // if (ByteUtils.byteArray2HexString(aid).toUpperCase().contains("A000000004")) {
emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x33}, ByteUtil.hexStr2Bytes(terminalCapability)); // emvHandler.setTlv(new byte[]{(byte) 0x9F, (byte) 0x33}, ByteUtil.hexStr2Bytes(terminalCapability));
emvHandler.setTlv(new byte[]{(byte) 0xE0, (byte) 0x1D}, ByteUtils.hexString2ByteArray("6C00800000000000"));//terminal risk // emvHandler.setTlv(new byte[]{(byte) 0xE0, (byte) 0x1D}, ByteUtils.hexString2ByteArray("6C00800000000000"));//terminal risk
//
} // }
} }
emvHandler.onSetTransInitBeforeGPOResponse(true); emvHandler.onSetTransInitBeforeGPOResponse(true);
@ -705,6 +642,9 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
public void onCardHolderInputPin(boolean isOnlinePin, int leftTimes) { public void onCardHolderInputPin(boolean isOnlinePin, int leftTimes) {
LogUtil.d(TAG, "onCardHolderInputPin isOnlinePin = " + isOnlinePin); LogUtil.d(TAG, "onCardHolderInputPin isOnlinePin = " + isOnlinePin);
LogUtil.d(TAG, "onCardHolderInputPin leftTimes = " + leftTimes); LogUtil.d(TAG, "onCardHolderInputPin leftTimes = " + leftTimes);
if (isOnlinePin) {
pinRemainingCount.postValue("");
}
// startPinProcess(isOnlinePin ? 1 : 0); // startPinProcess(isOnlinePin ? 1 : 0);
mProcessStep = EMV_SHOW_PIN_PAD; mProcessStep = EMV_SHOW_PIN_PAD;
// mHandler.obtainMessage(EMV_SHOW_PIN_PAD, isOnlinePin ? 1 : 0).sendToTarget(); // mHandler.obtainMessage(EMV_SHOW_PIN_PAD, isOnlinePin ? 1 : 0).sendToTarget();
@ -743,8 +683,18 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
@Override @Override
public void onPrompt(PromptEnum promptEnum) { public void onPrompt(PromptEnum promptEnum) {
LogUtil.d(TAG, "onPrompt->" + promptEnum); LogUtil.d(TAG, "onPrompt->" + promptEnum);
if( promptEnum == PromptEnum.OFFLINE_PIN_INCORRECT_TRY_AGAIN) {
offlinePinIncorrectPromptCount++;
pinEnterCount = 0;
pinText.postValue("");
int attemptLeft = Math.max(0, 3 - offlinePinIncorrectPromptCount);
pinRemainingCount.postValue("Please try again!\n" + attemptLeft + " attempt left!");
emvHandler.onSetPromptResponse(false);
} else {
emvHandler.onSetPromptResponse(true); emvHandler.onSetPromptResponse(true);
} }
}
@Override @Override
public void onRemoveCard() { public void onRemoveCard() {
@ -801,6 +751,9 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
byte[] tlv_50 = emvHandler.getTlv(new byte[]{(byte) 0x50}, EmvDataSourceEnum.FROM_KERNEL); byte[] tlv_50 = emvHandler.getTlv(new byte[]{(byte) 0x50}, EmvDataSourceEnum.FROM_KERNEL);
LogUtil.d(TAG, "tlv_50--" + ByteUtils.byteArray2HexString(tlv_50)); LogUtil.d(TAG, "tlv_50--" + ByteUtils.byteArray2HexString(tlv_50));
byte[] tlv_9B = emvHandler.getTlv(new byte[]{(byte) 0x9B}, EmvDataSourceEnum.FROM_KERNEL);
LogUtil.d(TAG, "tlv_9B--" + ByteUtils.byteArray2HexString(tlv_9B));
switch (retCode) { switch (retCode) {
case SdkResult.Emv_Success_Arpc_Fail: case SdkResult.Emv_Success_Arpc_Fail:
case SdkResult.Success: case SdkResult.Success:
@ -967,6 +920,7 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
emvCardType.postValue(""); emvCardType.postValue("");
pinText.setValue(""); pinText.setValue("");
pinEnterCount = 0; pinEnterCount = 0;
offlinePinIncorrectPromptCount = 0;
} }
protected void getCardInfo() { protected void getCardInfo() {
@ -1257,7 +1211,6 @@ public abstract class EmvBaseViewModel extends BaseViewModel {
kernelTTQ[2] = TTQ[2]; kernelTTQ[2] = TTQ[2];
kernelTTQ[3] = TTQ[3]; kernelTTQ[3] = TTQ[3];
// FIXME: 2019/3/20
//If there is no special requirements, do not change TTQ byte1 //If there is no special requirements, do not change TTQ byte1
//if online force required , can set byte2 bit 8 = 1 //if online force required , can set byte2 bit 8 = 1
emvHandler.setTlv(ByteUtils.hexString2ByteArray("9F66"), kernelTTQ); emvHandler.setTlv(ByteUtils.hexString2ByteArray("9F66"), kernelTTQ);

View File

@ -14,7 +14,7 @@
"tacOnline": "DC4004F800", "tacOnline": "DC4004F800",
"tacDenial": "0000000000", "tacDenial": "0000000000",
"floorLimit": "000000000000", "floorLimit": "000000000000",
"cvmLimit": 75000, "cvmLimit": 30000,
"transLimit": "9999999999", "transLimit": "9999999999",
"transLimitCDV": "9999999999", "transLimitCDV": "9999999999",
"terminalCapability": "0000000000000000", "terminalCapability": "0000000000000000",
@ -26,7 +26,6 @@
}, },
{ {
"aidEnable": true, "aidEnable": true,
"aid": "A000000333010102",
"cardLabel": "UPI", "cardLabel": "UPI",
"applicationVersion": "0002", "applicationVersion": "0002",
"emvDDOL": "9F3704", "emvDDOL": "9F3704",
@ -39,7 +38,57 @@
"tacOnline": "DC4004F800", "tacOnline": "DC4004F800",
"tacDenial": "0000000000", "tacDenial": "0000000000",
"floorLimit": "000000000000", "floorLimit": "000000000000",
"cvmLimit": 75000, "cvmLimit": 30000,
"transLimit": "9999999999",
"transLimitCDV": "9999999999",
"terminalCapability": "0000000000000000",
"riskManageData": "01",
"kernelType": "01",
"ttq": "36800000",
"cateCode": "2701",
"currencyCode": "0104"
},
{
"aidEnable": true,
"aid": "A000000333010105",
"cardLabel": "UPI",
"applicationVersion": "0002",
"emvDDOL": "9F3704",
"emvTDOL": "9F3704",
"partialAidSelection": false,
"targetPercent": "99",
"maxTargetPercent": "99",
"threshold": "00000000",
"tacDefault": "D84000A800",
"tacOnline": "DC4004F800",
"tacDenial": "0000000000",
"floorLimit": "000000000000",
"cvmLimit": 30000,
"transLimit": "9999999999",
"transLimitCDV": "9999999999",
"terminalCapability": "0000000000000000",
"riskManageData": "01",
"kernelType": "01",
"ttq": "36800000",
"cateCode": "2701",
"currencyCode": "0104"
},
{
"aidEnable": true,
"aid": "A000000333010106",
"cardLabel": "UPI",
"applicationVersion": "0002",
"emvDDOL": "9F3704",
"emvTDOL": "9F3704",
"partialAidSelection": false,
"targetPercent": "99",
"maxTargetPercent": "99",
"threshold": "00000000",
"tacDefault": "D84000A800",
"tacOnline": "DC4004F800",
"tacDenial": "0000000000",
"floorLimit": "000000000000",
"cvmLimit": 30000,
"transLimit": "9999999999", "transLimit": "9999999999",
"transLimitCDV": "9999999999", "transLimitCDV": "9999999999",
"terminalCapability": "0000000000000000", "terminalCapability": "0000000000000000",

View File

@ -6,6 +6,7 @@ import android.os.Looper;
import android.os.RemoteException; import android.os.RemoteException;
import android.util.Log; import android.util.Log;
import com.nexgo.common.LogUtils;
import com.nexgo.oaf.apiv3.SdkResult; import com.nexgo.oaf.apiv3.SdkResult;
import com.nexgo.oaf.apiv3.device.reader.CardInfoEntity; import com.nexgo.oaf.apiv3.device.reader.CardInfoEntity;
import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum; import com.nexgo.oaf.apiv3.device.reader.CardSlotTypeEnum;
@ -106,6 +107,14 @@ public class CheckCardX {
Log.d(TAG, "Find IC"); Log.d(TAG, "Find IC");
} else if(cardInfoEntity.getCardExistslot() == CardSlotTypeEnum.RF) { } else if(cardInfoEntity.getCardExistslot() == CardSlotTypeEnum.RF) {
checkCardResultX.onSuccess(CardTypeX.NFC,false); checkCardResultX.onSuccess(CardTypeX.NFC,false);
} else if(cardInfoEntity.getCardExistslot() == CardSlotTypeEnum.SWIPE) {
LogUtils.debug(TAG,"Found Swipe");
Bundle info = new Bundle();
info.putString("TRACK1",cardInfoEntity.getTk1());
info.putString("TRACK2",cardInfoEntity.getTk2());
info.putString("TRACK3",cardInfoEntity.getTk3());
MAGXReadCard.getInstance().setBundle(info);
checkCardResultX.onSuccess(CardTypeX.MAG,false);
} }
} else if( i == SdkResult.Fail) { } else if( i == SdkResult.Fail) {
checkCardResultX.onError(i,"Failure"); checkCardResultX.onError(i,"Failure");

View File

@ -1,9 +1,10 @@
package com.utsmyanmar.paylibs.model; package com.utsmyanmar.paylibs.model;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class CardSettleData { public class CardSettleData implements Serializable {
private String cardType; private String cardType;
private String cardNum; private String cardNum;

View File

@ -1,9 +1,10 @@
package com.utsmyanmar.paylibs.model; package com.utsmyanmar.paylibs.model;
import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
public class QRSettleData { public class QRSettleData implements Serializable {
private String transId; private String transId;
private String date; private String date;

View File

@ -1,6 +1,8 @@
package com.utsmyanmar.paylibs.model; package com.utsmyanmar.paylibs.model;
public class SettleData { import java.io.Serializable;
public class SettleData implements Serializable {
private int saleCount; private int saleCount;
private long saleAmount; private long saleAmount;

View File

@ -1,6 +1,8 @@
package com.utsmyanmar.paylibs.model.enums; package com.utsmyanmar.paylibs.model.enums;
public enum TransCVM { import java.io.Serializable;
public enum TransCVM implements Serializable {
OFFLINE_PIN("Offline PIN"), OFFLINE_PIN("Offline PIN"),
ONLINE_PIN("Online PIN"), ONLINE_PIN("Online PIN"),
SIGNATURE("Signature"), SIGNATURE("Signature"),

View File

@ -154,7 +154,6 @@ public class AuthorizationProcessUtil {
hexValues[i] = value; hexValues[i] = value;
} }
int status; int status;
String f055Data = getF055Data();
LogUtil.d(TAG,"is equal:"+equals); LogUtil.d(TAG,"is equal:"+equals);
LogUtil.d(TAG,"Emv Online Result:"+emvOnlineResult); LogUtil.d(TAG,"Emv Online Result:"+emvOnlineResult);
if (equals) { if (equals) {
@ -177,7 +176,7 @@ public class AuthorizationProcessUtil {
LogUtil.e(Constant.TAG, "scriptResult: " + scriptResult); LogUtil.e(Constant.TAG, "scriptResult: " + scriptResult);
payDetail.setScriptResult(scriptResult); payDetail.setScriptResult(scriptResult);
String f055Data = getF055Data();
LogUtil.e(Constant.TAG, "f055Data: " + f055Data); LogUtil.e(Constant.TAG, "f055Data: " + f055Data);
// if (status >= 0) { // if (status >= 0) {
@ -205,6 +204,9 @@ public class AuthorizationProcessUtil {
private void importOnlineProcessStatus(int sdkResult,EmvOnlineResultEntity emvOnlineResult) { private void importOnlineProcessStatus(int sdkResult,EmvOnlineResultEntity emvOnlineResult) {
LogUtil.d(TAG, "importOnlineProcessStatus sdkResult:"+sdkResult); LogUtil.d(TAG, "importOnlineProcessStatus sdkResult:"+sdkResult);
LogUtil.d(TAG, "importOnlineProcessStatus emvOnlineResult:"+emvOnlineResult.toString()); LogUtil.d(TAG, "importOnlineProcessStatus emvOnlineResult:"+emvOnlineResult.toString());
LogUtil.d(TAG, "importOnlineProcessStatus emvOnlineResult:"+emvOnlineResult.getAuthCode());
LogUtil.d(TAG, "importOnlineProcessStatus emvOnlineResult:"+emvOnlineResult.getRejCode());
LogUtil.d(TAG, "importOnlineProcessStatus emvOnlineResult:"+ ByteUtil.bytes2HexStr(emvOnlineResult.getRecvField55()));
PayLibNex.getInstance().deviceEngine.getEmvHandler2("app2").onSetOnlineProcResponse(sdkResult, emvOnlineResult); PayLibNex.getInstance().deviceEngine.getEmvHandler2("app2").onSetOnlineProcResponse(sdkResult, emvOnlineResult);
} }

View File

@ -2,7 +2,10 @@ package com.utsmyanmar.paylibs.utils.core_utils;
import android.text.TextUtils; import android.text.TextUtils;
import com.nexgo.oaf.apiv3.emv.EmvDataSourceEnum;
import com.nexgo.oaf.apiv3.emv.EmvHandler2;
import com.utsmyanmar.paylibs.Constant; import com.utsmyanmar.paylibs.Constant;
import com.utsmyanmar.paylibs.PayLibNex;
import com.utsmyanmar.paylibs.model.BaseCardInfo; import com.utsmyanmar.paylibs.model.BaseCardInfo;
import com.utsmyanmar.paylibs.model.CardInfo; import com.utsmyanmar.paylibs.model.CardInfo;
import com.utsmyanmar.paylibs.model.ICCardInfo; import com.utsmyanmar.paylibs.model.ICCardInfo;
@ -670,43 +673,42 @@ public class KernelDataProcessUtil {
} }
LogUtil.d(TAG,"9F6E data :"+hexStr); LogUtil.d(TAG,"9F6E data :"+hexStr);
// byte[] dataOut = new byte[1024]; byte[] dataOut = new byte[1024];
// EmvHandler2 emvHandler = PayLibNex.getInstance().deviceEngine.getEmvHandler2("app2");
// try { try {
// int len = PayLibsUtils.getInstance().emvOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYWAVE, tagList, dataOut);
// if (len > 0) { byte[] dateValue = emvHandler.getTlv(ByteUtil.hexStr2Bytes("9F6E"), EmvDataSourceEnum.FROM_CARD);
// byte[] dataOutBytes = Arrays.copyOf(dataOut, len); if (dateValue != null) {
// hexStr = ByteUtil.bytes2HexStr(dataOutBytes);
// LogUtil.d(TAG, "get 9F6E Data :" + hexStr); hexStr = ByteUtil.bytes2HexStr(dateValue);
// Map<String, TLV> map = TLVUtil.buildTLVMap(hexStr); LogUtil.d(TAG, "get 9F6E Data :" + hexStr);
// LogUtil.d(TAG, "get 9F6E Data :" + map);
//
// } else { } else {
// LogUtil.e(TAG, "Get the data length of payWave is negative = " + len); LogUtil.e(TAG, "Get the data length of payWave is null = " );
// } }
// } catch (Exception e) { } catch (Exception e) {
// e.printStackTrace(); e.printStackTrace();
// } }
//
// if (hexStr.equals("9F6E00")) { // if (hexStr.equals("9F6E00")) {
// try { // try {
// int len = PayLibsUtils.getInstance().emvOptV2.getTlvList(AidlConstantsV2.EMV.TLVOpCode.OP_PAYPASS, tagList, dataOut); // byte[] dateValue = emvHandler.getTlv(ByteUtil.hexStr2Bytes("9F6E"), EmvDataSourceEnum.FROM_CARD);
// if (len > 0) { // if (dateValue != null) {
// byte[] dataOutBytes = Arrays.copyOf(dataOut, len); // hexStr = ByteUtil.bytes2HexStr(dateValue);
// hexStr = ByteUtil.bytes2HexStr(dataOutBytes);
// LogUtil.d(TAG, "get 9F6E Data :" + hexStr); // LogUtil.d(TAG, "get 9F6E Data :" + hexStr);
// Map<String, TLV> map = TLVUtil.buildTLVMap(hexStr); // Map<String, TLV> map = TLVUtil.buildTLVMap(hexStr);
// LogUtil.d(TAG, "get 9F6E Data :" + map); // LogUtil.d(TAG, "get 9F6E Data :" + map);
// //
// } else { // } else {
// LogUtil.e(TAG, "Get the data length of payPass is negative = " + len); // LogUtil.e(TAG, "Get the data length of payPass is null = ");
// } // }
// } catch (Exception e) { // } catch (Exception e) {
// e.printStackTrace(); // e.printStackTrace();
// } // }
// } // }
// if (!hexStr.equals("9F6E00")) { // if (!hexStr.isEmpty()) {
// f55WaveDataStr += hexStr; // f55WaveDataStr += "9F6E04"+hexStr;
// } // }
icCardInfo.setICC55(f55WaveDataStr); icCardInfo.setICC55(f55WaveDataStr);
payDetail.setICC55(f55WaveDataStr); payDetail.setICC55(f55WaveDataStr);

View File

@ -69,7 +69,8 @@ public class BitmapConfig {
// public static final String BPC_VOID = "3230058028C08000"; // public static final String BPC_VOID = "3230058028C08000";
// commented on Nov 13,2024 // commented on Nov 13,2024
public static final String BPC_VOID = "3230058028C18000"; // original // public static final String BPC_VOID = "3230058028C18000"; // original
public static final String BPC_VOID = "3230058028C08000"; // original March 25, 2026
// public static final String BPC_VOID = "3230058028C08000"; // 16-May-2025 removed DE48 requested by KoAAT added DE2 // public static final String BPC_VOID = "3230058028C08000"; // 16-May-2025 removed DE48 requested by KoAAT added DE2
// public static final String BPC_VOID = "3230058028C08000"; // 16-May-2025 removed DE48 requested by KoAAT // public static final String BPC_VOID = "3230058028C08000"; // 16-May-2025 removed DE48 requested by KoAAT
// public static final String BPC_VOID = "3230058028C18200"; // public static final String BPC_VOID = "3230058028C18200";
@ -108,8 +109,9 @@ public class BitmapConfig {
// public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "7230058028C19800"; // added DE 2 // public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "7230058028C19800"; // added DE 2
// public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "7234058008C09000"; // for tmk MPU // public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "7234058008C09000"; // for tmk MPU
// public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "7230058008C09000"; // for KBZ MPU // public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "7230058008C09000"; // for KBZ MPU
public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "7234058008C09000"; // for KBZ MPU added DE 14 // public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "7234058008C09000"; // for KBZ MPU added DE 14 Mar 25, 26
// public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "3230058028C19800"; public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "3230058028C08000"; // from log March 25
// public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "3230058028C19A00"; //DE55 // public static final String BPC_PRE_AUTH_SALE_VOID_REVERSAL = "3230058028C19A00"; //DE55
// //
// public static final String BPC_PRE_AUTH_SALE_COMPLETE_VOID = "3230058028C09200"; // public static final String BPC_PRE_AUTH_SALE_COMPLETE_VOID = "3230058028C09200";

View File

@ -341,7 +341,8 @@ public class FieldUtils {
} else if (BaseCardType.IC.getValue() == cardType) { // IC } else if (BaseCardType.IC.getValue() == cardType) { // IC
value = "05"; value = "05";
} else if (FALLBACK == cardType){ // Fallback } else if (FALLBACK == cardType){ // Fallback
value = "08"; value = "72";
// value = "08";
} else { // Hand-in card number } else { // Hand-in card number
value = "01"; value = "01";
} }
@ -349,6 +350,9 @@ public class FieldUtils {
if(payDetail.getTransCVM() == TransCVM.OFFLINE_PIN) { if(payDetail.getTransCVM() == TransCVM.OFFLINE_PIN) {
value += "9"; value += "9";
} else {
if(payDetail.getTransactionType() == VOID.value) {
value += "0";
} else { } else {
if (payDetail.getPINCipher() != null && !payDetail.getPINCipher().trim().isEmpty()) { if (payDetail.getPINCipher() != null && !payDetail.getPINCipher().trim().isEmpty()) {
value += "1"; value += "1";
@ -357,6 +361,8 @@ public class FieldUtils {
} }
} }
}
field.setDataStr(value); field.setDataStr(value);

View File

@ -32,7 +32,7 @@ include ':baselib'
include ':mpulib' include ':mpulib'
//include ':ecr-client-lib' //include ':ecr-client-lib'
include ':ecr-service' //include ':ecr-service'
include ':xpay' include ':xpay'
include ':ecr' include ':ecr'
include ':ecr-service-lib' include ':ecr-service-lib'