auto-route

This commit is contained in:
moon 2026-07-20 10:18:34 +06:30
parent 2f1466d67b
commit e613dfa246
5 changed files with 60 additions and 669 deletions

View File

@ -49,6 +49,7 @@ import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsOperation;
import com.utsmyanmar.paylibs.utils.core_utils.SystemParamsSettings;
import com.utsmyanmar.paylibs.utils.enums.TransMenu;
import com.utsmyanmar.paylibs.utils.iso_utils.TransactionsType;
import com.utsmm.kbz.util.enums.SettlementType;
import com.utsmm.kbz.databinding.ActivityMainNewBinding;
import com.utsmm.kbz.service.AutoAlarmReceiver;
import com.utsmm.kbz.ui.core_ui.InputPasswordFragment;
@ -474,93 +475,22 @@ public class MainActivity extends AppCompatActivity implements
private void handleAutoSettlementIntent(Intent intent) {
if (intent == null) return;
boolean hasPOS = intent.getBooleanExtra("AUTO_SETTLEMENT", false);
boolean hasQR = intent.getBooleanExtra("AUTO_QR_SETTLEMENT", false);
boolean hasAutoSettle = intent.getBooleanExtra("AUTO_SETTLEMENT", false);
if (!hasAutoSettle) return;
if (!hasPOS && !hasQR) return;
// Clear immediately so onResume won't re-trigger on next wake
intent.removeExtra("AUTO_SETTLEMENT");
intent.removeExtra("AUTO_QR_SETTLEMENT");
if (hasPOS) {
PayDetail payDetail = (PayDetail) intent.getSerializableExtra("EXTRA_PAY_DETAIL");
if (payDetail != null) {
sharedViewModel.payDetail.setValue(payDetail);
sharedViewModel.settlementType.setValue(SettlementType.NORMAL);
sharedViewModel.transactionsType.setValue(TransactionsType.SETTLEMENT);
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(payDetail.getAmount()));
sharedViewModel.setTransMenu(TransMenu.SETTLEMENT);
sharedViewModel.autoSettle.setValue(true);
try {
navController.navigate(R.id.transactionResultFragment);
navController.navigate(R.id.settlementTransactionFragment);
} catch (Exception e) {
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);
}
}
} else if (hasQR) {
// Only QR settlement, no POS
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);
long qrSaleAmount = intent.getLongExtra("QR_SALE_AMOUNT", 0L);
int qrRefundCount = intent.getIntExtra("QR_REFUND_COUNT", 0);
long qrRefundAmount = intent.getLongExtra("QR_REFUND_AMOUNT", 0L);
long totalAmount = intent.getLongExtra("QR_TOTAL_AMOUNT", 0L);
List<PayDetail> qrTransList = (List<PayDetail>) intent.getSerializableExtra("QR_TRANS_LIST");
SettleData settleData = new SettleData(
qrSaleCount, qrSaleAmount, 0, 0L, qrRefundCount, qrRefundAmount, 0, 0L);
TradeData tradeData = Params.newTrade(false);
PayDetail payDetail = tradeData.getPayDetail();
payDetail.setSettleDataObj(settleData);
payDetail.setTransactionType(TransactionsType.MMQR_SETTLEMENT.value);
payDetail.setTransType(TransactionsType.MMQR_SETTLEMENT.name);
payDetail.setAmount(totalAmount);
payDetail.setTradeAnswerCode("000");
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(totalAmount));
sharedViewModel.payDetails.setValue(qrTransList);
sharedViewModel.payDetail.setValue(payDetail);
sharedViewModel.transactionsType.setValue(TransactionsType.MMQR_SETTLEMENT);
try {
navController.navigate(R.id.transactionResultFragment);
} catch (Exception e) {
LogUtil.e(TAG, "QR Auto Settlement navigation error: " + e.getMessage());
}
}
@Override

View File

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

View File

@ -132,6 +132,8 @@ public class SharedViewModel extends ViewModel {
public MutableLiveData<Boolean> _manualEntryStatus = new MutableLiveData<>();
public MutableLiveData<Boolean> autoSettle = new MutableLiveData<>(false);
public MutableLiveData<Boolean> fullVoidPreauthStatus = new MutableLiveData<>();
public MutableLiveData<Boolean> partialVoidPreauthStatus = new MutableLiveData<>();

View File

@ -529,6 +529,17 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
safeNavigateToRouteId();
}
private void performAutoSettle() {
if (isUSDSettleNeeded()) {
currencySelectionHelper.applyCardCurrencyAndHost("USD");
settlementViewModel.startSettlementProcess(usdBucket, false);
} else {
currencySelectionHelper.applyCardCurrencyAndHost("MMK");
settlementViewModel.startSettlementProcess(mmkBucket, true);
}
showLoadingDialog("Sending ...");
}
private boolean isUSDSettleNeeded() {
return (usdBucket.saleCount != 0 || usdBucket.preCount != 0 || usdBucket.refundCount != 0 || usdBucket.caCount != 0);
}
@ -565,6 +576,13 @@ public class SettlementTransactionFragment extends DataBindingFragment implement
settlementViewModel.settlementType.setValue(sharedViewModel.settlementType.getValue());
settlementViewModel.isNoData.observe(getViewLifecycleOwner(), noData -> {
if (Boolean.TRUE.equals(sharedViewModel.autoSettle.getValue()) && noData == false) {
sharedViewModel.autoSettle.setValue(false);
delayFunctionCall(this::performAutoSettle);
}
});
settlementViewModel.resultString.observe(getViewLifecycleOwner(), transactionStatus -> {
switch (transactionStatus) {
case ON_BATCH_UPLOAD:

View File

@ -460,7 +460,7 @@ public class TMSSetupsImpl implements TMSSetups{
SystemParamsOperation.getInstance().setRandomPinPad(parseBoolean(data));
} else if (TextUtils.equals(name,"clear_batch_time")) {
SystemParamsOperation.getInstance().setClearBatchTime(data);
SystemParamsOperation.getInstance().setClearBatchTime("00:00");
} else if (TextUtils.equals(name,"alert_sound_enable")) {
SystemParamsOperation.getInstance().setAlertSound(parseBoolean(data));