团购网站设计:商品、套餐与成交快照

商家修改套餐内容后,历史订单仍应能说明用户当时买了什么。

edyang · 2014-09-05

商家修改套餐内容后,历史订单仍应能说明用户当时买了什么。商品主数据与成交事实要分开。

本文使用团购业务的虚构订单与关系数据模型,伪代码不连接真实支付。团购把用户购买、平台收款、商家履约与结算连接起来。下单、支付、成团、消费和退款必须保留各自状态,不能用一个布尔字段表达整个生命周期。

1. 从现象推到机制

商品描述当前可售内容,套餐规格决定价格与权益,订单行保存成交时的标题、单价和使用规则快照。只存商品外键会让历史订单随着商品修改而改变,难以解释退款和履约争议。

团购网站设计:商品、套餐与成交快照的处理、反馈与观察关系

图中的四个节点分别表示当前套餐、发布版本、下单快照、历史展示。顺着实线检查输入如何变成输出,再沿虚线核对反馈条件。图示表达的是本文讨论的关系,不是实测曲线或现场截图。

2. 最小实现与输入条件

给套餐分配稳定编号,发布新权益时保留版本。下单事务读取当前有效版本并复制必要成交字段,后续展示订单使用快照。

1
2
3
Product -> Offer(version, price, rights)
OrderLine -> offer_id, offer_version
OrderLine -> title_snapshot, price_snapshot, rules_snapshot

先列业务事件与允许的状态迁移,再用少量匿名订单演算。涉及金额的地方保存成交快照,涉及并发的地方使用数据库约束,外部支付行为按支付协议另行实现。

3. 用对照区分原因

下表列出需要主动改变的条件。预期行为来自机制分析,复现时还需记录运行环境和原始输出,不能将预期当作已经测得的结果。

改变的条件 需要验证的行为
商家下调当前价格 旧订单成交价保持原值
套餐权益发生调整 新订单引用新版本规则
商品停止销售 历史订单仍可读取履约信息

对照 1:商家下调当前价格

旧订单成交价保持原值。观察时记录订单快照与当前套餐字段。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 2:套餐权益发生调整

新订单引用新版本规则。观察时记录下单时的版本身份。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 3:商品停止销售

历史订单仍可读取履约信息。观察时记录主数据下架与订单保留策略。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

4. 适用条件与取舍

快照只保存证明成交所需内容,不应无差别复制所有商家资料。保留范围要兼顾可解释性、隐私与存储成本。

一次正常运行只覆盖了这组输入。继续扩展前,应把上面的异常对照保留下来,尤其关注“商品停止销售”这一分支。后续方案若改变了图中任意一处依赖,原来的判断就要重新验证,不能仅凭界面相似或返回值相同沿用结论。

同月延伸

参考资料

  1. Spring 3.2.6 事务管理
  2. Hibernate 4.3 事务与并发