[FIX] 修復掃碼支付(玉山)結案前購物車被清空導致「無商品紀錄」
1. 根因:order.items 在結案 build() 當下才即時讀 live buyList,掃碼支付(玉山)流程較慢(掃碼+玉山API約20s),結案前 buyList 會被取消/倒數路徑清空,造成 order.items 變空陣列(無商品紀錄),但出貨其實成功(dispense 有商品)。 2. TransactionFinalizeBuilder 新增 itemsSnapshot 商品明細快照欄位與 captureItems() 方法;buyList 為空時不覆寫既有快照。 3. 抽出共用 buildItemRecords() helper,captureItems() 與 build() fallback 共用。 4. build()/buildOrderPayload() 改為優先採用快照,無快照時才 fallback 讀 live buyList。 5. DispatchDialog onCreate 建立 finalizeBuilder 後立即 captureItems(),此時 buyList 必完整。 6. 升版 verPatch 95 → 96 (S9XYU versionName 21_01_96_R / versionCode 210196)。 正常情況快照==live,逐字等價;僅在 buyList 被清空的 bug 情境修正。純 App 端,不影響後台與線上 main。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
89c7d04f7a
commit
c7bc554eca
@ -10,7 +10,7 @@ plugins {
|
||||
// 避免不同尺寸機台間版本號產生衝突。
|
||||
// =========================================================================
|
||||
def verMinor = 1
|
||||
def verPatch = 94
|
||||
def verPatch = 96
|
||||
|
||||
|
||||
|
||||
|
||||
@ -47,6 +47,14 @@ public class TransactionFinalizeBuilder {
|
||||
/** 累積的出貨結果清單 */
|
||||
private final List<TransactionFinalizePayload.DispenseRecord> dispenseRecords = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 商品明細快照。在「buyList 仍完整」時擷取(例如進入出貨流程當下);
|
||||
* 之後 build() 會優先採用此快照,不再即時讀 live buyList。
|
||||
* 用以修正掃碼支付(玉山)等較慢流程:結案前 buyList 可能被取消/倒數路徑清空,
|
||||
* 導致 order.items 變成空陣列(出現「無商品紀錄」),但出貨其實成功。
|
||||
*/
|
||||
private List<TransactionFinalizePayload.ItemRecord> itemsSnapshot = null;
|
||||
|
||||
private String codeId = "0";
|
||||
|
||||
/** 交易生命週期狀態(pending/completed/failed/abandoned);預設 completed 維持成功路徑原行為。 */
|
||||
@ -151,6 +159,42 @@ public class TransactionFinalizeBuilder {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 擷取目前 buyList 的商品明細快照。
|
||||
* 應在「buyList 仍完整」時呼叫(例如 DispatchDialog 進入出貨流程當下);
|
||||
* 之後 {@link #build()} 會優先採用此快照,不再即時讀 live buyList,
|
||||
* 避免結案前 buyList 被取消/倒數等其他執行緒清空,導致 order.items 變成空陣列。
|
||||
* buyList 為空時不覆寫既有快照(避免把有效快照洗成空)。
|
||||
*/
|
||||
public void captureItems() {
|
||||
List<BuyStructure> buyList = MyApp.getInstance().getBuyList();
|
||||
if (buyList == null || buyList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
this.itemsSnapshot = buildItemRecords(buyList);
|
||||
Log.i(TAG, "captureItems: snapshot " + this.itemsSnapshot.size()
|
||||
+ " item(s), flow_id=" + flowId);
|
||||
}
|
||||
|
||||
/** 由 buyList 組出 items 明細(captureItems 與 build() fallback 共用)。 */
|
||||
private List<TransactionFinalizePayload.ItemRecord> buildItemRecords(List<BuyStructure> buyList) {
|
||||
List<TransactionFinalizePayload.ItemRecord> items = new ArrayList<>();
|
||||
if (buyList != null) {
|
||||
for (BuyStructure buy : buyList) {
|
||||
int productId = 0;
|
||||
try {
|
||||
productId = Integer.parseInt(buy.getProduct().getProductID());
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, "Cannot parse productID to int: " + buy.getProduct().getProductID());
|
||||
}
|
||||
int price = buy.getProduct().getRealPrice();
|
||||
int quantity = buy.getCount() > 0 ? buy.getCount() : 1;
|
||||
items.add(new TransactionFinalizePayload.ItemRecord(productId, price, quantity));
|
||||
}
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加入一筆出貨結果記錄(每個貨道出貨後呼叫一次)。
|
||||
*
|
||||
@ -309,20 +353,13 @@ public class TransactionFinalizeBuilder {
|
||||
order.setMachine_time(orderMachineTime);
|
||||
|
||||
// --- 組裝購買商品清單 (items) ---
|
||||
List<TransactionFinalizePayload.ItemRecord> items = new ArrayList<>();
|
||||
List<BuyStructure> buyList = MyApp.getInstance().getBuyList();
|
||||
if (buyList != null) {
|
||||
for (BuyStructure buy : buyList) {
|
||||
int productId = 0;
|
||||
try {
|
||||
productId = Integer.parseInt(buy.getProduct().getProductID());
|
||||
} catch (NumberFormatException e) {
|
||||
Log.w(TAG, "Cannot parse productID to int: " + buy.getProduct().getProductID());
|
||||
}
|
||||
int price = buy.getProduct().getRealPrice();
|
||||
int quantity = buy.getCount() > 0 ? buy.getCount() : 1;
|
||||
items.add(new TransactionFinalizePayload.ItemRecord(productId, price, quantity));
|
||||
}
|
||||
// 優先採用 captureItems() 在出貨流程開始時擷取的快照;無快照時才即時讀 live buyList。
|
||||
// 快照可避免結案前 buyList 被其他執行緒清空(掃碼支付等慢流程的競態),造成「無商品紀錄」。
|
||||
List<TransactionFinalizePayload.ItemRecord> items;
|
||||
if (itemsSnapshot != null && !itemsSnapshot.isEmpty()) {
|
||||
items = new ArrayList<>(itemsSnapshot);
|
||||
} else {
|
||||
items = buildItemRecords(MyApp.getInstance().getBuyList());
|
||||
}
|
||||
order.setItems(items);
|
||||
|
||||
|
||||
@ -258,6 +258,10 @@ public class DispatchDialog extends DialogAbstract {
|
||||
httpAPI = new HttpAPI(getHandlerMain());
|
||||
// 初始化 Finalize Builder(在支付完成、進入出貨流程時建立)
|
||||
finalizeBuilder = new TransactionFinalizeBuilder();
|
||||
// 進入出貨流程當下 buyList 必為完整(下方即用它組 dispatchList),先擷取商品明細快照。
|
||||
// 之後結案 build() 會優先採用此快照,避免掃碼支付(玉山)等慢流程在結案前 buyList
|
||||
// 被取消/倒數路徑清空,導致 order.items 變空(無商品紀錄)但出貨其實成功。
|
||||
finalizeBuilder.captureItems();
|
||||
if (com.unibuy.smartdevice.AppEntry.isCmuh()) {
|
||||
MyApp.getInstance().getReportFlowInfoData().setFlowType(42);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user