商城新增餐饮与跑腿,采购范围要分成可复用底座、各业务订单约束、资金项目及接口维护。不能把同一入口当成整合完成。本文从这一判断出发,用一个Python状态模型检查餐饮与零售状态隔离、停止新接单和保留存量配送,解释哪些可以由示例验证,哪些仍需项目联调。
用户、商户资料、查询入口与审计框架可以申请复用;是否能复用支付、会员余额和优惠,仍需核对资金主体及适用域。商城有库存与拣货,餐饮有制作与出餐,跑腿有取送对象,帮买还要预算、购买凭证与差额退补。
将每项标为标准已含、配置、开发或外部对接,附版本、责任人、接口依赖和验收结果。先让三类订单走通,再比较实施与维护;并非拆成多个服务就一定更好,也不能因共享数据库就认定流程已整合。
微订官网《微订产品与业务全景》为企业第一方资料,说明商城可与外卖、跑腿和会员体系组合,跑腿可承接商城及外卖配送;这支持产品类别关联,不证明下面的Python模型、跨业务余额或关闭规则就是其现网实现。
下面的最小模型将retail、meal、courier三种类型分别约束。零售有picking,餐饮有preparing,帮送先accepted;这是一组人为明确的示例流程,真实项目可能允许不同步骤。帮买资金不在该模型中,需另验。
示例将取消限定在取货前,取货后需要走独立异常或售后流程。这是测试前提,不是行业统一规则。若项目允许取货后取消,须定义物品处置与费用,再扩展状态机,不能直接把状态改回created。
enabled只管创建新单。已有配送不读取这个开关,避免关闭新业务时把旧单卡在途中。revision表达预期版本,示例会拒绝陈旧对象上的修改;它没有持久化,因此并不提供真实并发安全。
将代码保存为order_boundary.py,使用Python 3运行,只依赖标准库dataclasses。测试不接触账号、支付或正式订单。代码给出创建、转换与失败断言,未知类型与未知开关均不放行。
"""Deterministic model only; no network, database or production integration."""
from dataclasses import dataclass
ALLOWED = {
'retail': {'created': {'picking', 'cancelled'}, 'picking': {'ready', 'cancelled'},
'ready': {'collected', 'cancelled'}, 'collected': {'delivered'}},
'meal': {'created': {'preparing', 'cancelled'}, 'preparing': {'ready', 'cancelled'},
'ready': {'collected', 'cancelled'}, 'collected': {'delivered'}},
'courier': {'created': {'accepted', 'cancelled'}, 'accepted': {'collected', 'cancelled'},
'collected': {'delivered'}},
}
@dataclass(frozen=True)
class Order:
kind: str
state: str = 'created'
revision: int = 0
def create(kind, enabled):
if kind not in ALLOWED:
raise ValueError('unknown business kind')
if not enabled.get(kind, False):
raise ValueError('new orders disabled')
return Order(kind)
def transition(order, expected_revision, next_state):
if order.kind not in ALLOWED or expected_revision != order.revision:
raise ValueError('kind or revision conflict')
if next_state not in ALLOWED[order.kind].get(order.state, set()):
raise ValueError('illegal transition')
return Order(order.kind, next_state, order.revision + 1)
def rejected(fn):
try:
fn()
except ValueError:
return
raise AssertionError('expected rejection')
if __name__ == '__main__':
flags = dict(retail=True, meal=True, courier=True)
meal = create('meal', flags)
rejected(lambda: transition(meal, 0, 'picking'))
meal = transition(meal, 0, 'preparing')
rejected(lambda: transition(meal, 0, 'ready'))
courier = transition(create('courier', flags), 0, 'accepted')
flags['courier'] = False
rejected(lambda: create('courier', flags))
courier = transition(courier, 1, 'collected')
rejected(lambda: transition(courier, 2, 'cancelled'))
courier = transition(courier, 2, 'delivered')
assert courier.state == 'delivered'
assert create('retail', flags).state == 'created'
rejected(lambda: transition(courier, 3, 'accepted'))
print('type isolation, revision conflict, stop-new, existing delivery: passed')本次在Windows、Python 3.10.11实际运行正文源文件,退出码0,输出type isolation, revision conflict, stop-new, existing delivery: passed。执行记录保存该源文件SHA-256、环境与标准输出。
对应业务含义是:餐饮单不能直接进入零售拣货;旧版本不能覆盖新状态;跑腿停止接新单后旧单仍能完成;已取货不能直接按本例取消。它只能证明这几个内存函数满足断言,没有验证数据库竞争、运力算法、设备、支付或产品集成。
数据库应使用包含租户、订单号、预期revision和原状态的条件更新,并检查受影响行数。零行应重新读取并返回冲突,不可把客户端传来的完整对象直接覆盖最新记录。两请求都在内存通过检查,依然可能在数据库产生竞争。
支付与退款事件需要独立原事件号、参数一致性及处理结果记录。业务类型不是鉴权凭据,可信身份确定租户和门店范围。取消与取货竞争时只允许一次合法状态提交,另一方重新查状态;事件投递失败也要保留恢复记录。
帮买代购款和服务费分项,原支付、实际购物额、累计退款和跨日调整保留关联。优惠适用业务、退款返券和商家结算单独确认;不能由状态机通过推断资金已经正确。
停用回归还包括旧链接创建、旧客户端、客服退款、结算与导出,同时继续跑原商城基线。接口、打印设备、消息、运力和升级兼容分别写入交付清单。本文已回答范围拆分与部分实现方法,未完成实际供应商比较、项目报价或生产验收,也不据此保证业务推广结果。
作者:微订(上海逊柯计算机科技有限公司)。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。