|
@@ -118,3 +118,137 @@ ezPay `Amt`=销售额、`TaxAmt`=税额、`TotalAmt`=含税总额,三者满足
|
|
|
- 否则(`Status != SUCCESS` 或含 KEY1/INV/LIB 错误前缀)→ 失败,记 `Message` 到 `fail_reason`,状态置失败,订单不变。
|
|
- 否则(`Status != SUCCESS` 或含 KEY1/INV/LIB 错误前缀)→ 失败,记 `Message` 到 `fail_reason`,状态置失败,订单不变。
|
|
|
|
|
|
|
|
**Rationale**: 与 009 凭证验证(看 KEY1)不同,开立以 `Status=SUCCESS` 为准。错误前缀见记忆规格(KEY1 加解密 / INV 发票业务 / LIB 重复状态 / NOR 网络)。
|
|
**Rationale**: 与 009 凭证验证(看 KEY1)不同,开立以 `Status=SUCCESS` 为准。错误前缀见记忆规格(KEY1 加解密 / INV 发票业务 / LIB 重复状态 / NOR 网络)。
|
|
|
|
|
+
|
|
|
|
|
+## D10. 管理后台「发票明细」展示范围(不复制 ezPay 控制台)
|
|
|
|
|
+
|
|
|
|
|
+**Decision**: 后台发票明细页**只展示「开票成功已落库信息 + 订单信息」**,不复制截图(ezPay 商家后台控制台)的完整布局。展示字段集:
|
|
|
|
|
+
|
|
|
|
|
+| 区块 | 字段 | 来源 |
|
|
|
|
|
+|------|------|------|
|
|
|
|
|
+| 发票核心 | 发票号码、防伪随机码、发票种类(B2B/B2C)、开立时间、发票状态 | `pos_order_invoice` |
|
|
|
|
|
+| 买方 | 买方名称、买方统编(B2B)、接收邮箱、载具类型+号码 | `pos_order_invoice` |
|
|
|
|
|
+| 金额 | 销售额、税额、含税总额 | `pos_order_invoice` |
|
|
|
|
|
+| 商品明细 | 品名、数量、单位、单价、小计 | 开票时存 `ItemDetail` JSON 或重新解析 `pos_order.food` |
|
|
|
|
|
+
|
|
|
|
|
+**不展示**(截图有、本期不做):卖方营业名称/统编/会员编号、上传状态、中奖注记、目前可折让金额、折让单号、通知表、BarCode/QRcode、Kiosk列印、报关标记、发票备注。
|
|
|
|
|
+
|
|
|
|
|
+**Rationale**:
|
|
|
|
|
+- 截图是 **ezPay 自己的商家后台控制台**,服务于营业人管理发票全生命周期(折让/中奖/上传/通知),信息密度对我们平台运营是噪音。
|
|
|
|
|
+- 卖方信息冗余:运营按订单/门店 scoped 进明细页,卖方上下文已知。
|
|
|
|
|
+- 上传状态/中奖/折让/通知:要么 `invoice_search` 不返回(中奖/可折让/通知),要么低价值(上传状态隔日才更新),要么需额外基础设施。
|
|
|
|
|
+- 结果:**明细页纯本地查询,不调 `invoice_search`**,秒开、不依赖 ezPay 可用性。
|
|
|
|
|
+
|
|
|
|
|
+**Alternatives**: 完整复制控制台 → 需调 `invoice_search` + 折让/中奖额外接口,且多个关键字段拿不到,过度设计,不采用。
|
|
|
|
|
+
|
|
|
|
|
+**已定(暂不存 ItemDetail)**:当前明细页(`selectInvoiceDetail` → `PosOrderInvoiceVo`)不展示逐商品行项,故无需存。日后若明细页要展示商品明细,再考虑开票时存一份(避免优惠按比例分摊后、行项与总额对不上)。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## D11. ezPay 不返回发票图/URL;`invoice_url` 是空壳字段
|
|
|
|
|
+
|
|
|
|
|
+**Finding**: 核实官方手册 `EZP_INVI_1.2.1`——开立(`invoice_issue`)与查询(`invoice_search`)回应**均不含任何发票图片/PDF/URL 字段**。开立回应实际只返回:
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+MerchantID / InvoiceTransNo / MerchantOrderNo / TotalAmt / InvoiceNumber / RandomNum
|
|
|
|
|
+CreateTime / CheckCode / BarCode / QRcodeL / QRcodeR (后三个仅 PrintFlag=Y 时返回)
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**Consequence & 处置(2026-06-22 已落地)**:原 `invoice_url` 确属空壳(ezPay issue/search 回应均不返回 URL/图片)。团队已按「改存 ezPay 真返回码值」处理:`invoice_url` 改名为 `invoice_trans_no`(InvoiceTransNo),新增 `invoice_bar_code`/`invoice_qrcode_l`/`invoice_qrcode_r`(PrintFlag=Y 时 ezPay 返回的 BarCode/QRcodeL/R)。已核实实体 `PosOrderInvoice` + `OrderInvoiceService.applyInvoice`/`reIssueAndSave` 均从 issue 回应取值落库;`data-model.md` 已同步。明细页「凭证/链接」一行 → 改展示发票号/随机码/交易流水号。
|
|
|
|
|
+
|
|
|
|
|
+**客户查看发票的三条路径**(能否给可点链接见 D12,能否打印见 D13):
|
|
|
|
|
+
|
|
|
|
|
+| 方式 | 机制 | 我们能否给可点链接 |
|
|
|
|
|
+|------|------|--------------------|
|
|
|
|
|
+| 邮箱(无载具) | 开票填 `BuyerEmail` → ezPay 自动发通知邮件,发票在邮件里 | ❌ 邮件由 ezPay 发、链接用平台密钥,复刻不了(D12) |
|
|
|
|
|
+| 载具 | 选手机条码/自然人凭证/ezPay会员载具 → 票存进载具 → 客户自己去财政部/ezPay 查(见「附:载具概念」) | ❌ 票在客户账户,我们只存发票号 |
|
|
|
|
|
+| 都不填(PrintFlag=Y) | 无自动送达渠道,票只在 ezPay/财政部平台,商家需手动打印交付 | ❌ 且外卖场景建议禁用此模式(见下) |
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 「都不填」模式建议禁用**:客户远程收餐无法当面递纸票,而该模式 ezPay 不发邮件、不进载具,票「悬空」、客户拿不到。建议 B2C 开票强制「邮箱 或 载具 至少填一个」,顺带消除 `contracts/api.md` 那条「ezPay 是否接受空 BuyerEmail」的待验证项。B2B 不受影响(PrintFlag=Y、靠统编报账)。
|
|
|
|
|
+
|
|
|
|
|
+> 订正:本节早先版本写过「均无静态链接可存」,过于绝对——准确结论见 D12(邮件链接不可复刻,但 `DisplayFlag=1` 查询链接可用商户密钥生成)。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## D12. 发票「查看链接」能否自动生成(邮件链接 vs DisplayFlag=1)
|
|
|
|
|
+
|
|
|
|
|
+**背景**:客户收到的邮件里有一个 `https://cinv.ezpay.com.tw/invoice_index/search_platform?PostData=<密文>` 链接,点开即展示发票。问:我们能否自己生成同类链接?
|
|
|
|
|
+
|
|
|
|
|
+**结论**:**邮件那个链接复刻不了;但 `/Api/invoice_search` + `DisplayFlag=1` 这条我们能生成。**
|
|
|
|
|
+
|
|
|
|
|
+| 链接来源 | 加密密钥 | 我们能生成 | 效果 |
|
|
|
|
|
+|----------|----------|------------|------|
|
|
|
|
|
+| 邮件 `invoice_index/search_platform` | ezPay **平台**密钥(推测) | ❌ 不能 | GET URL,点开展示发票 |
|
|
|
|
|
+| `/Api/invoice_search` + `DisplayFlag=1` | **商户** HashKey/HashIV | ✅ 能 | Form POST 跳 ezPay 页面展示发票 |
|
|
|
|
|
+
|
|
|
|
|
+**验证(邮件链接不可复刻)**:邮件 PostData = 96 字节 = 3×32 块(ezPay AES block-32 格式特征)。用商户密钥(`J3ln4b6axMafUE1HMTF3boeqTCoD5Ia5` / `CgabhUpEbwpoATlP`)解密 → 高熵乱码(96 字节仅 37 个可打印 ASCII,pad=42 非法),CBC/ECB/零IV 三种变体可打印率均低;AES-CBC round-trip 自检通过 → **证明商户密钥解不开,邮件链接用的是另一把(平台)密钥**。
|
|
|
|
|
+
|
|
|
|
|
+**可生成路径(DisplayFlag=1)**:手册第八章,`invoice_search` 带 `DisplayFlag=1` 时 ezPay「以網頁顯示發票查詢結果」。明文示例:
|
|
|
|
|
+```
|
|
|
|
|
+RespondType=JSON&Version=1.3&TimeStamp=<ts>&SearchType=0
|
|
|
|
|
+&InvoiceNumber=<发票号>&RandomNum=<随机码>&DisplayFlag=1
|
|
|
|
|
+```
|
|
|
|
|
+用 `EzPayEncryptUtil.encrypt` + 商户密钥加密 → Form POST `MerchantID_`+`PostData_` 到 `/Api/invoice_search`。
|
|
|
|
|
+
|
|
|
|
|
+**落地形态**:是 **Form POST 不是 GET URL**,没法存成超链接直接发。方案:点「查看发票」时后端即时生成 PostData(TimeStamp 现生成、防过期)→ 返回自动提交的小页 → 跳 ezPay 展示。密钥留后端,前端只拿 URL。
|
|
|
|
|
+
|
|
|
|
|
+**⚠️ 待实测确认**(已生成测试表单 `%TEMP%\ezpay_view_test.html`,用测试票 `DK00000003/5071` + 商户密钥):
|
|
|
|
|
+1. 点开是否正常展示发票(不报错);
|
|
|
|
|
+2. 落地页是否与邮件链接同页/相似;
|
|
|
|
|
+3. 是否要求登 ezPay(决定能否当客户-facing 链接)。
|
|
|
|
|
+若要求登录或失效 → 此路仅限内部/商家用,客户-facing 仍走邮箱/载具。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## D13. 发票打印:无 API/模板 + B2C 列印限制 + 交付路径
|
|
|
|
|
+
|
|
|
|
|
+**来源**:官方手册 4 份 + ezPay QA 页(`cinv.ezpay.com.tw/Invoice_index/qa`)。
|
|
|
|
|
+
|
|
|
|
|
+**结论:ezPay 不提供打印 API、无可下载模板、无发票图片/PDF 接口。「拿样票装数据打印」这条路不存在。**
|
|
|
|
|
+
|
|
|
|
|
+**打印的实际形态(QA 第八章「列印發票作業」)**:
|
|
|
|
|
+- **纯手动后台操作**:商家登 ezPay 后台「列印電子發票」→ 勾选 → 点列印 → **输入登入密码** → 生成 PDF。非 API。
|
|
|
|
|
+- **B2C 列印 1 次限制(財政部規定)**:非首次列印必须加註「補印」,否则责任商家自负。
|
|
|
|
|
+- **B2C 买方不能列印**:平台「僅供買受人查詢發票資訊,無法提供買受人列印服務」(防重复兑奖)。B2B 买方可在「電子發票查詢專區」凭发票号/日期/随机码列印證明聯。
|
|
|
|
|
+- **「樣張」≠模板**:QA 第二章「發票證明聯樣張」是商家在测试区开票后用「熱感列印」产出的 PDF,用于**字轨申请交国税局**——是打印**输出**,非可填充的**输入模板**。数据开票时已存 ezPay,打印只渲染 ezPay 内数据。
|
|
|
|
|
+
|
|
|
|
|
+**前端实现现状(平台后台 orderInvoice 详情页)**:详情页对已开票会渲染发票防伪码——用存的 `invoiceBarCode/QRcodeL/R`(ezPay 开立回应返回、PrintFlag=Y 才有)画出二维码+条码供**查看**;已去掉下载 PNG / 打印按钮(避免 D13 担心的自行打印/補印合规风险)。
|
|
|
|
|
+- 因「B2C 必填载具 → PrintFlag=N」(见 D11),**B2C 票无码值** → 详情显示「已存入载具,无纸本凭证」,不画码。
|
|
|
|
|
+- **仅 B2B(PrintFlag=Y)**有码值 → 渲染 QR/条码展示。B2B 无法规列印次数限制,码值为 ezPay 官方防伪码,仅展示、不打印,合规。
|
|
|
|
|
+- 结论:自渲染**展示**可接受(只读、B2B 限定);自渲染**打印/下载**已移除。原 D13「不建议自行渲染打印」订正为此。
|
|
|
|
|
+
|
|
|
|
|
+**发票交付的现实路径(就这三条,无「自己打印」)**:
|
|
|
|
|
+
|
|
|
|
|
+| 场景 | 怎么把发票给到人 | 谁操作 |
|
|
|
|
|
+|------|------------------|--------|
|
|
|
|
|
+| B2C | 邮箱(ezPay 发邮件)/ 载具(客户去财政部·ezPay 查) | ezPay 自动 / 客户自取 |
|
|
|
|
|
+| B2B | 商家在 ezPay 后台手动印 PDF 交买方;或买方在查询专区自印 | 商家 / 买方 |
|
|
|
|
|
+| B2C 中奖票 | 商家中奖后在 ezPay 后台印熱感紙證明聯给买方兑奖 | 商家手动 |
|
|
|
|
|
+
|
|
|
|
|
+**对外卖平台的落地建议**:B2C 走邮箱/载具送达(不需、也不能随便打印);B2B 打印让商家去 ezPay 后台做(或我们做个「跳转 ezPay 后台」快捷入口,印的动作仍在 ezPay)。平台自渲染/打印发票不建议做。
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## 附:载具(Carrier)业务概念(参考)
|
|
|
|
|
+
|
|
|
|
|
+**载具 = 电子发票的「钱包/账户」。** 发票不印纸、不发文件,而是像存钱一样「存」进客户的某个发票账户;客户看的不是「一张票」,而是「去自己账户翻这笔记录」。
|
|
|
|
|
+
|
|
|
|
|
+- **纸质发票**:商家印纸给你,票在手上(物理持有)。
|
|
|
|
|
+- **载具发票**:商家不给任何东西,把发票数据上报财政部电子发票平台、打上「属于载具号 XXX」标记;票以记录形式躺在该载具名下。
|
|
|
|
|
+
|
|
|
|
|
+ezPay `Category=B2C` 三种载具(`CarrierType`):
|
|
|
|
|
+
|
|
|
|
|
+| 载具 | 号码 | 票存于 |
|
|
|
|
|
+|------|------|--------|
|
|
|
|
|
+| `0` 手机条码 | `/ABC1234`(/开头) | 财政部电子发票平台,绑手机 |
|
|
|
|
|
+| `1` 自然人凭证 | `2字母+14数字` | 财政部平台,绑身份证 |
|
|
|
|
|
+| `2` ezPay会员载具 | ezPay会员号(如截图 `C1597…`) | ezPay 系统 |
|
|
|
|
|
+
|
|
|
|
|
+- **「存进载具」**:票上报到财政部/ezPay 平台、标记归属某载具号;选载具则 `PrintFlag=N`(不打印)。
|
|
|
|
|
+- **「客户自己去查」**:票存在财政部/ezPay、不在我们手里,我们只存了发票号、给不出票图。客户须登票据所在地查看:手机条码/自然人凭证 → 财政部电子发票整合服务平台(einvoice.nat.gov.tw)或「财政部发票夹」App;ezPay会员载具 → ezPay App/网站。
|
|
|
|
|
+- **连带好处(中奖)**:用载具的票,开奖时财政部自动比对、奖金拨入载具绑定账户,客户无需持纸票兑奖——这也是台湾主推载具的原因。
|
|
|
|
|
+
|
|
|
|
|
+> 一句话:载具=客户在政府/ezPay 的「发票账户」;存进载具=票打进该账户;自己去查=客户登该账户才能看到票。这是明细页「无发票链接可显示」的根本原因。
|
|
|
|
|
+
|
|
|
|
|
+### 补充:查询发票明细接口(invoice_search)能力备忘
|
|
|
|
|
+
|
|
|
|
|
+ezPay **有**查询发票明细的接口 `/Api/invoice_search`(v1.3),工具类已封装 `EzPay.searchInvoice(baseUrl, cfg, invoiceNumber, randomNum)`(`ruoyi-admin/.../utils/ezPay/EzPay.java`),按 D10 决策本期业务层不调用它。其回应字段(手册第八章)覆盖:MerchantID/InvoiceTransNo/MerchantOrderNo/InvoiceNumber/RandomNum/BuyerName/BuyerUBN/BuyerAddress/BuyerPhone/BuyerEmail/InvoiceType/Category/TaxType/TaxRate/Amt(含AmtSales/Zero/Free)/TaxAmt/TotalAmt/CarrierType/CarrierNum/LoveCode/PrintFlag/KioskPrintFlag/CreateTime/ItemDetail(JSON)/InvoiceStatus/UploadStatus/CheckCode/BarCode/QRcodeL/QRcodeR。**注意**:中奖注记、目前可折让金额、通知状态、折让单号该接口**不返回**(属 ezPay 控制台聚合 / 折让接口范畴)。日后若需「确认上传状态」等 live 字段再启用此接口。
|