auto-route
This commit is contained in:
parent
2f1466d67b
commit
e613dfa246
@ -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,92 +475,21 @@ 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.transactionsType.setValue(TransactionsType.SETTLEMENT);
|
||||
sharedViewModel.setAmount(POSUtil.getInstance().getDecimalAmountSeparatorFormat(payDetail.getAmount()));
|
||||
|
||||
try {
|
||||
navController.navigate(R.id.transactionResultFragment);
|
||||
} 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);
|
||||
sharedViewModel.settlementType.setValue(SettlementType.NORMAL);
|
||||
sharedViewModel.transactionsType.setValue(TransactionsType.SETTLEMENT);
|
||||
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, "QR Auto Settlement navigation error: " + e.getMessage());
|
||||
LogUtil.e(TAG, "Navigation error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
launchIntent.putExtra("AUTO_SETTLEMENT", true);
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<>();
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user