From ff65559b4c93a4a36305019b9b28e0f6ec303b9d Mon Sep 17 00:00:00 2001 From: sky121113 Date: Mon, 15 Jun 2026 16:18:11 +0800 Subject: [PATCH] =?UTF-8?q?[FEAT]=20=E9=9B=BB=E5=AD=90=E7=99=BC=E7=A5=A8?= =?UTF-8?q?=E6=94=B9=E7=94=B1=E5=BE=8C=E5=8F=B0=E9=96=8B=E7=AB=8B=EF=BC=9A?= =?UTF-8?q?=E6=A9=9F=E5=8F=B0=E5=8F=AA=E9=9A=A8=20finalize=20=E4=B8=8A?= =?UTF-8?q?=E5=A0=B1=E7=99=BC=E7=A5=A8=E8=BC=B8=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. TransactionFinalizePayload 新增 InvoicePayload 物件(status/amount/carrier_id/business_tax_id/love_code 等),讓 finalize 一併帶上發票開立輸入。 2. TransactionFinalizeBuilder:有發票需求(invoiceInfo 非空)時,從 InvoiceData 組發票輸入並固定 status=pending 帶進 finalize;機台不再判定開立結果。 3. DispatchDialog:移除機台直連綠界開票,改為進出貨流程僅上報;發票由後台收到 finalize 後建 pending 並去綠界開立(避免機台網路不確定性與等待)。 4. ReportInvoiceInfoStructure:保留 relateNumber 欄位(冪等鍵相關)。 5. 開票邏輯不放在即將淘汰的 HttpAPI(先前暫放 StarCloudAPI 的機台開票方法亦已移除)。 Co-Authored-By: Claude Opus 4.8 (1M context) --- .../structure/ReportInvoiceInfoStructure.java | 11 +++ .../mqtt/TransactionFinalizePayload.java | 76 +++++++++++++++++++ .../tools/TransactionFinalizeBuilder.java | 23 ++++++ .../smartdevice/ui/dialog/DispatchDialog.java | 4 + 4 files changed, 114 insertions(+) diff --git a/app/src/main/java/com/unibuy/smartdevice/structure/ReportInvoiceInfoStructure.java b/app/src/main/java/com/unibuy/smartdevice/structure/ReportInvoiceInfoStructure.java index 188cdff..90e5a70 100644 --- a/app/src/main/java/com/unibuy/smartdevice/structure/ReportInvoiceInfoStructure.java +++ b/app/src/main/java/com/unibuy/smartdevice/structure/ReportInvoiceInfoStructure.java @@ -8,6 +8,9 @@ public class ReportInvoiceInfoStructure { String invoiceDate; String randomNumber; String loveCode; + // 綠界 RelateNumber(冪等鍵,= machineID + flow_id)。由 DispatchDialog 開票前產生, + // 開票請求與 finalize 上報共用同一值,後台據此查詢/補開避免重複開立。 + String relateNumber = ""; public ReportInvoiceInfoStructure(String reportFlowId, String rtnCode, String rtnMsg, String invoiceNo, String invoiceDate, String randomNumber, String loveCode) { this.reportFlowId = reportFlowId; @@ -75,6 +78,14 @@ public class ReportInvoiceInfoStructure { this.loveCode = loveCode; } + public String getRelateNumber() { + return relateNumber; + } + + public void setRelateNumber(String relateNumber) { + this.relateNumber = relateNumber; + } + @Override public String toString() { return "ReportInvoiceInfoStructure{" + diff --git a/app/src/main/java/com/unibuy/smartdevice/structure/mqtt/TransactionFinalizePayload.java b/app/src/main/java/com/unibuy/smartdevice/structure/mqtt/TransactionFinalizePayload.java index f3d10bf..df517f7 100644 --- a/app/src/main/java/com/unibuy/smartdevice/structure/mqtt/TransactionFinalizePayload.java +++ b/app/src/main/java/com/unibuy/smartdevice/structure/mqtt/TransactionFinalizePayload.java @@ -35,6 +35,14 @@ public class TransactionFinalizePayload { /** 每個貨道的出貨結果列表 */ private List dispense; + /** + * 電子發票開立結果(選填)。 + * 機台在進入出貨流程時平行向綠界開立,結果折進此物件隨 finalize 一起上報; + * 若開票尚未回應則 status=pending,後台依 relate_number 去綠界查詢/補開。 + * 無發票需求(未帶發票資訊)時此欄為 null,後台不建立發票。 + */ + private InvoicePayload invoice; + // =========== Getters & Setters =========== public String getAction() { @@ -82,6 +90,74 @@ public class TransactionFinalizePayload { this.dispense = dispense; } + public InvoicePayload getInvoice() { + return invoice; + } + + public void setInvoice(InvoicePayload invoice) { + this.invoice = invoice; + } + + // =========== 內部類別:電子發票開立結果 =========== + + public static class InvoicePayload { + /** 開立狀態:issued(已開)/ pending(已送出未回應)/ failed(綠界回失敗) */ + private String status; + /** 綠界 RelateNumber(= machineID + flow_id),後台查詢/補開用 */ + private String relate_number; + /** 發票號碼(pending/failed 時為空) */ + private String invoice_no; + /** 綠界回應碼(1=成功) */ + private String rtn_code; + /** 綠界回應訊息 */ + private String rtn_msg; + /** 發票開立日期 */ + private String invoice_date; + /** 隨機碼 */ + private String random_number; + /** 愛心碼(捐贈時) */ + private String love_code; + /** 載具號碼 */ + private String carrier_id; + /** 統一編號(B2B 統編,有打統編時) */ + private String business_tax_id; + /** 發票金額 */ + private int amount; + + public String getStatus() { return status; } + public void setStatus(String status) { this.status = status; } + + public String getRelate_number() { return relate_number; } + public void setRelate_number(String relate_number) { this.relate_number = relate_number; } + + public String getInvoice_no() { return invoice_no; } + public void setInvoice_no(String invoice_no) { this.invoice_no = invoice_no; } + + public String getRtn_code() { return rtn_code; } + public void setRtn_code(String rtn_code) { this.rtn_code = rtn_code; } + + public String getRtn_msg() { return rtn_msg; } + public void setRtn_msg(String rtn_msg) { this.rtn_msg = rtn_msg; } + + public String getInvoice_date() { return invoice_date; } + public void setInvoice_date(String invoice_date) { this.invoice_date = invoice_date; } + + public String getRandom_number() { return random_number; } + public void setRandom_number(String random_number) { this.random_number = random_number; } + + public String getLove_code() { return love_code; } + public void setLove_code(String love_code) { this.love_code = love_code; } + + public String getCarrier_id() { return carrier_id; } + public void setCarrier_id(String carrier_id) { this.carrier_id = carrier_id; } + + public String getBusiness_tax_id() { return business_tax_id; } + public void setBusiness_tax_id(String business_tax_id) { this.business_tax_id = business_tax_id; } + + public int getAmount() { return amount; } + public void setAmount(int amount) { this.amount = amount; } + } + // =========== 內部類別:訂單資訊 =========== public static class OrderPayload { diff --git a/app/src/main/java/com/unibuy/smartdevice/tools/TransactionFinalizeBuilder.java b/app/src/main/java/com/unibuy/smartdevice/tools/TransactionFinalizeBuilder.java index 71885d6..fab5ca3 100644 --- a/app/src/main/java/com/unibuy/smartdevice/tools/TransactionFinalizeBuilder.java +++ b/app/src/main/java/com/unibuy/smartdevice/tools/TransactionFinalizeBuilder.java @@ -5,6 +5,7 @@ import android.util.Log; import com.unibuy.smartdevice.MyApp; import com.unibuy.smartdevice.structure.BuyStructure; +import com.unibuy.smartdevice.structure.InvoiceStructure; import com.unibuy.smartdevice.structure.ReportFlowInfoStructure; import com.unibuy.smartdevice.structure.mqtt.TransactionFinalizePayload; @@ -59,6 +60,10 @@ public class TransactionFinalizeBuilder { this.flowId = flowId; } + public String getFlowId() { + return flowId; + } + public void setOrderNo(String orderNo) { this.orderNo = orderNo; } @@ -133,6 +138,24 @@ public class TransactionFinalizeBuilder { // --- 出貨記錄 --- payload.setDispense(new ArrayList<>(dispenseRecords)); + // --- 電子發票(改由後台開立)--- + // 機台不開票,只把「開立輸入」(載具/愛心碼/統編/金額)帶上去,狀態固定 pending; + // 後台建 pending 發票後派 Job 去綠界開立。無發票需求(invoiceInfo 為空)時不帶,後台不建立發票。 + if (flowInfo.getInvoiceInfo() != null && !flowInfo.getInvoiceInfo().isEmpty()) { + TransactionFinalizePayload.InvoicePayload invoicePayload = + new TransactionFinalizePayload.InvoicePayload(); + invoicePayload.setStatus("pending"); + invoicePayload.setAmount(flowInfo.getTotalPrice()); + + InvoiceStructure invoiceData = MyApp.getInstance().getInvoiceData(); + if (invoiceData != null) { + invoicePayload.setCarrier_id(invoiceData.getCarrier()); + invoicePayload.setBusiness_tax_id(invoiceData.getCustomerIdentifier()); + invoicePayload.setLove_code(invoiceData.getLoveCode()); + } + payload.setInvoice(invoicePayload); + } + Log.i(TAG, "TransactionFinalizePayload built: flow_id=" + flowId + ", order_no=" + order.getOrder_no() + ", items=" + order.getItems().size() diff --git a/app/src/main/java/com/unibuy/smartdevice/ui/dialog/DispatchDialog.java b/app/src/main/java/com/unibuy/smartdevice/ui/dialog/DispatchDialog.java index dc34eb9..6ddb946 100644 --- a/app/src/main/java/com/unibuy/smartdevice/ui/dialog/DispatchDialog.java +++ b/app/src/main/java/com/unibuy/smartdevice/ui/dialog/DispatchDialog.java @@ -262,6 +262,10 @@ public class DispatchDialog extends DialogAbstract { MyApp.getInstance().getReportFlowInfoData().setFlowType(42); } + // [MQTT Finalize 重構] 電子發票改由「後台」開立:機台不再直連綠界, + // 僅把發票輸入(載具/愛心碼/統編/金額)隨 finalize 的 invoice 物件上報(TransactionFinalizeBuilder 組裝)。 + // 後台收到 finalize 後建 pending 發票並派 Job 去綠界開立,避免機台網路不確定性與等待。 + MyApp.getInstance().setReportFreeGiftCodeStructure(new ReportFreeGiftCodeStructure("", 0, "", 0, 0, "")); getLogs().info("BuyList size:" + MyApp.getInstance().getBuyList().size());