Date: 2026-09-08 | 遵守项目 Controller 规范(@RequestHeader token / @RequestBody DTO / @RequestParam 显式标注 / 禁 Map 入参)
/chanting/store/getMdSelfDeliveryHours| 参数 | 位置 | 类型 | 说明 |
|---|---|---|---|
| token | Header | String | 登录 token |
| mdId | Query | Integer | 配置主体门店 id(普通门店=自身;夜市=夜市主门店行) |
响应:{ enabled: boolean, mode: Integer(1=全天,2=自定义,null=未设置), hours: [{dayOfWeek, startTime, endTime}] }
(摊位主查询自己摊位 → 返回所辖夜市主门店的配置,便于前端展示"由夜市统一配送"提示;无配置返回 enabled=false 空结构)
/chanting/store/saveMdSelfDeliveryHours入参 DTO SelfDeliveryConfigInput:
| 字段 | 类型 | 校验(Service 内,MessageUtils 报错) |
|---|---|---|
| mdId | Integer | 必填;权限校验见下 |
| enabled | Boolean | 必填 |
| mode | Integer | enabled=true 时必填,∈{1,2} |
| hours | List | mode=2 时必填非空;每项 dayOfWeek∈[1,7]、startTime/endTime 匹配 HH:mm、end>start |
| 校验 | 失败响应 |
|---|---|
订单存在且 requireMerchantOrderAccess(夜市主按 shId、商家按门店权限,复用现有方法) |
merchant.order.not.found / 权限错误 |
type==0 && self_delivery==1 && qsId==null |
no.order.selfdelivery.required(非自配送单) |
state==2(已出餐)且 deliveryStatus==0 |
no.order.status.not.allow |
| afterSaleStatus==0 | no.order.aftersale.block |
效果:deliveryStatus=2;订单日志"商家已开始配送";向用户推送配送中通知(新 key no.message.push.merchant.delivery.start,文案区分商家自配送)。Redisson 锁 order:sh:selfdelivery:{id} 防并发(镜像 QsOprate 模式)。
/selfDeliveryComplete(确认送达)入参 DTO 同上(id 必填,qsImg 可选送达凭证)
校验同上,但状态要求 state==2 && deliveryStatus∈{0,2}(允许跳过开始配送);
另须 payStatus==1(在线/到付创建即付;商家POS现金/转账外送单须先确认收款——对齐骑手送达语义与管理端"完成单必已支付"不变量,错误 key no.order.selfdelivery.unpaid,2026-09-08 核验修复)。
效果(事务内):
deliveryStatus=3 + state=3 + sdTime=nowcompleteSideEffects(复用/扩展 OrderLifecycleService L491-496 的分支):商品分成 + 自配送运费入账(UserBilling type="5",user_id=sh_id,amount=freight 全额,divvy=0)UserOrderController.createOrder 与 PosOrderShOprateController.createOrder 两个入口在创建每条 PosOrder 时:
delryTime 非空 → 预约时间;否则当前时间SelfDeliveryUtil.matches(...)([start,end),ISO dayOfWeek)→ 写 self_delivery=1/0响应变化:订单对象自动携带 selfDelivery 字段(全字段序列化),客户端无需额外接口。
| 接口 | 变化 |
|---|---|
GET /system/orderQsOprate/orderList?tab=newTask |
追加过滤 self_delivery=0(NULL 视为 0,兼容存量) |
GET /system/orderQsOprate/acceptOrder |
订单 self_delivery=1 → 拒绝 no.order.selfdelivery.rider.denied(防直调,镜像 027 模式) |
POST /system/orderQsOprate/pickupOrder / deliverOrder |
同上 |
后端(messages.properties + en_US/vi/zh_CN/zh_TW 共 5 文件):
no.store.stall.selfdelivery.readonly、no.store.selfdelivery.hours.invalid、no.order.selfdelivery.required、no.order.selfdelivery.rider.denied、no.order.selfdelivery.status.invalid、no.order.selfdelivery.unpaid、no.message.push.merchant.accepted.content(自配送单商家接单推用户,核验修复)、no.message.push.merchant.delivery.start、no.billing.selfdelivery.freight(账单说明)
商家端前端(foodie-store src/lang/:zh.js/tw.js/en.js/vi.js,key 用有意义英文驼峰):
selfDelivery.*(开关/模式/星期时段编辑/保存成功)、orderList.selfDeliveryTag(订单"自配送"标识)等,四文件 key 完全一致。
| 位置 | 改动 |
|---|---|
| 门店信息页 | 自配送区块:开关 + 模式选择 + 星期×多时段编辑(复用营业时段编辑交互);摊位主隐藏该区块(读接口返回夜市配置时只读展示) |
| 订单列表/详情 | selfDelivery=1 显示"自配送"标签;自配送单不显示"等待骑手接单"类状态 |
| 配送操作按钮 | 独立任务(依赖 clarify Q2 暂缓决策):开始配送/确认送达按钮调用 §2 接口;接口先行交付 |
注意:foodie-store 文件为 CRLF,编辑用 Python 脚本替换(项目规则)。