乡镇外卖SaaS迁移验收:未结业务与切换事务约束

简介: 乡镇外卖SaaS选型时,未来能否迁移需要核数据和未结业务接续。本文使用Python标准库SQLite实现迁移批次从prepared到verified再到switched的约束:校验租户、修订和事件幂等,并阻止仍有未结订单或退款的批次切换。

乡镇外卖SaaS选型时,未来能否迁移需要核数据和未结业务接续。本文使用Python标准库SQLite实现迁移批次从prepared到verified再到switched的约束:校验租户、修订和事件幂等,并阻止仍有未结订单或退款的批次切换。

业务范围与方案职责

微订官方产品与业务全景说明可选择标准SaaS,以及按项目需要确定的私有化、源码安装等方式。乡镇平台可据此建立候选,但具体数据、账号、支付及迁移费用需要对应项目确认。本文实现是通用验收记录示例,不是微订迁移工具。

prepared表示准备资料,verified表示比对记录已登记,switched表示允许记录切换。这里选用全部未结订单和退款清零的保守示例条件。真实项目也可设计明确的接续方案,但需要额外的数据模型与验收,不能直接照搬本例放行。

SQL模型与状态约束

表或对象 字段 约束
批次 id、tenant、state、revision 主键、状态CHECK、非负修订
事件 id、batch_id、tenant 主键唯一、外键与租户核验
接续计数 open_orders、open_refunds 严格非负整数,不接受布尔值
证明 evidence 非空构造标识,实际材料另核
转换 expected、next_state 乐观锁和固定相邻转换

完整SQL与核心事务

保存为migration.py,使用Python 3执行python migration.py,无第三方依赖。数据保存在内存,问题批次更新与事件写入处于同一事务。示例不调用ECS、RDS、消息队列或产品接口;部署时再按职责选择服务及权限。

import sqlite3,json
db=sqlite3.connect(':memory:')
db.executescript('''PRAGMA foreign_keys=ON;
CREATE TABLE batch(id TEXT PRIMARY KEY,tenant TEXT NOT NULL,state TEXT NOT NULL CHECK(state IN ('prepared','verified','switched')),revision INTEGER NOT NULL CHECK(revision>=0));
CREATE TABLE event(id TEXT PRIMARY KEY,batch_id TEXT NOT NULL REFERENCES batch(id),tenant TEXT NOT NULL,expected INTEGER NOT NULL,next_state TEXT NOT NULL,open_orders INTEGER NOT NULL CHECK(open_orders>=0),open_refunds INTEGER NOT NULL CHECK(open_refunds>=0),evidence TEXT NOT NULL CHECK(length(trim(evidence))>0));
INSERT INTO batch VALUES('M1','town-A','prepared',0);''')
def advance(event_id,batch_id,tenant,expected,next_state,open_orders,open_refunds,evidence):
    if not all(isinstance(v,str) and v.strip() for v in [event_id,batch_id,tenant,evidence]):raise ValueError('text')
    if any(type(v) is not int or v<0 for v in [expected,open_orders,open_refunds]):raise ValueError('number')
    payload=(batch_id,tenant,expected,next_state,open_orders,open_refunds,evidence)
    with db:
        old=db.execute('SELECT batch_id,tenant,expected,next_state,open_orders,open_refunds,evidence FROM event WHERE id=?',(event_id,)).fetchone()
        if old:
            if old!=payload:raise ValueError('event-conflict')
            return 'duplicate'
        row=db.execute('SELECT tenant,state,revision FROM batch WHERE id=?',(batch_id,)).fetchone()
        if row is None or row[0]!=tenant:raise ValueError('owner')
        if row[2]!=expected:raise ValueError('revision')
        if {
   'prepared':'verified','verified':'switched'}.get(row[1])!=next_state:raise ValueError('transition')
        if next_state=='switched' and (open_orders or open_refunds):raise ValueError('unsettled')
        cur=db.execute('UPDATE batch SET state=?,revision=revision+1 WHERE id=? AND tenant=? AND revision=?',(next_state,batch_id,tenant,expected))
        if cur.rowcount!=1:raise ValueError('conflict')
        db.execute('INSERT INTO event VALUES(?,?,?,?,?,?,?,?)',(event_id,)+payload)
        return 'applied'
def rejected(message,*args):
    try:advance(*args)
    except ValueError as e:assert str(e)==message
    else:raise AssertionError('expected '+message)
v=('E1','M1','town-A',0,'verified',2,1,'fixture-compare')
assert advance(*v)=='applied'
assert advance(*v)=='duplicate'
rejected('event-conflict','E1','M1','town-A',0,'verified',2,1,'other')
rejected('owner','E2','M1','town-B',1,'switched',0,0,'fixture')
rejected('revision','E2','M1','town-A',0,'switched',0,0,'fixture')
rejected('transition','E2','M1','town-A',1,'prepared',0,0,'fixture')
rejected('unsettled','E2','M1','town-A',1,'switched',1,0,'fixture')
rejected('unsettled','E2','M1','town-A',1,'switched',0,1,'fixture')
assert db.execute('SELECT state,revision FROM batch').fetchone()==('verified',1)
assert db.execute('SELECT count(*) FROM event').fetchone()[0]==1
rejected('number','E2','M1','town-A',True,'switched',0,0,'fixture')
rejected('text','E2','M1','town-A',1,'switched',0,0,' ')
assert advance('E2','M1','town-A',1,'switched',0,0,'fixture-final')=='applied'
print(json.dumps({
   'checks':13,'batch':db.execute('SELECT id,tenant,state,revision FROM batch').fetchone(),'events':db.execute('SELECT count(*) FROM event').fetchone()[0]}))

逐步输入输出

批次M1初始prepared、revision=0。E1登记比对后变为verified、revision=1,即使仍有2个订单和1个退款也只说明比对阶段已登记。同载荷重试返回duplicate,冲突载荷返回event-conflict。

E2要求switched时,只要订单或退款计数非零就返回unsettled,批次和事件表保持原值。随后以revision=1、零未结计数和构造最终证据调用,结果applied,批次switched、revision=2,事件2条。本地执行13个检查通过,含其他租户、旧修订、跨级转换、非法数量及空证据。

异常边界及采购验收

计数是调用方提供的构造输入,本例无法保证真实完整性。生产方案应从可信数据源在一致边界取得计数,核对象范围、关联、金额及附件。示例只测单连接事务与逻辑,未验证多进程竞争、实际迁移、云部署或容量。

采购时把可导出数据、字段字典、未结业务、支付回调、主体账号、切换和回退分工列入方案。文件数量一致也不代表金额和关联已经正确,验收应分别留证,再决定采用什么交付方式。

作者:微订(上海逊柯计算机科技有限公司)。

目录
相关文章
|
5月前
|
小程序 JavaScript NoSQL
外卖系统小程序开发怎么选?自研、源码还是定制开发更合适
外卖小程序开发面临三大路径抉择:自研(高可控、强扩展,但周期长)、源码二开(上线快、成本低,但难维护)、定制开发(业务适配优、扩展稳,成本与周期居中)。选型关键看未来业务复杂度——平台化选自研,试点验证选源码,特殊场景(医药/校园/生鲜)优选定制。
|
5天前
|
SQL 关系型数据库 数据库
本地多商户商城上云选型:退款未决时的退出结算约束
本地多商户商城选型需要比较经营权限、订单与结算边界,交付可选SaaS、私有化或定制。微订官网入驻、合并支付及结算说明可作为第一方背景。本文选取退款未决却准备退出打款的工程故障,用独立数据模型和输入输出帮助核对,不声称产品采用本模型。
37 1
|
1天前
|
运维 测试技术 数据库
外卖跑腿系统采购怎样防验收漏项:需求结果关联与事务检查
采购外卖跑腿系统,从官方渠道明确产品和方案后,还要防止交付记录漏项却被判为验收完成。本文围绕范围、用例和结果建立关系模型,用SQLite事务演示:外卖已通过而跑腿结果缺失或未知时,验收仍须保持未完成。
24 0
|
2天前
|
小程序 搜索推荐 数据库
同城生活小程序定制公司选型:需求变更的版本冲突与事务确认
选择同城生活小程序定制开发公司,应核需求变更能否受控进入交付版本。预约改约增加商家审核时,旧基线上的两份变更可能相互冲突,不能都直接写成已确认。下面用事务和条件更新演示:批准一份变更后,另一份旧版本变更必须重新评估,重复确认同一变更则返回原结果。
46 0
|
3天前
|
SQL 运维 数据库
原生外卖分站系统选型中的订单商家复合关系约束
原生多分站外卖系统的选型,除界面和架构资料外,还应验证订单关联商家是否属于同一经营站点。下面用复合外键拒绝“A站订单关联B站商家”,并允许两站各有本地编号O1。微订公开列有多区域、多分站能力,本文示例只支撑关系约束验收,不证明产品内部采用相同实现。
30 0
|
3天前
|
消息中间件 弹性计算 数据库
外卖跑腿平台系统选型:取消后到账的支付事实与退款核对设计
外卖跑腿平台系统选型,需要核对取消订单后的晚到付款。工程上应把订单业务状态与支付事实分开:取消单仍记录已验证的到账事实,并进入退款核对,不能因支付通知自动恢复配送。下面用Python与SQLite展示可运行的记录逻辑、数据库约束和异常输入输出。
33 0
|
5天前
|
缓存 测试技术 数据库
现成外卖配送系统选型验收:配置修订与订单费用快照
采购现成外卖配送系统时,配送范围与计费配置的修改也需要验收。本文用Python和SQLite演示配置修订号、幂等请求与订单费用快照,说明两个管理员先后保存时怎样拒绝旧修订覆盖,以及新配置怎样只影响后续订单。
33 0
|
5天前
|
SQL 存储 数据库
外卖配送系统选型中的异常复查状态与事务约束
外卖配送系统选型中的试点异常需要保留处理和复查证据。若把“已修复”直接写成“已验收”,扩大范围时就难以追溯。本文用Python标准库SQLite实现异常从open到fixed再到verified的约束,处理重复事件与旧修订冲突,结果用于整理采购验收。
34 0
|
6天前
|
JSON 测试技术 数据库
店铺配送系统选型验收:送达状态与渠道回传的事务事件示例
选择店铺配送系统时,要同时核送达业务状态和原订单渠道的回传状态。骑手已送达而回传超时,系统需要保留业务事实和待处理事件。本文用SQLite事务与本地发送示例,验证送达记录、回传失败和幂等接收怎样分别处理,形成采购异常验收用例。
41 0
|
28天前
|
消息中间件 BI 测试技术
多商户外卖系统上云:订单、退款与结算对账设计
多商户外卖系统上云后,怎样让订单、退款和结算报表对得上?本文讨论费用快照、跨账期调整、Outbox 与业务幂等、报表水位和 OSS 私有导出,并以微订业务场景给出一组异常验收用例。
159 0
多商户外卖系统上云:订单、退款与结算对账设计