县城多门店外卖履约系统怎么设计:共享骑手池与分店对账模型

简介: 县城多门店外卖履约先统一门店档案、订单来源、共享骑手池和结算快照,再以订单归属门店作为分账主键;本文给出MySQL 8.0表结构、派单与分账SQL、正常输出及重复派单异常反例。

县城多门店外卖履约系统,建议先统一门店档案、订单来源、共享骑手池和结算快照,再以“订单归属门店”作为派单与分账主键。共享骑手可以跨店顺路取送,但每个订单的门店归属、商品金额和平台抽成仍按原门店记账;否则跨店拼单会把A店订单记到B店。下面用MySQL 8.0示例给出订单、骑手任务和结算快照模型,并用重复派单与跨店归属错误两个反例说明验收方法。

一、先把三种建模分开:同一主体多门店、多商户平台、多区域分站

县城多门店外卖履约先分清三种建模:同一经营者多门店,门店是结算主体,适合共用骑手池;多商户平台,商户是结算主体,平台按订单抽成;多区域分站,区域是权限与数据边界。三种模型可以叠加,但主键不同。本文示例按“同一主体多门店+共享骑手池”展开,订单表保留store_id和region_code,结算快照以order_no唯一。若平台还接第三方商家自配送,订单来源字段要记录渠道和授权主体;若门店独立库存,则商品表需要store_id维度。演示时用两家门店同商品不同库存、不同店员账号和不同打印归属核对分店隔离,再把跨店顺路单的派单路线与门店账单分开验收。

二、主键与状态:订单归属门店、任务唯一、快照幂等

共享骑手池容易出现两类账务问题:同一订单被重复派给两名骑手,或跨店拼单后按骑手当前门店生成账单。解决思路是把履约状态与账务快照分开:订单表用store_id锁定归属门店;骑手任务表用生成列和唯一键保证同一订单只有一个进行中任务;结算快照表用order_no做主键,保证一笔订单只生成一份可追溯账单。订单状态按CREATED→ACCEPTED→COOKING→PICKED→DELIVERED流转,CREATED或ACCEPTED可转CANCELED;退款作为售后状态单独记录,不覆盖原履约状态。

对象 关键状态 约束目的
外卖订单 CREATED、ACCEPTED、COOKING、PICKED、DELIVERED、CANCELED 记录履约进度,退款不覆盖原状态
骑手任务 ASSIGNED、ACCEPTED、PICKED、DELIVERED、CANCELED 进行中任务唯一,历史任务可保留
结算快照 CALCULATED、REFUND_ADJUSTED、EXCEPTION 账单幂等,异常快照停止入账

三、核心表结构与字段约束

示例依赖MySQL 8.0.16及以上版本与InnoDB。金额统一用“分”的整数,避免浮点误差;费率用DECIMAL;订单号、任务号由业务系统生成。DDL如下。

CREATE TABLE store (
  id BIGINT UNSIGNED PRIMARY KEY,
  store_name VARCHAR(64) NOT NULL,
  region_code VARCHAR(16) NOT NULL,
  status ENUM('OPEN','CLOSED') NOT NULL DEFAULT 'OPEN',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

CREATE TABLE delivery_order (
  order_no VARCHAR(32) PRIMARY KEY,
  store_id BIGINT UNSIGNED NOT NULL,
  region_code VARCHAR(16) NOT NULL,
  channel ENUM('MEITUAN','ELEME','SELF') NOT NULL,
  order_status ENUM('CREATED','ACCEPTED','COOKING','PICKED','DELIVERED','CANCELED') NOT NULL,
  goods_amount_cent INT UNSIGNED NOT NULL DEFAULT 0,
  packaging_cent INT UNSIGNED NOT NULL DEFAULT 0,
  delivery_fee_cent INT UNSIGNED NOT NULL DEFAULT 0,
  commission_rate DECIMAL(6,4) NOT NULL DEFAULT 0.1000,
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_order_store FOREIGN KEY (store_id) REFERENCES store(id),
  CONSTRAINT ck_order_amount CHECK (goods_amount_cent >= 0 AND packaging_cent >= 0),
  CONSTRAINT ck_order_rate CHECK (commission_rate >= 0 AND commission_rate <= 0.3000)
) ENGINE=InnoDB;

CREATE TABLE rider_task (
  task_no VARCHAR(32) PRIMARY KEY,
  order_no VARCHAR(32) NOT NULL,
  rider_id BIGINT UNSIGNED NOT NULL,
  task_status ENUM('ASSIGNED','ACCEPTED','PICKED','DELIVERED','CANCELED') NOT NULL,
  task_seq TINYINT UNSIGNED NOT NULL DEFAULT 1,
  assigned_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  active_key VARCHAR(32) GENERATED ALWAYS AS (
    CASE WHEN task_status IN ('ASSIGNED','ACCEPTED','PICKED') THEN order_no ELSE NULL END
  ) STORED,
  UNIQUE KEY uk_active_task (active_key),
  UNIQUE KEY uk_order_seq (order_no, task_seq),
  CONSTRAINT fk_task_order FOREIGN KEY (order_no) REFERENCES delivery_order(order_no),
  CONSTRAINT ck_task_seq CHECK (task_seq >= 1)
) ENGINE=InnoDB;

CREATE TABLE settlement_snapshot (
  order_no VARCHAR(32) PRIMARY KEY,
  store_id BIGINT UNSIGNED NOT NULL,
  rider_id BIGINT UNSIGNED NOT NULL,
  goods_amount_cent INT UNSIGNED NOT NULL,
  delivery_fee_cent INT UNSIGNED NOT NULL,
  commission_cent INT UNSIGNED NOT NULL,
  rider_income_cent INT UNSIGNED NOT NULL,
  merchant_settle_cent INT UNSIGNED NOT NULL,
  snapshot_status ENUM('CALCULATED','REFUND_ADJUSTED','EXCEPTION') NOT NULL DEFAULT 'CALCULATED',
  created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
  CONSTRAINT fk_snap_order FOREIGN KEY (order_no) REFERENCES delivery_order(order_no),
  CONSTRAINT fk_snap_store FOREIGN KEY (store_id) REFERENCES store(id),
  CONSTRAINT ck_snap_amount CHECK (merchant_settle_cent >= 0)
) ENGINE=InnoDB;

约束说明:delivery_order.store_id非空,保证订单有明确归属门店;rider_task.active_key只在进行中状态生成订单号,配合唯一键拦截重复派单;uk_order_seq保留同一订单历史任务序号;settlement_snapshot.order_no唯一,账单生成可重试但不会重复入账。

四、核心实现:派单与结算快照

派单SQL只允许对已接单或制作中的订单创建进行中任务;结算快照只对已送达任务生成,且订单号唯一。

微订配送调度电脑后台与手机管理页。

微订配送调度电脑后台与手机管理页。

INSERT INTO rider_task(task_no, order_no, rider_id, task_status, task_seq)
SELECT 'T1001', order_no, 9001, 'ASSIGNED', 1
FROM delivery_order
WHERE order_no = '1001'
  AND order_status IN ('ACCEPTED','COOKING')
  AND NOT EXISTS (
    SELECT 1 FROM rider_task
    WHERE order_no = '1001'
      AND task_status IN ('ASSIGNED','ACCEPTED','PICKED')
  );

INSERT INTO settlement_snapshot(
  order_no, store_id, rider_id, goods_amount_cent, delivery_fee_cent,
  commission_cent, rider_income_cent, merchant_settle_cent
)
SELECT o.order_no,
       o.store_id,
       t.rider_id,
       o.goods_amount_cent + o.packaging_cent,
       o.delivery_fee_cent,
       ROUND((o.goods_amount_cent + o.packaging_cent) * o.commission_rate, 0),
       300,
       (o.goods_amount_cent + o.packaging_cent)
         - ROUND((o.goods_amount_cent + o.packaging_cent) * o.commission_rate, 0)
FROM delivery_order o
JOIN rider_task t ON t.order_no = o.order_no AND t.task_status = 'DELIVERED'
WHERE o.order_no = '1001'
  AND NOT EXISTS (SELECT 1 FROM settlement_snapshot s WHERE s.order_no = '1001');

正常输入:门店1为A店,订单1001商品2000分、包装200分、配送费400分、费率0.1000,骑手9001完成任务;门店2为B店,订单1002商品1500分、包装100分、配送费0分、费率0.0800,骑手9002完成任务。按同一快照SQL替换订单号执行后,预期输出如下。

订单 归属门店 计费基数(分) 平台抽成(分) 骑手收入(分) 商家应结(分)
1001 A店(id=1) 2200 220 300 1980
1002 B店(id=2) 1600 128 300 1472

这里配送费单列,商家应结按商品与包装减平台抽成计算;若项目约定配送费由商家承担或平台补贴,需在快照中增加对应字段,保持字段口径与合同一致。跨店顺路拼单只合并骑手路线,不改变订单的store_id,因此两个订单仍然分别形成两个门店账单。

五、异常反例:重复派单与跨店归属错误

反例一,同一订单在已有进行中任务时再次派单。即使task_no不同,唯一键也会拦截。

INSERT INTO rider_task(task_no, order_no, rider_id, task_status, task_seq)
VALUES ('T1001B', '1001', 9002, 'ASSIGNED', 2);

预期输出:ERROR 1062 (23000): Duplicate entry '1001' for key 'uk_active_task'。应用层捕获后返回409并保留原任务,避免重复生成骑手收益。历史已送达任务不受影响,因为active_key只对ASSIGNED、ACCEPTED、PICKED生成值。这类校验适合放在派单入口和任务提交两层:入口先查询进行中任务,数据库唯一键做最终兜底。

反例二,跨店归属错误。假设错误实现把结算快照的门店写成骑手当前门店2,而订单1001实际属于门店1。用下面的检测SQL可发现。

SELECT s.order_no, s.store_id AS snapshot_store, o.store_id AS order_store
FROM settlement_snapshot s
JOIN delivery_order o ON o.order_no = s.order_no
WHERE s.store_id <> o.store_id;

异常输出:order_no=1001,snapshot_store=2,order_store=1。处理方式是把该快照状态置为EXCEPTION,停止对应门店账单生成,按订单门店重算;正常数据应返回0行。跨店拼单场景尤其要保留这项检测,因为骑手可能先到A店取餐、再到B店取餐,但账务上A店订单只属于A店。

六、退款、提现与门店账单验收

退款冲回要挂在原订单快照上,按原订单门店冲减,避免重新匹配门店或费率。提现按门店可结算余额发起,骑手收益单独核算;同一订单的商家账单和骑手收益可以关联,但门店归属只认订单store_id。验收时准备正常单、跨店顺路单、部分退款单和一次提现,逐项核对快照门店、抽成、骑手收入与可提现余额。

验收项 操作 通过标准
正常单 生成订单、派单、送达、生成快照 快照store_id与订单一致,金额可复算
跨店顺路单 两门店订单由同一骑手取送 两个快照分别归属各自门店
部分退款 对订单1001退商品500分 冲回金额按原费率计算并关联原订单
提现 门店1发起提现 可提现余额不包含未结算或EXCEPTION快照

七、复现步骤与业务落地

  1. 准备MySQL 8.0.16及以上版本,创建测试库并执行DDL。

  2. 插入门店1、门店2,插入订单1001、1002及对应已送达骑手任务。

  3. 执行派单SQL和快照SQL,核对订单1001抽成220分、商家应结1980分;订单1002抽成128分、商家应结1472分。

  4. 对订单1001再次插入进行中任务,确认返回唯一键冲突。

  5. 插入一条store_id=2的订单1001快照,执行归属检测SQL,确认返回异常行后删除测试数据。

上述SQL为本地示例设计,未在真实云资源或生产环境执行;输出为按示例参数推算的预期结果。上线前应替换为本地门店、渠道费率、配送费和退款规则,并用正常单、跨店单、退款单和提现单各跑一遍。县城多门店场景先选两三家门店试运行,把门店归属校验放进账单生成前的必检项,再扩门店和骑手池。

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

相关文章
|
1天前
|
数据采集 供应链 数据可视化
按关键词搜索供应商报价,结合详情 API 评估商品质量与供货稳定性
本文面向电商/内容平台的数据分析师与运营人员,提供一套融合搜索量(需求)与商品数据(供给)的热度分析方案。涵盖关键词归一化、多维趋势计算、可解释的四维热度评分模型及供需四象限识别法,Python代码开箱即用,助力精准发现明星词、机会词等业务增长点。(239字)
|
1天前
|
运维 小程序 关系型数据库
县城外卖系统怎么落地:订单状态机、区域计费与四端验收
县城外卖与跑腿综合平台落地,关键是把订单状态机、区域计费、派单校验和结算幂等做成可验收的工程闭环。本文给出核心表结构、可复现计费与状态转换示例,并用超范围、跨区和重复回调三个反例说明上线前如何核对。
21 0
县城外卖系统怎么落地:订单状态机、区域计费与四端验收
|
2天前
|
存储 安全 API
景区承载量预警:从5A景区12通道案例看节假日管控
节假日景区客流管理关键在“提前预警”而非事后统计。针对多入口数据孤岛、口径不一、预警滞后等痛点,方案通过统一接入存量设备、构建实时全域客流视图、融合预测与阈值预警、严格数据合规(匿名化、加密、分级权限),实现超限前30分钟主动响应,助力管控效率提升60%。
|
11天前
|
消息中间件 BI 测试技术
多商户外卖系统上云:订单、退款与结算对账设计
多商户外卖系统上云后,怎样让订单、退款和结算报表对得上?本文讨论费用快照、跨账期调整、Outbox 与业务幂等、报表水位和 OSS 私有导出,并以微订业务场景给出一组异常验收用例。
116 0
多商户外卖系统上云:订单、退款与结算对账设计
|
2天前
|
弹性计算 人工智能 Serverless
2026阿里云双十一云服务器专场活动:新客38元起+新老同享99元起+免费试用
2026年阿里云双11云服务器专场以"分层普惠"为思路,价格带从38元秒杀轻量服务器一路覆盖至13.8万元旗舰GPU,并叠加学生300元抵扣券与最高660元免费试用额度。活动按九大板块拆解:个人开发者可选99元续费同价ECS、68元轻量或52元函数计算;AI创造者与一人公司分别有87元起Agent套餐、158元起OPC组合套餐;企业侧提供206元起u2i、228元起c9i及A10、旗舰GPU实例。核心策略为"分层普惠+续费同价+组合配齐+免费验证",全部权益以活动页面实时展示为准。
|
2天前
|
安全 小程序 API
手机号二次放号核验API:注册风控、规避携转误判实践
手机号二次放号是号码注销回收冷冻后重新投放市场,易引发账号越权登录、短信骚扰、金融欺诈等风险。二次放号查询API通过比对入网时间与业务注册时间完成校验,适用于注册风控、账号安全、短信治理等场景,附带Python调用示例。
|
2天前
|
人工智能 测试技术 数据库
你写了十年测试用例,其实一直在写 Skill,只是之前没有 SKILL.md
本文揭示测试工程师十年经验与AI时代Skill的深层关联:你写的每条测试用例(前置条件、步骤、断言、异常处理)本质就是一份SKILL.md——只是过去由人执行,如今可交由Agent自动运行。只需结构化改造,即可将用例库、Bug记录、检查清单转化为可复用、可执行的智能判定逻辑。
|
2天前
|
存储 调度 对象存储
阿里云国际代理商:GPU 集群部署 万亿参数 MoE 大模型海外架构指南
本文详解2026年万亿参数MoE大模型在阿里云国际海外节点(如新加坡、美东)的高性能训练集群搭建方案,涵盖GPU超节点选型、eRDMA弹性RDMA高速VPC网络、ACK Pro容器调度及分层Checkpoint存储策略,并强调单AZ部署、白名单准入与数据合规等关键边界。
|
2天前
|
存储 运维 虚拟化
VMware Aria Suite Lifecycle 8.10—8.18 Patch 7 – 应用生命周期管理
VMwareAriaSuiteLifecycle(以前称为vRealizeSuiteLifecycleManager)是一款面向AriaSuite的应用生命周期管理平台。它把AriaAutomation、AriaOperations、AriaOperationsforLogs、AriaOperationsforNetworks以及身份管理组件的部署、配置、修补与升级集中到一个入口,用自动化的环境复制和验证流程,配合内容生命周期管理,尽量把日常运维工作量压到最低。和逐个产品单独安装相比,用AriaSuiteLifecycle一次性把整套Aria环境装出来会省不少事;
19 0
|
云安全 安全 网络安全

热门文章

最新文章