Files
jcgl-dev/docs/公寓端/12-消费充值与菜品管理.md
zfjia 329e27b515 初始提交:三端设计文档与 dev 代码基线
docs/:系统梳理、架构优化方案、CR-02 三端功能设计修订(含 §15 三端一致性同步与平台统计分析)、公寓端/应用端/平台端分册、公寓统计分析与排名报表、公寓端小步迭代开发计划(IT-0~IT-8)

dev/:RuoYi-Vue-master(后端)与 RuoYi-Vue2-master(前端)官方上游基线,未改动
2026-11-10 13:43:05 +08:00

51 KiB
Raw Permalink Blame History

12 消费、充值与菜品管理

文档编号:docs/公寓端/12。性质:设计稿(Design Only),不是接口契约冻结稿;阶段二契约冻结评审通过后才落 DDL。 落地权威表述:本文件是「人员消费、人员线下充值、公寓菜品管理」三项业务流程的唯一权威表述(CF-01CF-03、表 12-112-34、图 12-112-4);口径裁决、流程增量、施工单与验收登记见 CR-02 §14。 上位依据:docs/10-架构优化方案-三端拆分.md、docs/backend/05-数据模型.md §4 / §6、docs/backend/04-核心业务流程.md §6、docs/设计变更/03-三端功能设计修订(CR-02).md(A-04、CR-C03、表 3-15 LEDGER_OFFLINE、表 3-20 offlineQuota、表 3-30 apt_ledger_offline、F-D)、docs/平台端/01 表 C-1、docs/平台端/03 表 3-7、docs/平台端/04 表 4-9、docs/公寓端/03 表 3-6。 硬约束:跨端仍为 **20 个接口编号(117 + 23~25)、契约 v2-draft、平台不回调公寓;不新增公寓本地业务表(仍 59 张)、不新增跨端编号、不新增 bizType;apt.ledger.local 是公寓本地账务唯一写入模块,platform-ledger 是平台余额主账唯一写入口;金额一律 decimal(12,2) / 字符串两位小数、扣减用负数、禁止浮点。 CR-02 §15 关联(三端一致性 / 统计数据源):本文件仍是三流程唯一权威表述;三端状态映射与数据同步机制以 CR-02 §15 表 3-66 为唯一权威,四能力业务规则 / 交互 / 权限 / 异常三端对照见 §15 表 3-65。平台 docs/平台端/10 以 gyid 分类统计时,本流程 #10 LEDGER_OFFLINE 的拆分字段(allowanceAmount / cashAmount / rechargeChannel)分别供补贴消费与现金充值(计为收入)**取数;评价情况与房间利用周转另由 #13 ARCHIVE 摘要 payload 分组计数提供(docs/公寓端/09 §0 表 C-9)。统计结果不回写本流程任何状态,本端不新增上报接口与 bizType;变更点与影响范围见 CR-02 §15 表 3-63。

表 12-1 文档信息

项 内容
范围 CF-01 人员消费、CF-02 人员线下充值、CF-03 公寓菜品管理;覆盖完整流程、状态流转、数据结构、接口定义(请求 / 响应字段)与异常场景
本端职责 消费终端受理与额度查询、apt.ledger.local 双额度 CAS 扣减、线下充值申请与管理员核对、apt-report #10 上报、食谱只读下发与终端选单
协同端 平台端(platform.ledger 余额主账与日对账、platform.catering 食谱主数据)、应用端(管理员核对入口)
编号规则 功能项 CF-01CF-03;表 表 12-y、图 图 12-y 篇内连续;端内接口 N-48N-58(承接 docs/公寓端/11 N-47);决策点 Q-41Q-45;裁决 CR-C31CR-C35、流程 F-L / F-M / F-N(见 CR-02 §14)
术语 表名一律小写(apartment/db/mysql/*.sql 实际写法),平台库沿用大写存量表名;枚举全大写下划线;时间统一 ts_ms / ISO-8601 带时区

表 12-2 修订记录

版本 日期 修订内容
v1.0 2026-11-10 首次形成:三项流程端到端说明、四条状态链、双额度扣减规则、复用表与补列结构、N-48N-58 请求 / 响应字段、#10 LEDGER_OFFLINE 扩展字段、异常与权限、Q-41Q-45 与验收要点;明确"仅线下充值、扫码非支付"与"远程点菜仅预留入口"

1. 定位与边界

1.1 三项流程与三端职责

表 12-3 流程、主体与落点

功能项 用户动作 主责端 / 模块 协同端 主要落表 跨端编号
CF-01 人员消费 食堂选餐 → 消费终端添加菜品显示金额 → 查补贴/现金额度 → 补贴优先扣款、不足部分现金补足 → 上报公寓端 → 同步平台落账户 消费终端 → apt.ledger.local → apt-report 平台端(platform.ledger) gy_ykt_remainder、gy_ykt_consume、apt_ledger_offline、apt_report_outbox #10(LEDGER_OFFLINE)、#1
CF-02 人员充值 扫公寓线下二维码 → 签到终端点"现金充值"输入金额 → 管理员核对 → 计入本人现金充值额度 → 保存公寓端现金额度 → 同步平台落账户 签到终端 → 值班台 / 管理端 → apt.ledger.local → apt-report 平台端(platform.ledger) gy_ykt_cash_request、gy_ykt_xjczjl、gy_ykt_remainder、apt_ledger_offline #10(LEDGER_OFFLINE)、#1
CF-03 公寓菜品管理 公寓管理员发布阶段性菜品食谱 → 消费人员在消费终端查看菜品 → 点击加入选择菜单;预留远程点菜入口 公寓管理员 → platform.catering → apt.catering(只读下发) → 消费终端 平台端(食谱主数据) YKT_MEALS(平台库,补列)、YKT_MEALS_ORDERING / YKT_MEALS_ORDERS_MX(预留) #4(recipes[])、#1(features.remoteOrdering)

1.2 与既有流程的关系

  • 账务闭环不重写:CF-01 / CF-02 的"离线受理 → 本地余额立即可用 → 先派 outbox → #10 逐条上报 → 平台归日 → 日对账通过置 RECONCILED"完整沿用 CR-02 F-D 六步;本文件只补齐"设备侧选菜 / 扫码申请 / 管理员核对"三个前置环节与字段。
  • 主账唯一写入口不变:platform-ledger 是 GY_YKT_REMAINDER 与 PL_LEDGER_FLOW 的唯一写者;platform-catering 与消费终端对余额表零写权限(docs/平台端/01 D1、docs/平台端/03)。
  • 菜品/订单表不重写:复用 YKT_MEALS / YKT_MEALS_ORDERING / YKT_MEALS_ORDERS_MX / PL_CATERING_SETTLE(docs/平台端/03 表 3-7)与 /platform/v1/admin/catering(docs/平台端/04 表 4-9);"阶段性食谱"以 YKT_MEALS 补列实现,不新增表。
  • 注册与入住不重写:充值需校验人员有效在寓与注册态,沿用 docs/公寓端/10 §4 与 docs/公寓端/11 §4;本文件不新增人员核验链路。
  • 远程点菜不实现:仅保留特性开关与接口入口(本期恒关闭),见 §6.4。

1.3 不变式

  1. 跨端 20 个编号、方向、路径不变;新增数据只走既有 payload + 既有 bizType(LEDGER_OFFLINE 已占 #10,CR-02 表 3-12)。
  2. 平台零回调;#1 / #4 由公寓 GET 拉取,#10 由公寓 POST 上行;#16 日对账本期只提供公寓可主动调用形态(P-02)。
  3. 公寓本地账务表唯一写入模块是 apt.ledger.local(docs/公寓端/03 表 3-6);设备侧只提交请求,不直改余额。
  4. GY_YKT_REMAINDER 是唯一余额表,不新造同义账户表;gy_card 全库不存在,卡号沿用 GY_YKT_RY.card_id。
  5. GY_YKT_CASH_REQUEST.request_state 沿用三值 PENDING / COMPLETED / CANCELLED,且申请表本身不存金额(金额落 apt_ledger_offline.amount)。
  6. offlineScope 三值 LOCAL_ONLY / SYNCED / RECONCILED 沿用 CR-02 表 3-15 / 表 3-21;LOCAL_ONLY 不是匹配状态。
  7. 幂等 idempotencyKey = hash(gyid + bizType + bizId + bizVersion);bizId = flowId、业务 UK (gyid, type, flow_id);归日以 serverReceivedAt 为准;count 按 biz_id 去重(R-C3)。
  8. outbox 是队列、apt_report_history 是终态流水,两者语义不互换(CR-C10);本流程的跨端上报态一律沿用 CR-02 表 3-21 的 reportState 正式五值 PENDING / SENT / FAILED / DEAD / RETRIED(outbox 与 history 共用),本地 outbox 内部状态机仍按 docs/公寓端/03 表 3-11。
  9. 设备侧一律主动拉取;抓拍、录音、签到现场图不出公寓;gyid 只从凭据解析、所有 SQL 必带 gyid。
  10. 仅线下充值:不接任何线上支付渠道、不产生支付订单与回调;扫公寓线下二维码只是公寓识别与入口引导,不构成资金流。

2. 状态流转总览

图 12-1 三项流程数据流向

flowchart LR
    subgraph DEV["公寓内设备"]
        CT["消费终端 CONSUME<br/>查看食谱 · 选单 · 显示金额"]
        CK["签到终端 CHECKIN<br/>扫码 · 现金充值申请"]
    end
    subgraph AP["公寓服务系统"]
        QUO["apt.ledger.local<br/>额度查询 / 双额度 CAS 扣减"]
        REQ["gy_ykt_cash_request<br/>充值申请与管理员核对"]
        LED["gy_ykt_* / apt_ledger_offline<br/>本地账务流水"]
        OUT["apt-report / outbox"]
        CAT["apt.catering<br/>食谱只读下发 / 水位"]
    end
    subgraph DUTY["值班台 / 管理端"]
        ADM["管理员核对现金充值"]
        RCP["公寓管理员发布食谱"]
    end
    subgraph PL["平台端"]
        CATM["platform.catering<br/>YKT_MEALS 食谱主数据"]
        ING["platform-ingest<br/>#10 接收"]
        LEDM["platform-ledger<br/>GY_YKT_REMAINDER / PL_LEDGER_FLOW"]
    end
    RCP -->|发布| CATM
    CATM -->|#4 recipes[](拉)| CAT
    CAT -->|CF-03 N-48 食谱| CT
    CT -->|CF-01 N-49 额度查询| QUO
    CT -->|CF-01 N-50 消费提交| QUO
    QUO -->|补贴优先 + 现金补足| LED
    CK -->|CF-02 N-52 充值申请| REQ
    REQ -->|待核对| ADM
    ADM -->|N-54 确认| REQ
    REQ -->|计入现金额度| LED
    LED -->|#10 LEDGER_OFFLINE| OUT
    OUT --> ING
    ING --> LEDM
    LEDM -->|日对账结论| OUT

表 12-4 四条状态链(互不替代)

链 字段 / 载体 取值 唯一写入口 说明
消费流水态 apt_ledger_offline.ledger_state(补列,流程态) SUBMITTED / DEDUCTED / REPORTED / RECONCILED / REJECTED / REVERSED apt.ledger.local 描述一笔消费从终端提交到平台对账;不是余额状态字段
充值申请态 gy_ykt_cash_request.request_state PENDING / COMPLETED / CANCELLED apt.ledger.local 沿用存量三值(docs/backend/05 §4.7),不新造
同步生命周期 apt_ledger_offline.offline_scope + reportState(outbox / history 共用)+ reconcile_state LOCAL_ONLY / SYNCED / RECONCILED;PENDING / SENT / FAILED / DEAD / RETRIED;PENDING / RECONCILED / DIFF apt.ledger.local / apt.report.outbox 沿用 CR-02 表 3-15、表 3-21、表 3-30
食谱发布态 YKT_MEALS.publish_state(平台库补列) DRAFT / PUBLISHED / EXPIRED / REVOKED platform.catering 阶段性食谱按 recipe_id + recipe_version 成组发布

表 12-5 全流程状态流转

序 流程 状态 触发 写入口与落表 后继 / 异常回退
1 CF-03 DRAFT 公寓管理员新建阶段性食谱 YKT_MEALS(补列) 菜品下架 / 价格改 → 新 recipe_version,不改已发布版
2 CF-03 PUBLISHED 管理员发布且 effective_from ≤ now ≤ effective_to YKT_MEALS.publish_state、#4 增量 到期 → EXPIRED;撤回 → REVOKED
3 CF-01 终端选单(不落库) 消费终端 N-48 拉食谱、点击加入选择菜单 设备本地选单缓存 仅本地状态,退出/超时清空
4 CF-01 SUBMITTED N-50 提交消费(flowId 幂等) apt_ledger_offline(ledger_state=SUBMITTED) 校验失败 → REJECTED,不扣款
5 CF-01 DEDUCTED 双额度 CAS 扣减成功、balance_before/after 留痕 gy_ykt_remainder、gy_ykt_consume、apt_ledger_offline CAS 冲突重读重试一次,再失败转人工
6 CF-01 REPORTED #10 LEDGER_OFFLINE 入 outbox 并 SENT apt_report_outbox / apt_report_history 断网 → outbox PENDING,恢复后复用原 idempotencyKey 续报
7 CF-01 RECONCILED 平台日对账通过 offline_scope=RECONCILED、local_balance_version 更新 差异 → DIFF,PF-5003 阻断调账
8 CF-02 PENDING N-52 扫码后输入金额提交申请 gy_ykt_cash_request、apt_ledger_offline(RECHARGE, PENDING) 重复 deviceEventId 返回原 flowId
9 CF-02 COMPLETED 管理员 N-54 核对确认(二次确认) gy_ykt_xjczjl、gy_ykt_remainder.xjye、apt_ledger_offline.balance_after 金额不符 → N-55 CANCELLED,写 reject_reason
10 CF-02 REPORTED → RECONCILED 同序 6 / 7 同序 6 / 7 同序 6 / 7
11 通用 REVERSED / CANCELLED 冲正或作废 apt_ledger_offline、duty_operation_log 已 RECONCILED 不得直接改,走 POST /adjustments 冲正

图 12-2 双额度扣减决策

flowchart TD
    A["N-50 消费提交 amount"] --> B{"额度查询<br/>allowanceQuota / cashQuota"}
    B --> C{"amount ≤ allowanceQuota?"}
    C -->|是| D["allowanceAmount = amount<br/>cashAmount = 0"]
    C -->|否| E["allowanceAmount = allowanceQuota<br/>cashAmount = amount - allowanceQuota"]
    E --> F{"cashAmount ≤ cashQuota?"}
    F -->|否| G["REJECTED 余额不足<br/>PF-5001 / 40933"]
    F -->|是| H["CAS 扣减两条额度<br/>balance_before/after"]
    D --> H
    H --> I["一条 CONSUME 流水<br/>payload 带拆分字段"]
    I --> J["#10 LEDGER_OFFLINE"]

一条流水原则(CR-C31):一笔消费只产生一条 flowId / type=CONSUME 流水,补贴与现金的拆分作为 allowanceAmount / cashAmount 字段随 payload 上报,不额外生成 ALLOWANCE_DEDUCT 流水,避免平台 sum(amount) 双计。ALLOWANCE_DEDUCT 保留给"独立退补助 / 补助调整"场景。


3. 数据模型

不新增公寓本地业务表(仍 59 张):账户额度、消费流水、充值记录全部复用 gy_ykt_* 五张预留表与 apt_ledger_offline;食谱主数据复用平台库 YKT_MEALS 并补列。所有补列均为设计定义,DDL 待阶段二契约冻结评审(Q-43)。

表 12-6 复用表清单

表 库 唯一写入模块 本流程用途 上报
gy_ykt_remainder apartment apt.ledger.local 账户额度本地快照(knye / xjye),CAS 扣减 否(经 #10 流水)
gy_ykt_consume apartment apt.ledger.local 消费流水(xfje / xfsj / deviceCode / xfly) 是(#10)
gy_ykt_allowance apartment apt.ledger.local 补助发放流水(本流程只读,作为额度来源) 是(#10)
gy_ykt_cash_request apartment apt.ledger.local 现金充值申请与 request_state 三值 否
gy_ykt_xjczjl apartment apt.ledger.local 现金充值记录(flow_id / czje / czsj) 是(#10)
apt_ledger_offline apartment apt.ledger.local 离线/在线统一的本地账务流水、CAS 留痕、同步生命周期 是(#10)
apt_report_outbox / apt_report_history apartment apt.report.outbox / apt-report 上行队列与终态留痕 是
GY_YKT_REMAINDER / PL_LEDGER_FLOW platform platform-ledger 平台余额主账与归集流水(公寓端零写权限) —
YKT_MEALS / YKT_MEALS_ORDERING / YKT_MEALS_ORDERS_MX platform platform.catering 菜品主数据、阶段性食谱补列、选单 / 订单(后两者本期预留) —
duty_manual_action / duty_operation_log duty 应用端 管理员核对、食谱发布留痕 否

表 12-7 账户额度 gy_ykt_remainder 列级结构与补列

列 类型 约束 来源 说明
ryid / gyid string(64) / string(32) UK (gyid, ryid) 存量 账户主键;gyid 打头隔离
xm string(128) 可空 存量 姓名快照
knye decimal(12,2) 默认 0.00 存量 补贴可用额度(逻辑名 allowanceQuota,沿用 docs/backend/05 §4.3 与 backend/11 实测口径)
xjye decimal(12,2) 默认 0.00 存量 现金可用额度(逻辑名 cashQuota)
xfze / bzze / xfxjje / xfbzje decimal(12,2) ×4 默认 0.00 存量 消费总额 / 补助总额 / 现金消费额 / 补助消费额,随每笔消费累加
local_balance_version bigint 默认 1 补列 CAS 版本;与 apt_ledger_offline.local_balance_version 一致,冲突重读重试一次
last_reconciled_at / reconcile_state datetime(3) / enum_s 可空 / 默认 PENDING 补列 最后对账日期与 PENDING / RECONCILED / DIFF(平台侧同名三值 RECEIVED / RECONCILED / DIFF)
quota_ref string(64) 可空 补列 #1 下发 offlineQuota 批次引用,断网额度校验用
updated_at datetime(3) NOT NULL 补列 只追加更新,不物理删除

knye / xjye 到"补贴 / 现金"的映射为设计映射,阶段二冻结前须按 backend/11 存量数据复核(写入 Q-43 一并拍板);本流程不新造同义余额字段。

表 12-8 消费流水 gy_ykt_consume / apt_ledger_offline 列级结构与补列

表 列 类型 来源 说明
gy_ykt_consume tid / flow_id / ryid / gyid string ×4 存量 / 补列 flow_id 为 #10 bizId,UK (gyid, flow_id)
xfje / xfsj / device_code / xfly decimal(12,2) / datetime / string / enum_s 存量 消费金额(正数)、时间、受理设备、消费来源
knye / xjye / xfze / bzze decimal(12,2) ×4 存量 扣款后两条余额与累计额快照
allowance_amount / cash_amount decimal(12,2) ×2 补列 本笔拆分:allowance_amount + cash_amount = xfje,一条流水不双计
recipe_id / recipe_version / items string / bigint / json 补列 关联阶段性食谱与选单明细(meal_id / name / price / qty),供对账与退单
apt_ledger_offline id / gyid / type / flow_id id_ulid / string / enum_s / string 存量 type = CONSUME / RECHARGE / ALLOWANCE_DEDUCT;UK (gyid, type, flow_id)
amount / balance_before / balance_after decimal(12,2) ×3 存量 扣减用负数、充值用正数;CAS 前后余额留痕
offline_scope / reconcile_state enum_s ×2 存量 LOCAL_ONLY / SYNCED / RECONCILED;PENDING / RECONCILED / DIFF
local_balance_version / quota_ref bigint / string 存量 本地余额版本与离线额度批次
ledger_state enum_s 补列 表 12-4 消费流水态(流程态,不写 gy_jcxx 状态字段)
allowance_before/after / cash_before/after decimal(12,2) ×4 补列 双额度各自 CAS 前后值,与 §2 决策图一致
occurred_at / synced_at / created_at datetime(3) ×3 存量 归日以平台 serverReceivedAt 为准

表 12-9 充值记录 gy_ykt_xjczjl / gy_ykt_cash_request 列级结构与补列

表 列 类型 来源 说明
gy_ykt_xjczjl flow_id / ryid / gyid string ×3 存量 PK flow_id;与 apt_ledger_offline.flow_id 一致
czje / czsj decimal(12,2) / datetime(3) 存量 充值金额(正数)与时间
channel / confirmed_by / confirmed_at enum_s / string / datetime 补列 channel 恒 OFFLINE_CASH(仅线下);管理员核对留痕
gy_ykt_cash_request id / ryid / gyid / device_code string ×4 存量 申请单;本身不存金额(金额在 apt_ledger_offline.amount)
request_state enum_s 存量 PENDING / COMPLETED / CANCELLED,不新造状态
flow_id / device_event_id string ×2 补列 关联账务流水;UK (gyid, device_code, device_event_id) 幂等
requested_at / confirmed_by / confirmed_at / reject_reason datetime ×2 / string / datetime / string 补列 申请、核对与作废留痕
qr_code_id string(64) 补列 公寓线下二维码标识,只作公寓识别,不含支付信息

表 12-10 食谱与菜品 YKT_MEALS 补列(平台库)

列 类型 来源 说明
meal_id / gyid / name / price / enabled string / string / string / decimal(12,2) / tinyint 存量 菜品主键、公寓、名称、单价、启停(docs/平台端/03 表 3-7)
recipe_id / recipe_version string(64) / bigint 补列 阶段性食谱批次与版本;同批次所有菜品共享,version 单调
meal_period enum_s 补列 BREAKFAST / LUNCH / DINNER / NIGHT / ANY
effective_from / effective_to datetime(3) ×2 补列 食谱生效区间;到期 EXPIRED
publish_state enum_s 补列 DRAFT / PUBLISHED / EXPIRED / REVOKED
published_by / published_at string(64) / datetime(3) 补列 公寓管理员发布留痕
category / sort_no / image_ref string / int / string 补列 分类、排序、图片引用占位;本期不落任何图片本体,#4 下行只带引用字符串,不进对象存储(平台侧仍只有 person-photo / report-export 两个桶,见 docs/平台端/07 §4.1)

YKT_MEALS_ORDERING / YKT_MEALS_ORDERS_MX 本期不写入:消费终端的"选择菜单"是设备本地选单,确认后才按 CF-01 生成一条消费流水;远程点菜启用后再落订单表(Q-44)。

表 12-11 枚举字典

枚举 取值 来源 / 说明
flowType CONSUME / RECHARGE / ALLOWANCE_DEDUCT CR-02 表 3-15,沿用不新增
offlineScope LOCAL_ONLY / SYNCED / RECONCILED CR-02 表 3-15 / 表 3-21
reportState PENDING / SENT / FAILED / DEAD / RETRIED CR-02 表 3-21,outbox 与 history 共用
requestState PENDING / COMPLETED / CANCELLED docs/backend/05 §4.7
ledgerState SUBMITTED / DEDUCTED / REPORTED / RECONCILED / REJECTED / REVERSED 本流程补列(流程态)
publishState DRAFT / PUBLISHED / EXPIRED / REVOKED 本流程补列
mealPeriod BREAKFAST / LUNCH / DINNER / NIGHT / ANY 本流程补列
rechargeChannel OFFLINE_CASH 唯一取值;不接线上支付(CR-C32)
source DEVICE / DUTY / SELF CR-02 表 3-14

4. CF-01 人员消费流程

4.1 触发条件与数据范围

表 12-12 触发与前置

项 口径
触发 消费终端(gy_sb.device_class=CONSUME)按当前 PUBLISHED 食谱展示菜品;人员点击加入选择菜单,终端实时显示合计金额;确认后 N-50 提交
数据范围 gyid(凭据解析)、ryid、deviceCode、deviceEventId、选单 items[]{mealId, name, price, qty}、amount、recipeId / recipeVersion、occurredAt
前置 人员已注册且有效在寓(docs/公寓端/11 §2);食谱为 PUBLISHED 且在生效区间;设备凭据、HMAC、±5 min 时间窗、nonce 通过
不触发 仅浏览食谱 / 仅加入选单(未确认)、食谱 EXPIRED / REVOKED、菜品 enabled=0、人员已离寓

表 12-13 双额度扣减规则(CR-C31)

步 规则 字段 异常
1 查询补贴额度与现金额度 allowanceQuota = gy_ykt_remainder.knye、cashQuota = xjye 账户不存在 → 40934;额度版本落后 → 重拉 #1 后重试
2 优先全额补贴 amount ≤ allowanceQuota → allowanceAmount = amount、cashAmount = 0 —
3 补贴不足则现金补足 allowanceAmount = allowanceQuota、cashAmount = amount - allowanceQuota cashAmount > cashQuota → REJECTED + PF-5001 / 40933,不部分扣款
4 CAS 扣减 where ryid=? and local_balance_version=?;更新 knye / xjye 与四个累计额 冲突重读重试一次,再失败转人工(40935)
5 记一条流水 type=CONSUME、amount = -xfje(payload 负数)、allowanceAmount + cashAmount = xfje 不生成第二条 ALLOWANCE_DEDUCT,不双计
6 断网额度校验 offlineScope=LOCAL_ONLY 时校验 #1 offlineQuota.{singleLimit, dailyLimit, maxOutstanding} 超限 40913,本地余额立即可用但不写平台主账
7 上报与对账 #10 LEDGER_OFFLINE;平台按 serverReceivedAt 归日;日对账通过置 RECONCILED PF-5002 重复流水、PF-5003 对账未结清

4.2 接口

表 12-14 N-49 / N-50 / N-51 请求 / 响应字段

编号 方法 + 路径 权限 / 凭据 幂等 请求字段 响应字段
N-49 GET /open/v1/ledger/quota?ryid&deviceCode 设备凭据 + HMAC L0 ryid(须与设备可见范围匹配)、deviceCode ryid、allowanceQuota / cashQuota(字符串两位小数)、localBalanceVersion、quotaRef、reconcileState、lastReconciledAt、serverTime
N-50 POST /open/v1/ledger/consume 设备凭据 + HMAC L2 (gyid, deviceCode, deviceEventId) ryid、items[]{mealId, name, price, qty}、amount、recipeId / recipeVersion、deviceEventId、occurredAt、nonce / signature flowId、ledgerState=DEDUCTED、allowanceAmount / cashAmount、allowanceAfter / cashAfter、offlineScope、localBalanceVersion、reportState、serverTime
N-51 GET /open/v1/ledger/flows/{flowId} 设备凭据 L0 flowId flowId、type、ledgerState、offlineScope、reportState、reconcileState、amount / allowanceAmount / cashAmount、syncedAt

表 12-15 消费状态机(条件更新带 ledger_state 期望值)

当前态 事件 目标态 落表 失败 / 补偿
— N-50 提交通过校验 SUBMITTED apt_ledger_offline 校验失败 → REJECTED,不扣款
SUBMITTED CAS 扣减成功 DEDUCTED gy_ykt_remainder、gy_ykt_consume、apt_ledger_offline CAS 冲突重试一次,再失败转人工
DEDUCTED #10 入 outbox 并 SENT REPORTED apt_report_outbox / apt_report_history 断网 PENDING 排队,恢复复用原幂等键
REPORTED 平台日对账通过 RECONCILED offline_scope / reconcile_state / local_balance_version 差异 DIFF + PF-5003,阻断调账
REPORTED / RECONCILED 人工冲正 REVERSED duty_manual_action、POST /adjustments 不直接改余额表,走 platform-ledger 冲正

图 12-3 消费端到端时序

sequenceDiagram
    autonumber
    participant CT as 消费终端 CONSUME
    participant AP as apt.ledger.local
    participant AC as apt.catering
    participant L as gy_ykt_* / apt_ledger_offline
    participant O as apt-report / outbox
    participant P as platform-ingest → platform-ledger

    CT->>AC: CF-03 N-48 拉当前食谱(设备主动拉取)
    AC-->>CT: recipes[] + version(终端缓存)
    CT->>CT: 点击菜品加入选择菜单,显示合计金额
    CT->>AP: N-49 查询补贴额度与现金额度
    AP-->>CT: allowanceQuota / cashQuota / localBalanceVersion
    CT->>AP: N-50 提交消费(flowId, items, amount)
    AP->>AP: 补贴优先 → 现金补足(图 12-2)
    AP->>L: CAS 扣减 + 记一条 CONSUME 流水(DEDUCTED)
    AP->>O: 生成 #10 LEDGER_OFFLINE
    O->>P: 上报(idempotencyKey = hash(gyid+bizType+flowId+bizVersion))
    P->>P: 按 serverReceivedAt 归日,落 PL_LEDGER_FLOW / GY_YKT_REMAINDER
    P-->>O: 接收回执 / 日对账结论
    O->>L: REPORTED → RECONCILED(offline_scope / local_balance_version)
    AP-->>CT: N-51 可查流水状态

表 12-16 CF-01 异常与错误码

场景 处理 不做什么
余额不足(补贴 + 现金仍不足) REJECTED + PF-5001 / 40933 不部分扣款、不透支(内部人员透支口径见 Q-45)
补贴刚好为 0 allowanceAmount=0,全额走现金 不生成 ALLOWANCE_DEDUCT 流水
CAS 版本冲突 重读额度重试一次,再失败 40935 转人工 不覆盖较新版本、不丢 balance_before/after
断网且超 offlineQuota 40913,本地余额立即可用但不写平台主账 不伪造 SYNCED
重复提交 deviceEventId 返回原 flowId 与快照 不产生第二笔扣款
平台重复流水 / 幂等重放 PF-5002 业务重复 vs PL-IDEMPOTENT-REPLAY 幂等重放分别处理 不把两者混为一谈
食谱过期 / 菜品下架 / 价格变更 40936 / PF-6001,要求终端重拉食谱 不用旧价格扣款
已离寓人员消费 40937 拒收 不改 finish_ly / ryzt
已 RECONCILED 需冲正 走 POST /adjustments + 审批留痕 不直改 GY_YKT_REMAINDER

5. CF-02 人员充值流程

5.1 线下充值边界

表 12-17 "仅线下充值、仅记账"口径(CR-C32)

项 口径
扫码含义 公寓线下二维码只携带 gyid + qrCodeId,用于识别公寓并引导到签到终端;不携带支付链接、不发起任何线上支付
资金动作 现金由管理员线下收取并核对;系统只做记账,不接微信/支付宝/网银、不建支付订单、不处理支付回调
金额载体 gy_ykt_cash_request 不存金额(沿用存量口径);金额落 apt_ledger_offline.amount(type=RECHARGE,正数)与 gy_ykt_xjczjl.czje
额度落点 管理员确认后由 apt.ledger.local 更新 gy_ykt_remainder.xjye(现金额度)并记 balance_before/after
同步 与 CF-01 共用 #10 LEDGER_OFFLINE + F-D 六步;平台 platform-ledger 落 GY_YKT_REMAINDER / PL_LEDGER_FLOW
断网 本地记账受 #1 offlineQuota 约束(缺省全 0 即断网不开放,Q-21 / Q-42),超限 40913

表 12-18 充值申请状态机(复用 request_state 三值)

当前态 事件 目标态 落表 失败 / 补偿
— N-52 扫码后输入金额提交 PENDING gy_ykt_cash_request、apt_ledger_offline(SUBMITTED) 金额非法 → 40938;重复 deviceEventId 返回原 flowId
PENDING 管理员 N-54 核对确认(duty:ledger:confirm + 二次确认) COMPLETED gy_ykt_xjczjl、gy_ykt_remainder.xjye、apt_ledger_offline(DEDUCTED) 金额与实收不符 → N-55 CANCELLED
PENDING 管理员 N-55 作废 / 超时 CANCELLED reject_reason、duty_operation_log 不写额度、不生成充值记录
COMPLETED #10 上报 / 日对账 REPORTED → RECONCILED apt_report_outbox / history 同 CF-01 序 6 / 7
终态 任何再次确认 拒绝 40939 — 返回原态快照,不重复入账

表 12-19 N-52~N-55 请求 / 响应字段

编号 方法 + 路径 权限 / 凭据 幂等 请求字段 响应字段
N-52 POST /open/v1/ledger/recharge-requests 签到终端设备凭据 + HMAC L2 (gyid, deviceCode, deviceEventId) ryid、amount(字符串两位小数,正数)、qrCodeId、deviceEventId、occurredAt、nonce / signature flowId、requestState=PENDING、amount、qrCodeId、requestedAt、serverTime
N-53 GET /duty/ledger/recharge-requests?state&cursor duty:ledger:local L0 state=PENDING、cursor、limit items[]{flowId, ryid, workNo, name, amount, qrCodeId, requestedAt, deviceCode}、cursor、total
N-54 POST /duty/ledger/recharge-requests/{flowId}/confirm duty:ledger:confirm + 二次确认 L2 commandId flowId、expectedAmount、confirmedAmount、expectedRequestState、commandId flowId、requestState=COMPLETED、cashQuotaAfter、localBalanceVersion、confirmedBy / confirmedAt、reportState
N-55 POST /duty/ledger/recharge-requests/{flowId}/cancel duty:ledger:confirm L2 commandId flowId、reason、commandId flowId、requestState=CANCELLED、rejectReason

表 12-20 管理员确认后的数据变更清单

# 对象 变更 约束
1 gy_ykt_cash_request request_state=COMPLETED、回填 confirmed_by / confirmed_at 条件更新带期望态 PENDING,并发冲突 40939
2 apt_ledger_offline type=RECHARGE、amount=+confirmedAmount、ledger_state=DEDUCTED、balance_before/after、cash_before/after 金额必须与 N-52 一致;不一致走 N-55
3 gy_ykt_xjczjl 新增 flow_id / czje / czsj、channel=OFFLINE_CASH、confirmed_by 一笔申请一条充值记录
4 gy_ykt_remainder xjye += confirmedAmount、local_balance_version + 1、更新 updated_at CAS 条件更新;只增现金额度,不改 knye 补贴额度
5 apt_report_outbox 生成 #10 LEDGER_OFFLINE 上报项(bizId=flowId) 断网 PENDING 排队,恢复复用原 idempotencyKey
6 duty_manual_action / duty_operation_log 记核对人、commandId、申请金额 / 实收金额、前后额度 二次确认留痕,越权 40301

图 12-4 线下充值端到端时序

sequenceDiagram
    autonumber
    participant CK as 签到终端 CHECKIN
    participant AP as apt.ledger.local
    participant D as 管理员(值班台 /duty)
    participant L as gy_ykt_* / apt_ledger_offline
    participant O as apt-report / outbox
    participant P as platform-ledger

    CK->>AP: 扫公寓线下二维码 → N-52 现金充值申请(amount)
    AP->>L: request_state=PENDING(申请表不存金额)
    AP->>D: 推待办 recharge.request
    D->>AP: N-53 查看待核对列表
    D->>AP: N-54 核对实收金额并二次确认
    AP->>L: COMPLETED + xjye 增加 + gy_ykt_xjczjl 记录
    AP->>O: 生成 #10 LEDGER_OFFLINE(RECHARGE)
    O->>P: 上报并归日
    P-->>O: 日对账结论 → RECONCILED
    AP-->>CK: 可查额度与流水状态
    Note over CK,P: 全程无线上支付渠道、无支付订单与回调

表 12-21 CF-02 异常与错误码

场景 处理 不做什么
金额为 0 / 负数 / 超上限 / 小数位 > 2 40938 拒收(沿用 backend/04 "金额 > 0 且 < 100") 不建申请单、不排队
二维码无效 / 跨 gyid 40301 / 40939 拒收并记审计 不解析任何支付参数
重复扫码提交 返回原 flowId(deviceEventId 幂等) 不生成第二笔充值
实收金额与申请不符 N-55 CANCELLED + reject_reason,重新发起申请 不按申请金额直接入账
并发确认 条件更新冲突 40939 不重复入账、不改终态
断网超 offlineQuota 40913 不伪造已同步、不写平台主账
已 RECONCILED 需冲正 POST /adjustments + 审批 不直改余额表、不改申请单终态
线上支付请求(若误接) 直接拒绝,不提供该入口 不建支付订单、不监听回调

6. CF-03 公寓菜品管理

6.1 发布与查看

表 12-22 食谱发布状态机(平台库 YKT_MEALS.publish_state)

当前态 事件 目标态 落表 / 编号 失败 / 补偿
— 公寓管理员新建食谱(选菜品、餐次、生效区间) DRAFT YKT_MEALS 补列 菜品 enabled=0 不得加入
DRAFT 发布(二次确认) PUBLISHED recipe_version 单调、published_by/at;#4 增量 区间重叠 → PF-6004(规则重叠沿用 PF-5004 语义)或拒绝发布
PUBLISHED 到达 effective_to EXPIRED 定时任务置态 终端重拉后不再展示
PUBLISHED 管理员撤回 REVOKED duty_manual_action 已发生的消费流水不受影响
任意已发布态 改价 / 下架菜品 新 recipe_version YKT_MEALS 新版本 不改已发布版本,避免历史对账错配

主数据归属(CR-C33):食谱主数据在平台库 YKT_MEALS(补列),由公寓管理员经 /platform/v1/admin/catering 的 recipes 资源发布并按 gyid 隔离;公寓端 apt.catering 通过 #4 下行 recipes[] 拉增量与水位,食谱缓存落在消费终端本地,不落公寓本地业务表(59 张不变)。Q-43 未决前按此默认口径执行。

表 12-23 N-48 / N-57 / N-58 请求 / 响应字段

编号 方法 + 路径 权限 / 凭据 幂等 请求字段 响应字段
N-48 GET /open/v1/catering/recipes?deviceCode&version 消费终端设备凭据 L0(版本) version(可选,来自上次响应) recipes[]{recipeId, recipeVersion, mealPeriod, effectiveFrom, effectiveTo, publishState, items[]{mealId, name, price, category, sortNo, enabled, imageRef}}、version、serverTime;版本未变返回 notModified=true
N-57 GET /apt/catering/recipes、POST /apt/catering/recipes、PUT /apt/catering/recipes/{recipeId}/publish、PUT /apt/catering/recipes/{recipeId}/revoke apt:catering:recipe:* L2 recipeId + version recipeId、mealPeriod、effectiveFrom/To、items[]、expectedVersion recipeId、recipeVersion、publishState、publishedBy/At、itemCount、serverTime
N-58 POST /open/v1/catering/orders(远程点菜预留入口) 设备凭据 L2 orderId ryid、items[]、recipeId、deliveryType 本期恒返回 40940 FEATURE_DISABLED 且 features.remoteOrdering=false;不落订单、不扣款

N-57 是公寓端管理入口,后端代理到平台餐饮管理端 /platform/v1/admin/catering/recipes;权限点 apt:catering:recipe:list / create / publish / revoke,前端 v-hasPermi 与后端 @PreAuthorize 同码并登记 sys_menu.perms。

表 12-24 阶段性食谱数据结构

字段 类型 必填 校验规则
recipeId / recipeVersion string(64) / bigint 是 服务端生成;version 单调,同 recipeId 不允许覆盖已发布版
gyid string(32) 是 只从会话解析,不接受请求参数
mealPeriod enum_s 是 BREAKFAST / LUNCH / DINNER / NIGHT / ANY
effectiveFrom / effectiveTo datetime(3) ×2 是 from < to;同 gyid + mealPeriod 区间重叠拒绝发布
publishState enum_s 是 表 12-22 状态机
items[] array 是 至少 1 项;每项 mealId 存在且 enabled=1、price > 0 且两位小数、qty 上限按 Q-45
imageRef string(512) 否 只存引用占位;本期不上传 / 不下载图片本体,不新增对象存储桶,docs/平台端/07 §4.1「只有两个桶」的边界不变
publishedBy / publishedAt string / datetime 发布时 二次确认留痕

6.2 选单与远程点菜预留

  • 选择菜单:消费终端本地维护(设备主动拉取食谱 → 点击加入 → 实时显示合计金额),确认前不落库;确认后只按 CF-01 生成一条消费流水。终端退出 / 超时(默认 5 min)清空选单。
  • 远程点菜入口:#1 下行 features.remoteOrdering(默认 false)+ N-58 接口骨架 + YKT_MEALS_ORDERING / YKT_MEALS_ORDERS_MX 两表预留;本期不实现下单、不落订单、不扣款,启用条件与配送 / 后厨 / 结算规则见 Q-44 与 平台端/09 P-07。
  • 价格一致性:N-50 提交时服务端按 recipeId + recipeVersion 重算金额,与终端 amount 不一致 → 40936 要求重拉食谱,防止改价期间错扣。

表 12-25 CF-03 异常与错误码

场景 处理 不做什么
食谱未发布 / 已过期 / 已撤回 40936 + 终端重拉 N-48 不展示、不允许加入选单
菜品下架 / 价格变更 PF-6001 / 40936,按服务端 recipeVersion 重算 不用终端旧价扣款
区间重叠发布 拒绝发布并提示调整 effectiveFrom/To 不产生第二个同时生效的同餐次食谱
改价影响已发布版 生成新 recipe_version 不改历史版本、不改已发生流水
远程点菜误调用 40940 FEATURE_DISABLED 不落订单、不扣款、不改额度
设备食谱缓存落后 N-48 按 version 增量刷新 不用过期缓存计算金额

7. 提报与平台同步(CF-01 / CF-02 共用)

表 12-26 #10 POST /platform/v1/report/ledger(bizType=LEDGER_OFFLINE)payload 字段

字段 类型 必填 说明
envelope object 是 contractVersion=v2-draft、gyId、bizType=LEDGER_OFFLINE、bizId=flowId、idempotencyKey=hash(gyid+bizType+flowId+bizVersion)、occurredAt、serverReceivedAt
flowId / type string / enum 是 沿用 CR-02 表 3-15;CONSUME / RECHARGE(ALLOWANCE_DEDUCT 不用于消费拆分)
amount string(2) 是 字符串十进制两位小数;扣减用负数、充值用正数,禁止浮点
ryid / cardNo / deviceCode string ×3 是 账户、GY_YKT_RY.card_id、受理设备
offlineScope / localBalanceVersion / quotaRef enum / bigint / string 是 沿用 F-D;断网期间恒 LOCAL_ONLY
allowanceAmount / cashAmount string(2) ×2 CONSUME 必填 本流程扩展:拆分金额,allowanceAmount + cashAmount = abs(amount)
allowanceBefore/After / cashBefore/After string(2) ×4 是 本流程扩展:双额度 CAS 前后值,供平台对账
recipeId / recipeVersion / items[] string / bigint / array 否 本流程扩展:消费关联食谱与选单明细,不含图像本体
rechargeChannel / qrCodeId / confirmedBy enum / string / string RECHARGE 必填 本流程扩展:OFFLINE_CASH + 线下二维码标识 + 管理员核对留痕
syncedAt datetime 否 归日仍以平台 serverReceivedAt 为准(CR-02 表 3-11)

表 12-27 平台侧处理链路与落表

步 主体 动作 编号 落表
1 platform-ingest 按 idempotencyKey 去重,落接收日志 #10 PL_RECEIVE_LOG
2 platform-ledger 按 serverReceivedAt 归日;业务 UK (gyid, type, flow_id) 去重;sum(amount) 对账 #10 PL_LEDGER_FLOW(reconcile_state = RECEIVED / RECONCILED / DIFF)
3 platform-ledger 唯一写入口更新余额主账;消费按 allowanceAmount / cashAmount 分别冲减 knye / xjye,充值只增 xjye 内部 GY_YKT_REMAINDER
4 公寓 apt-report 日对账通过后把 offline_scope 置 RECONCILED、更新 local_balance_version #16(本期公寓主动调用形态) apt_ledger_offline、gy_ykt_remainder
5 值班台 推 ledger.offline WS 消息(flowId / offlineScope / localBalanceVersion / quotaRemain / seq) 端内 duty_operation_log

表 12-28 对账与冲正规则(沿用,不新造)

项 口径
三维比对 count(按 biz_id 去重,R-C3)/ sum(amount) / max(watermark);差异落 PL_RECONCILE_DIFF
归日 平台 serverReceivedAt;公寓 occurredAt 不参与日切
重复语义 PF-5002 业务重复流水 vs PL-IDEMPOTENT-REPLAY 幂等重放,两者不同
阻断 当日 sum(amount) 不等即 P0,PF-5003 阻断所有调账入口
冲正 只允许 POST /adjustments(带原因 + 审批人)经 platform-ledger 冲正,不改余额表字段、不改申请单终态
续报 断网恢复先派 outbox 再拉 #7(CR-01 §2.9),复用原 idempotencyKey,不产生新业务事实

8. 接口清单汇总

表 12-29 端内接口 N-48~N-58(均不计入跨端 20 个编号)

编号 方法 + 路径 权限 / 凭据 幂等 流程 用途
N-48 GET /open/v1/catering/recipes 消费终端设备凭据 L0(版本) CF-03 / CF-01 拉取当前有效阶段性食谱与菜品
N-49 GET /open/v1/ledger/quota 消费终端设备凭据 L0 CF-01 查询补贴额度与现金额度
N-50 POST /open/v1/ledger/consume 消费终端设备凭据 + HMAC L2 (gyid, deviceCode, deviceEventId) CF-01 提交选单与金额,触发双额度扣减
N-51 GET /open/v1/ledger/flows/{flowId} 设备凭据 L0 CF-01 / CF-02 流水状态与拆分金额查询
N-52 POST /open/v1/ledger/recharge-requests 签到终端设备凭据 + HMAC L2 (gyid, deviceCode, deviceEventId) CF-02 扫码后发起线下现金充值申请
N-53 GET /duty/ledger/recharge-requests duty:ledger:local L0(游标) CF-02 管理员待核对列表
N-54 POST /duty/ledger/recharge-requests/{flowId}/confirm duty:ledger:confirm + 二次确认 L2 commandId CF-02 核对实收金额并计入现金额度
N-55 POST /duty/ledger/recharge-requests/{flowId}/cancel duty:ledger:confirm L2 commandId CF-02 作废申请
N-56 GET /apt/ledger/accounts/{ryid} apt:ledger:list L0 CF-01 / CF-02 账户额度、流水与对账状态查询
N-57 GET/POST /apt/catering/recipes、PUT .../{recipeId}/publish、PUT .../{recipeId}/revoke apt:catering:recipe:* L2 recipeId + version CF-03 公寓管理员发布 / 撤回阶段性食谱
N-58 POST /open/v1/catering/orders 设备凭据 L2 orderId CF-03 远程点菜预留入口,本期恒 40940

通用约定(前缀、HMAC + 时间窗 + nonce、错误码分段、data.reason / data.traceId、gyid 锁定)见 docs/公寓端/04 §1;既有 N-09 / N-10(duty:ledger:local)保持不变,本文件不重复登记。

表 12-30 跨端接口(沿用既有编号,不新增、不重排)

# 接口 方向 本流程扩展 字段表
1 GET /platform/v1/master/apartments/{gyId} 下行(拉) offlineQuota 沿用;新增 features.remoteOrdering(默认 false) CR-02 表 3-20
4 GET /platform/v1/master/rules?gyId 下行(拉) 响应增 recipes[]{recipeId, recipeVersion, mealPeriod, effectiveFrom/To, items[]} + recipeWatermark 表 12-24
10 POST /platform/v1/report/ledger 上行 LEDGER_OFFLINE payload 扩展(拆分金额 / CAS 值 / 食谱 / 线下充值标记) 表 12-26
16 POST /platform/v1/reconcile/run?gyId&date 补偿(本期公寓主动调用形态,P-02) 日对账结论回写 RECONCILED 表 12-28

9. 异常、一致性与权限

表 12-31 异常总表(三项流程一致口径)

场景 处理 不做什么
设备断网 本地额度内受理,offlineScope=LOCAL_ONLY、outbox PENDING,恢复复用原 idempotencyKey 续报 不伪造 SYNCED、不产生新业务事实
超离线额度 40913 APT_OFFLINE_QUOTA_EXCEEDED(#1 offlineQuota 缺省全 0 即断网不开放) 不放行本地扣款
余额不足 REJECTED + PF-5001 / 40933 不部分扣款、不透支
CAS 冲突 重读重试一次,再失败 40935 转人工 不覆盖新版本、不留半条余额
金额非法 40938 拒收(> 0、< 100、≤ 2 位小数) 不建申请单 / 流水
并发确认 / 重复提交 条件更新 + commandId / deviceEventId 幂等,冲突 40939 不重复入账、不重复扣款
平台重复 / 幂等重放 PF-5002 与 PL-IDEMPOTENT-REPLAY 分别处理 不混用两种语义
对账差异 DIFF + PF-5003 阻断调账,人工走 POST /adjustments 不直改余额表
食谱 / 价格失效 40936 / PF-6001,终端重拉 N-48 不用旧价 / 已下架菜品扣款
已离寓 / 未注册 40937 拒收 不改 finish_ly / ryzt、不改人脸主档
远程点菜误调用 40940 FEATURE_DISABLED 不落订单、不扣款
越权 / 跨 gyid 40301 拒收并记审计 不接受请求参数指定 gyid

表 12-32 权限与审计

# 要求
1 双校验:/apt/** 走 RuoYi 会话 + @PreAuthorize,前端 v-hasPermi 同码;/duty/** 走 duty:ledger:*;/open/v1/** 走设备凭据 + HMAC + 时间窗 + nonce。新增权限点 apt:catering:recipe:*、duty:ledger:confirm 必须登记 sys_menu.perms(docs/公寓端/02 §4.2)
2 职责分离:消费终端 / 签到终端只能提交请求与查询,管理员负责核对与发布,apt.ledger.local 落库,platform-ledger 写主账;设备与前端零余额表写权限
3 二次确认:N-54 充值确认、N-57 食谱发布 / 撤回必须二次确认并写 duty_manual_action
4 审计:选单确认、额度查询(异常时)、扣减、充值申请、核对、作废、发布、撤回、上报、对账十类动作全部记 duty_operation_log(操作人 / 设备、flowId / commandId、前后额度、结果)
5 最小必要:N-49 / N-53 / N-56 不返回人脸媒体;食谱只返回 imageRef 引用;抓拍、录音、签到现场图不出公寓
6 gyid 锁定:只从会话 / 设备凭据解析;所有 SQL 必带 gyid,唯一键以 gyid 打头
7 金额安全:一律字符串两位小数 / decimal(12,2),禁止浮点;服务端按 recipeVersion 重算金额,不信任终端合计

10. 决策点与验收

表 12-33 待决口径(Q-41~Q-45,承接 docs/公寓端/11 Q-40)

编号 事项 默认口径(未决前执行) 拍板时点
Q-41 补贴不足时是否允许现金补足 允许(本流程核心规则);两者合计仍不足则全额拒绝,不部分扣款 阶段二契约冻结前
Q-42 线下充值在断网时是否受 offlineQuota 约束 是;缺省全 0 即断网不开放本地充值记账(沿用 Q-21) 阶段三试点前
Q-43 食谱主数据归属与 knye / xjye 语义复核 平台库 YKT_MEALS 补列 + 公寓只读下发;knye=补贴 / xjye=现金为设计映射,须按 backend/11 存量数据复核 阶段二契约冻结前
Q-44 远程点菜启用条件 本期 features.remoteOrdering=false,仅留 N-58 入口与两表预留;后厨 / 配送 / 结算规则待 平台端/09 P-07 定稿 后续迭代
Q-45 充值单笔上限、是否需要双人复核、内部人员透支 单笔 > 0 且 < 100(沿用 backend/04)、二次确认即可、不允许透支 阶段三试点前

表 12-34 验收要点

# 验收项 判据
1 消费流程 终端按 PUBLISHED 食谱选菜并显示金额;N-49 返回两条额度;扣减严格"补贴优先、现金补足";一笔消费只产生一条 flowId 且 allowanceAmount + cashAmount = abs(amount);CAS 前后值留痕
2 充值流程 扫码只识别公寓、无支付订单与回调;申请表不存金额;管理员二次确认后只增 xjye;channel=OFFLINE_CASH;request_state 沿用三值、终态不可回写
3 菜品管理 阶段性食谱按 recipe_id + version + period + 区间 发布;终端只看到当前有效版;选单确认前不落库;N-58 恒 40940 且 features.remoteOrdering=false
4 提报与同步 #10 LEDGER_OFFLINE 字段与表 12-26 一致;bizId=flowId、idempotencyKey 复用;归日以 serverReceivedAt;日对账通过才置 RECONCILED;差异 PF-5003 阻断调账
5 状态一致性 四条状态链(表 12-4)互不替代;ledger_state / request_state / offline_scope / publish_state 与 §4~§6 状态机、§9 异常表逐项对应;终态不回写
6 异常完整性 余额不足、CAS 冲突、断网超额度、重复提交、对账差异、食谱改价、远程点菜误调用、越权均有明确错误码与"不做什么"
7 边界不破 跨端 20 编号、v2-draft、平台零回调、59 张表、不新增 bizType、apt.ledger.local / platform-ledger 单写入口不变
8 安全与审计 十类动作全部留痕;新增权限点前后端同码并登记 sys_menu.perms;gyid 不可由请求参数指定;金额禁止浮点、服务端重算