团购网站设计:消费券核销怎样避免重复使用

消费券二维码只是载体,核销是否成功需要由服务端以同一条券记录裁决。

edyang · 2014-10-05

消费券二维码只是载体,核销是否成功需要由服务端以同一条券记录裁决。

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

1. 从现象推到机制

券码不应包含可直接信任的余额或核销结果。商家发起核销时,服务器先验证商家与券的适用关系,再执行未使用到已使用的条件迁移。网络重试需要返回同一核销身份,而不是再次消费。

团购网站设计:消费券核销怎样避免重复使用的处理、反馈与观察关系

图中的四个节点分别表示券码输入、商家校验、条件核销、核销流水。顺着实线检查输入如何变成输出,再沿虚线核对反馈条件。图示表达的是本文讨论的关系,不是实测曲线或现场截图。

2. 最小实现与输入条件

用不可预测的演示令牌映射券记录。核销事务记录操作者类别、商户和业务时间,日志中避免完整展示可使用券码。

1
2
3
UPDATE voucher SET state = :used, redeemed_at = :now
WHERE id = :id AND merchant_id = :merchant
  AND state = :unused;

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

3. 用对照区分原因

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

改变的条件 需要验证的行为
同一券并发核销两次 只能有一次成功迁移
另一商家尝试核销 应被适用关系校验拒绝
成功响应在网络中丢失 重试可查询原核销结果

对照 1:同一券并发核销两次

只能有一次成功迁移。观察时记录条件更新行数与核销流水。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 2:另一商家尝试核销

应被适用关系校验拒绝。观察时记录券对应商户与请求身份。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

对照 3:成功响应在网络中丢失

重试可查询原核销结果。观察时记录稳定核销请求号。把这个条件与基准情形分开,有助于判断变化来自哪一层;若得到相反结果,应先核对前提,再修改实现。

4. 适用条件与取舍

券码保密与账号权限同样重要。离线核销会引入重复使用风险,必须另设受控额度和后续冲突处理,不能直接复用在线流程的承诺。

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

同月延伸

参考资料

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