data-model.md 5.8 KB

Data Model: 商家自配送 (029)

Date: 2026-09-08 | 依据: spec.md + research.md

所有 DDL 写入 updatesql/sql.md(标注日期+用途),不直接执行(项目规则)。

表变更

1. pos_store(现有表,加 2 列)

列 类型 说明
self_delivery_enabled TINYINT(1) NOT NULL DEFAULT 0 自配送开关(配置主体=该门店;夜市主门店行开启=整个夜市生效)
self_delivery_mode TINYINT(1) NULL 时段模式:NULL/0=未设置,1=全天,2=自定义(按星期);仅 enabled=1 时有意义
-- 2026-09-08 029 商家自配送:门店配置
ALTER TABLE pos_store ADD COLUMN self_delivery_enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT '自配送开关(夜市主门店行开启=旗下摊位统一生效)';
ALTER TABLE pos_store ADD COLUMN self_delivery_mode TINYINT(1) DEFAULT NULL COMMENT '自配送时段模式:1=全天,2=自定义按星期';

2. pos_store_self_delivery_hours(新表,镜像 operating_hours)

列 类型 说明
id BIGINT PK AUTO_INCREMENT
md_id INT NOT NULL 配置主体门店 id(普通门店=自身;夜市=夜市主门店行 id,不是摊位 id)
day_of_week TINYINT NOT NULL ISO 星期:1=周一 … 7=周日(对齐 OperatingHours 现有取值)
start_time VARCHAR(5) NOT NULL HH:mm
end_time VARCHAR(5) NOT NULL HH:mm,必须 > start_time(同段内不允许跨天)

约束:UNIQUE (md_id, day_of_week, start_time)。某天无记录 = 该天无自配送(对齐营业时段"未配即不营业"语义)。

-- 2026-09-08 029 商家自配送:时段表
CREATE TABLE pos_store_self_delivery_hours (
  id BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键',
  md_id INT NOT NULL COMMENT '配置主体门店id(夜市场景为夜市主门店行)',
  day_of_week TINYINT NOT NULL COMMENT 'ISO星期:1=周一..7=周日',
  start_time VARCHAR(5) NOT NULL COMMENT '开始时刻 HH:mm(含)',
  end_time VARCHAR(5) NOT NULL COMMENT '结束时刻 HH:mm(不含)',
  PRIMARY KEY (id),
  UNIQUE KEY uk_sd_hours (md_id, day_of_week, start_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='门店自配送时段(按星期)';

3. pos_order(现有表,加 1 列)

列 类型 说明
self_delivery TINYINT(1) NOT NULL DEFAULT 0 下单判定快照:1=商家自配送(不进骑手池、运费归 sh_id)。终身不变,存量单默认 0
-- 2026-09-08 029 商家自配送:订单判定快照
ALTER TABLE pos_order ADD COLUMN self_delivery TINYINT(1) NOT NULL DEFAULT 0 COMMENT '1=商家自配送(下单时快照,不进骑手池,运费归sh_id)';

4. user_billing(现有表,无 DDL,启用新 type 值)

  • 现有用途:type="0" 分成(商家/骑手,dedup 键 userId+type+ddId)、type="3" 到付用户账单。
  • type="5" 固定为自配送运费入账。原商家端“金额解冻”业务已停止,页面筛选和展示均以“自配送运费”为准;不新增账单类型,避免与商品分成 type="0" 的去重键冲突。
  • 字段赋值:user_id=pos_order.sh_id(普通商家=商家、夜市摊位单=夜市主,见 research F3)、amount=freight 全额、divvy=0、divvy_rate=0、user_type="1"、md_id、dd_id、state="0"、illustrate=自配送运费(i18n)。dedup 键沿用 (userId, type, ddId)——type 不同不与商品分成冲突。
  • 到付自配送单:送达时用户账单(type="3")payment_id=sh_id(镜像骑手送达的 qsId 归因,research F13)。

实体/Mapper 变更(Java)

层 文件 变更
Entity ruoyi-system/.../domain/PosStore.java +selfDeliveryEnabled, +selfDeliveryMode
Entity ruoyi-system/.../domain/PosOrder.java +selfDelivery
Entity(新) ruoyi-system/.../domain/PosStoreSelfDeliveryHours.java 新实体(MyBatis-Plus 注解风格对齐 OperatingHours)
Mapper(新) ruoyi-system/.../mapper/PosStoreSelfDeliveryHoursMapper.java MyBatis-Plus BaseMapper,无需 XML(简单 CRUD)
Service(新) ruoyi-admin/.../order/SelfDeliveryService.java 配置解析(含摊位→夜市主门店解析)、时段判定入口、运费入账;仅依赖 system 实体+服务,符合模块边界
Util(新) ruoyi-admin/.../utils/SelfDeliveryUtil.java 纯函数:matches(hours, enabled, mode, target),[start,end) 语义,可单测

状态机(自配送外送单,type=0)

state:         0 待接单 ──商家接单──> 1 已接单 ──商家出餐──> 2 已出餐 ──确认送达──> 3 已完成
deliveryStatus: 0 ────────────────────────────────(可选:开始配送──> 2 配送中)──────> 3 已送达
  • 商家接单/出餐:requireRiderAssigned 对 self_delivery=1 放行(现状 F2 会拦)
  • "开始配送"(可选):state=2 且 deliveryStatus=0 → deliveryStatus=2;重复操作拒绝
  • "确认送达":state=2 且 deliveryStatus∈{0,2} → 原子置 deliveryStatus=3 + state=3 + sdTime=now;随后 completeSideEffects(商品分成 + 自配送运费入账 + 到付归因)
  • 满足管理端不变量(research F7):delivery=3 ⇒ state=3
  • 售后/取消:沿用现有规则,无骑手环节

校验规则(配置保存)

  1. 自定义模式必须至少一段时段(否则拒绝)
  2. 每段 end_time > start_time(字符串比较即可,HH:mm 定长)
  3. day_of_week ∈ [1,7];start/end 匹配 ^([01]\d|2[0-3]):[0-5]\d$
  4. 同一星期内时段不得重叠(相邻衔接允许:前段结束=后段开始不算重叠)
  5. 同 md_id + 星期 + start 唯一(数据库约束兜底)
  6. 保存为整体覆盖式(先删 md_id 全部再插入,与营业时段保存一致)