熟食消费模式实现方案

1. 方案结论

在现有 SellWeight 称重和结算能力上新增独立的 CookedFoodActivity,复用底层称重、支付和订单能力;不继承麻辣烫 WeightActivity,不改变服务端订单协议,不复用 categories 保存熟食明细。

核心原则:

  1. 称重硬件复用,业务状态独立。
  2. 熟食商品本地维护,价格以 500g 为固定基准。
  3. “加入购物车”是显式命令,不是重量变化事件。
  4. 购物车按商品标识合并,订单行保存价格快照。
  5. 本地展示明细与服务端上传摘要物理分离。

2. 当前代码依据

能力当前位置影响
首页进入称重HomeActivity增加熟食入口或模式参数
称重主流程CookedFoodActivity复用称重回调,独立维护熟食状态机
商品模型ProductBean增加计价基准和熟食类型
商品数据库ProductDatabaseHelper增加熟食商品字段和迁移
设置页WeightSetActivity增加“熟食设置”同级页签
支付请求OrderPaymentRequest仍只构造一条 custom_dish
本地订单OrderOrderDao新增独立熟食明细字段
离线补传UploadOrderWorker只从 categories 读取单条上传摘要
稳定重量ScaleProtocolParser加入操作必须检查稳定标志

3. 推荐数据模型

3.1 本地商品

在现有商品模型基础上增加:

type = TYPE_COOKED_FOOD
basisGrams = 500
enabled
sort

商品表保留现有字段,并新增 basis_gramsenabledsort;熟食商品固定保存 basis_grams=500,设置页只读展示计价基准。

数据库版本从 1 升级到 2 时使用 ALTER TABLE 增加字段并设置默认值,禁止沿用当前“删除整表后重建”的升级方式,以免丢失已配置的汤底和其他本地商品。

3.2 购物车行

CookedFoodCartLine
- productId
- nameSnapshot
- unitPriceSnapshot
- basisGrams = 500
- weightGrams
- amount

合并键为 productId。同一商品再次加入时只累加 weightGrams,再按快照单价重新计算 amount

3.3 本地订单明细

推荐在 Order 增加 cookedFoodDetails 字段,以版本化 JSON 保存熟食明细;由 OrderDao 独立序列化到订单表的新列。字段名可采用 cooked_food_details,与现有 categories 并列。

CookedFoodOrderDetails
- version
- lines[]
- customAmount
- cookedFoodAmount
- totalAmount

保存时写入已合并的购物车行和价格快照,不保存实时秤重引用。读取失败时不影响旧订单上传,但详情页应给出降级展示或空明细提示。

4. 结算与离线补传

4.1 在线支付

结算时使用统一金额汇总器计算总额,然后构造:

{
  "dishes": [
    {
      "uuid": "custom_dish",
      "number": "1",
      "money": "totalAmount"
    }
  ]
}

服务端不感知每个熟食商品,熟食商品明细只用于本地订单、显示和审计。

4.2 离线订单

本地保存时同时保存:

5. 页面与状态机

5.1 状态

IDLE_ZERO_WEIGHT
  ├─ 先选商品 → PRODUCT_SELECTED → WEIGHT_UNSTABLE → WEIGHT_STABLE
  └─ 先放商品 → WEIGHT_UNSTABLE → WEIGHT_STABLE → PRODUCT_SELECTED_STABLE
                                      ↓
                              ADDED_TO_CART
                                      ↓
                              IDLE_ZERO_WEIGHT

异常状态包括 NO_PRODUCTZERO_WEIGHTUNSTABLE_WEIGHTINVALID_EDIT_WEIGHT。这些状态只阻止当前动作,不清空已有购物车。

5.2 关键动作

动作前置条件结果
选择商品当前重量为 0,或当前重量已稳定且尚未绑定商品设置当前商品,不入车
加入购物车当前商品存在、重量大于 0、重量稳定新增或合并购物车行
归零清除当前称重重量,保留购物车
编辑重量购物车行存在更新行重量和金额
删除购物车行存在删除行并重算金额
结算至少存在有效金额先显示对账单,确认后保存本地订单并发起支付

6. 设置实现

WeightSetActivity 的页签和 Fragment 列表中增加 FragmentCookedFood 或等价页面。页面沿用现有汤底设置的 CRUD 交互,但商品保存到 TYPE_COOKED_FOOD,并将 500g 作为只读计价基准。

当前订单已加入的购物车行必须保存商品名称和单价快照;设置页修改商品后,只影响后续新加入的行。

7. 金额与精度

8. 实施步骤

  1. 增加熟食商品类型、字段、DAO 和数据库安全迁移。
  2. 增加熟食设置页,实现本地商品 CRUD 和启停。
  3. 增加熟食称重模式入口及“归零—选择—稳定—主动加入”状态机。
  4. 实现购物车同品合并、删除、重量编辑和金额汇总。
  5. 增加本地熟食明细字段及独立序列化/反序列化。
  6. 统一在线支付和离线保存使用单条 custom_dish 上传摘要。
  7. 补齐订单详情、离线补传和旧功能回归测试。

9. 风险与控制

风险控制措施
秤重变化误入车只有点击加入才提交快照
未稳定重量计入加入前校验 isWeightStable()
商品设置改价影响历史订单购物车和订单保存价格快照
离线补传拆分熟食明细明细与 categories 分字段保存
数据库升级丢配置使用版本迁移,不删除整表
金额字段不兼容DishItem.money 为上传唯一格式并测试
旧麻辣烫流程受影响熟食类型、入口和状态分支隔离,做回归测试

10. 定值商品点选补充方案

10.1 决策

熟食商品继续统一在本地维护,但新增 saleMode 区分两类商品:SALE_MODE_WEIGHT = 1 为按重量计价、单价单位固定为 500g;SALE_MODE_FIXED = 2 为定值商品、单价单位固定为份。历史熟食商品迁移后默认按重量计价,商品表新增 sale_mode,数据库版本升至 3,使用增列迁移保留既有配置。

10.2 收银交互

10.3 购物车与本地明细

商品类型合并方式金额公式可编辑字段
称重熟食同商品累计重量unitPrice × weightGrams ÷ 500重量(g)
定值商品同商品累计数量unitPrice × quantity数量(份)

CookedFoodCartLine 保存 saleModeweightGramsquantity 与价格快照;CookedFoodOrderDetails 升级为版本 2。上传仍只构造一个 custom_dish,不改变 categoriescooked_food_details 的职责分离。