data-model.md 4.1 KB

Phase 1 Data Model: 订单 ezPay 电子发票开立

Date: 2026-06-16

新增表:pos_order_invoice(订单电子发票,与 pos_order 1:1)

DDL 写入 updatesql/sql.md,由开发者手动执行(项目规范)。当前态表:一笔订单至多一行;作废后状态置「作废」、允许重开(同行覆盖,MVP 不留历史明细)。

字段 类型 说明
id BIGINT PK AUTO 主键
order_id BIGINT NOT NULL 关联 pos_order.id(UNIQUE)
order_no VARCHAR(64) 冗余 pos_order.ddId,便于排查
store_id BIGINT NOT NULL 冗余 pos_order 所属门店 id(关联 pos_store.id
invoice_category VARCHAR(8) 发票类型:B2C / B2B
buyer_name VARCHAR(100) 买方名称(B2C=客户名/邮箱名,B2B=公司名)
buyer_ubn VARCHAR(16) 买方统一编号(统编 8 码,B2B 必填)
buyer_email VARCHAR(200) 接收邮箱(B2C 无载具时用)
carrier_type VARCHAR(8) 载具类型:0手机条码/1自然人凭证/2ezPay会员载具(可空)
carrier_num VARCHAR(64) 载具号码(carrier_type 非空时必填)
invoice_number VARCHAR(16) ezPay 发票号(开立成功后填,字轨号段分配)
random_num VARCHAR(8) 防伪随机码(ezPay 返回)
invoice_status TINYINT NOT NULL DEFAULT 0 0未开 / 1已开 / 2失败 / 3作废
total_amt INT 含税总额(= 订单实付 amount)
sales_amt INT 销售额(未税,= round(total/1.05))
tax_amt INT 税额(= total - sales)
fail_reason VARCHAR(500) 开票/作废失败原因
invoice_url VARCHAR(500) 发票查看凭证 / 链接
apply_time DATETIME 客户申请开票时间
issue_time DATETIME 开立成功时间
invalid_time DATETIME 作废时间
create_time DATETIME 创建时间
update_time DATETIME 更新时间
create_by VARCHAR(64) 创建人
update_by VARCHAR(64) 更新人

索引

  • UNIQUE KEY uk_order_id (order_id) —— 防重复开票(D5)
  • KEY idx_status (invoice_status)
  • KEY idx_store (store_id)

状态机(invoice_status)

        开票成功              作废(ezPay invalid 成功)
  ┌─────────────────┐   ┌──────────────────┐
  ▼                 │   ▼                  │
[0 未开] ──成功──> [1 已开] ──作废──> [3 作废]
  │                 │
  │ 失败            │ 失败
  ▼                 ▼
[2 失败] <──重试─── (失败/作废/未开 均可重试开票)
  └──重试成功──> [1 已开]
  • 开票前置:invoice_status ∈ {0 未开, 2 失败, 3 作废} 才允许发起开票;1 已开 拒绝(FR-005)。
  • 重开:作废(3) 后可再次开票 → 状态先置 0、再走开票成功置 1(同行,新 invoice_number 覆盖旧号)。

复用实体(不改)

  • PosOrderpos_order):开票来源。取 id/ddId/amount/food/state(=3 完成)/payStatus(=1)/门店归属(shId/mdId)。门店 id 判定:依据 CLAUDE.md 商家类型口径(普通/夜市商家用 shId,摊位用 mdId)对齐 pos_store
  • PosStoreEzpay(009,pos_store_ezpay):开票凭证来源。仅 ezpayStatus=2 且 isEnabled=1 的门店可开票;取 merchantId/hashKey/hashIv 构造 EzPayConfig
  • PosStorepos_store):invoice_exempt=1 的门店不提供开票(009)。

金额拆分(开票时计算,不入订单表)

按 research D1(不含运费,订单构成 amount = foodAmount − 优惠 + freight):

invoice_total = amount - freight            // 商品实付(已扣优惠、不含运费)
total_amt     = invoice_total               // 含税总额
sales_amt     = round(invoice_total / 1.05) // 销售额未税
tax_amt       = total_amt - sales_amt       // 税额

逐商品明细由 food JSON 组装(D2),优惠按比例分摊到各商品使 ΣItemAmt = total_amt(D3);运费不进发票。