外卖多商户系统二次开发指南:自定义配送规则模块改造方案
一、改造背景与原有系统痛点
很多开源多商户外卖系统原生配送逻辑比较简单,一般是全局统一配送半径、固定配送费,所有商家共用一套规则,无法满足差异化经营需求。在县域、本地商圈场景下,不同商家营业时间、配送范围、阶梯配送费、高峰加价策略不一样,原生硬编码的配送逻辑扩展性很差。
本次二次开发目标是抽离独立的配送规则模块,支持商户自主配置多边形围栏、时段规则、阶梯计费、免配送费门槛,下单时动态匹配规则,同时保留平台统一管控能力,不改动原有订单、支付、调度主流程,降低改造风险。
二、模块改造整体思路
采用规则配置+运行时匹配的方案,新增独立配送规则表,和商户一对一或一对多绑定,原有下单链路增加配送规则校验切面。
数据存储:MySQL存储配送区域、时段、计费参数;Redis缓存商户生效配送规则,减少下单时重复查询;地图围栏坐标序列持久化存储,下单时做坐标点在多边形内判断。
执行顺序:用户提交收货地址→匹配商户生效配送规则→校验地址是否在配送区域→计算起送价、配送费、附加费→返回结果给前端,不满足条件直接拦截下单。
权限隔离:商家只能维护自己门店的配送规则,平台后台拥有查看、禁用、覆盖商户规则的权限。
三、数据表新增设计
新增核心表:商户配送规则主表、配送区域子表、时段附加规则表。
一条商户配送规则可以包含多个配送区域,每个区域独立配置起送价、配送费、免配送门槛;时段附加规则叠加在区域规则之上,午高峰、夜间、雨雪天气可以叠加附加配送费或者缩小配送范围。
规则生效优先级:商户自定义时段规则 > 商户常规区域规则 > 平台兜底默认规则。
四、核心规则匹配与计费Java代码实现
@Service
public class DeliveryRuleService {
@Resource
private ShopDeliveryRuleMapper ruleMapper;
@Resource
private RedisTemplate<String,Object> redisTemplate;
// 匹配门店当前生效配送规则,计算配送费用
public DeliveryResult calcDeliveryFee(Long shopId, double userLon, double userLat, BigDecimal orderAmount) {
String cacheKey = "delivery:rule:" + shopId;
ShopDeliveryRule rule = (ShopDeliveryRule) redisTemplate.opsForValue().get(cacheKey);
if(rule == null){
rule = ruleMapper.selectEffectiveRuleByShopId(shopId);
if(rule != null){
redisTemplate.opsForValue().set(cacheKey, rule, 30, TimeUnit.MINUTES);
}
}
if(rule == null){
return DeliveryResult.fail("该门店暂未配置配送规则");
}
// 判断坐标是否落在任一配送区域
DeliveryArea matchedArea = matchArea(rule.getAreaList(), userLon, userLat);
if(matchedArea == null){
return DeliveryResult.fail("收货地址超出门店配送范围");
}
// 校验起送价
if(orderAmount.compareTo(matchedArea.getMinSendAmount()) < 0){
return DeliveryResult.fail("未达到该区域起送金额");
}
// 满足免配送门槛则配送费为0
BigDecimal deliveryFee;
if(orderAmount.compareTo(matchedArea.getFreeDeliveryAmount()) >= 0){
deliveryFee = BigDecimal.ZERO;
}else{
deliveryFee = matchedArea.getBaseDeliveryFee();
}
// 叠加时段附加费
BigDecimal extraFee = getTimeExtraFee(rule.getTimeRuleList());
deliveryFee = deliveryFee.add(extraFee);
DeliveryResult result = new DeliveryResult();
result.setSuccess(true);
result.setDeliveryFee(deliveryFee);
result.setAreaName(matchedArea.getAreaName());
return result;
}
}
坐标判断工具类依赖多边形点包含算法,后台配置页面支持地图可视化绘制围栏,前端回传坐标数组存入数据库。
五、后台配置页面能力改造
商家后台新增配送规则配置页,支持:
- 地图绘制圆形/多边形配送区域,多区域分开设置参数;
- 新增多条时段策略,选择生效时间段,配置附加费、临时缩小配送范围开关;
- 设置免配送费门槛、区域起送价;
- 规则启用、禁用、版本保存,修改后自动清理Redis缓存,保证即时生效。
平台后台可以查看所有商户配送规则,支持给商户设置强制兜底规则,防止商家配置不合理导致履约亏损。
六、下单链路接入与兼容性处理
改造时采用切面模式接入,不修改原有OrderService核心代码。在订单参数校验阶段调用配送规则服务:
- 校验不通过:返回提示,终止下单流程;
- 校验通过:将本次命中的配送规则ID、区域信息存入订单快照,用于后续对账和售后溯源。
兼容逻辑:没有配置自定义规则的商户,自动回退到平台原有全局配送规则,保证老商户业务不受升级影响,实现灰度上线。
七、缓存失效、并发与兜底策略
商户修改配送规则后,主动删除对应商户的Redis缓存,保证新规则即时生效;缓存击穿场景,加简单互斥锁防止大量请求穿透数据库。
增加定时任务,每日凌晨校验所有配送规则的围栏数据,清理异常坐标;同时增加日志记录,每一笔订单命中哪一条配送规则都写入订单日志,方便排查配送费计算纠纷。
异常兜底:地图坐标解析失败、围栏数据异常时,自动降级使用平台默认半径规则,避免直接阻断用户下单。
八、和调度派单模块联动
配送规则只负责下单阶段的范围拦截和费用计算,不侵入骑手调度逻辑。调度模块可以读取订单快照里的配送区域信息,优先给对应区域的骑手派单;如果商户在高峰时段缩小配送范围,超出范围的订单从源头拦截,减少无效派单和骑手投诉。
九、总结
多商户外卖系统自定义配送规则模块二次开发,核心思路是将配送计费、范围判断逻辑从原有业务代码中抽离为独立可配置模块,通过商户维度的区域围栏、时段附加规则实现差异化配送策略,采用缓存加速下单校验,同时保留旧规则兜底保证平滑升级。这套改造方案侵入性低,不需要大规模重构原有订单、支付、调度代码,适合中小同城外卖平台迭代。后续业务发展后,可以继续扩展天气加价、距离阶梯计费、自提点独立规则等能力,持续适配本地多样化的配送履约场景。