简介
本设计文档聚焦 DouPHP 电商系统的“订单物流”能力,围绕订单发货、物流公司选择、运单号管理、收货地址快照、退货寄回物流等核心场景,梳理并说明相关数据库表结构、业务处理流程、异常处理与扩展点。面向电商平台开发者提供可落地的集成参考实现,帮助快速完成多家物流公司的接入、轨迹追踪、配送范围限制、运费计算、签收确认与统计分析等复杂场景的数据建模与流程编排。
项目结构与范围
- 订单主表与物流字段:订单主表包含物流公司标识、运单号、发货时间等关键字段,用于承载正向发货的物流信息。
- 收货地址快照:订单下单时冻结收货地址,避免后续地址变更影响历史订单。
- 退货物流:售后退货场景下,记录买家寄回物流的公司与运单号、寄出时间。
- 物流公司来源:物流公司来自已启用的配送插件列表,支持多物流公司集成。
- 发货流程:后台录入物流公司与运单号,首次填写时推进订单状态并解锁库存;后续更新仅刷新物流信息。
graph TB
A["订单主表<br/>dou_order"] --> B["物流公司/配送方式<br/>plugin 表 slug"]
A --> C["收货地址快照<br/>dou_order_address"]
D["售后退货表<br/>dou_aftersale_return"] --> E["售后状态机<br/>返回已发货"]
F["后台订单服务<br/>OrderService::tracking"] --> A
F --> G["核心订单服务<br/>changeStatus / getShippingList"]
核心数据模型与表设计
- 订单主表(dou_order)
- 关键字段:shipping_id(物流公司/配送方式 slug)、tracking_no(运单号)、shipped_at(发货时间)、status(订单状态)、allow_aftersale(是否允许售后)、item_amount/shipping_fee/order_amount(金额)。
- 作用:承载正向发货的物流信息与订单生命周期状态。
- 收货地址快照(dou_order_address)
- 关键字段:order_id、contact_name、phone、country、province、address、postcode。
- 作用:下单瞬间冻结收货信息,与会员地址本解耦,确保历史订单地址一致性。
- 售后退货表(dou_aftersale_return)
- 关键字段:aftersale_id、shipping_company、tracking_no、shipped_at(DATETIME)。
- 作用:记录买家退货寄出的物流公司、运单号与寄出时间,并与售后状态机联动。
- 物流公司来源(plugin 表)
- 通过 plugin.slug 表示启用的配送方式,后台下拉列表由核心订单服务获取。
erDiagram
DOU_ORDER {
int id PK
string order_sn UK
int user_id
string shipping_id
string tracking_no
datetime shipped_at
decimal item_amount
decimal shipping_fee
decimal order_amount
string status
string allow_aftersale
datetime created_at
}
DOU_ORDER_ADDRESS {
int id PK
int order_id FK
string contact_name
string phone
string country
string province
string address
string postcode
datetime created_at
}
DOU_AFTERSALE_RETURN {
int aftersale_id PK
string shipping_company
string tracking_no
datetime shipped_at
}
DOU_ORDER ||--o{ DOU_ORDER_ADDRESS : "一对一快照"
DOU_ORDER ||--|| DOU_AFTERSALE_RETURN : "售后退货关联"
架构总览
- 入口层:后台订单控制器接收物流提交请求,调用表单校验与服务层。
- 服务层:
- 后台订单服务负责物流保存、首次发货状态推进、库存解锁。
- 核心订单服务提供状态机、物流公司列表、支付/配送选项等能力。
- 数据层:订单主表、收货地址快照、售后退货表与插件表协作。
- 售后链路:用户提交退货物流后写入退货表并推进售后状态。
sequenceDiagram
participant Admin as "后台管理员"
participant Ctrl as "订单控制器"
participant Req as "表单校验"
participant Svc as "后台订单服务"
participant Core as "核心订单服务"
participant DB as "数据库"
Admin->>Ctrl : 提交物流order_id, shipping_id, tracking_no
Ctrl->>Req : 参数校验
Req-->>Ctrl : 校验通过
Ctrl->>Svc : tracking(data)
alt 首次填写运单号
Svc->>Core : changeStatus(COMPLETED)
Core-->>Svc : 成功
Svc->>DB : 更新 order(shipping_id, tracking_no, shipped_at, allow_aftersale)
Svc->>DB : 更新 order_item(stock_lock=0)
else 非首次更新
Svc->>DB : 更新 order(shipping_id, tracking_no, shipped_at)
end
Ctrl-->>Admin : 跳转订单详情
关键业务流程详解
物流配送流程管理(发货)
- 触发点:后台订单详情页“保存物流”。
- 规则:
- 首次填写运单号:将订单状态推进为已完成,设置 allow_aftersale=1,并解锁库存。
- 非首次更新:仅刷新物流公司、运单号与发货时间。
- 结果:订单主表 shipping_id/tracking_no/shipped_at 更新;order_item.stock_lock 在首次发货时清零。
flowchart TD
Start(["开始"]) --> Check{"是否已有运单号?"}
Check -- 否 --> FirstShip["推进订单状态为已完成<br/>设置 allow_aftersale=1<br/>解锁库存"]
FirstShip --> UpdateOrder["更新 order.shipping_id/tracking_no/shipped_at"]
Check -- 是 --> UpdateOnly["仅更新 order.shipping_id/tracking_no/shipped_at"]
UpdateOrder --> End(["结束"])
UpdateOnly --> End
物流信息查询
- 物流公司下拉:由核心订单服务获取启用配送插件列表,后台详情页渲染。
- 订单详情展示:从订单主表读取 shipping_id/tracking_no/shipped_at,并从插件表解析物流公司名称。
- 收货地址:统一从收货地址快照表读取联系人、电话、省市区、详细地址、邮编。
graph LR
UI["后台订单详情页"] --> List["getShippingList()"]
UI --> ReadOrder["读取 order.shipping_id/tracking_no/shipped_at"]
UI --> ReadAddr["读取 order_address 快照"]
List --> Plugin["plugin 表 slug→name"]
签收确认
- 当前实现以“首次填写运单号即视为发货完成”,订单状态推进为已完成,并开启售后窗口。
- 若需引入第三方物流轨迹回调或签收事件,可在现有 order.tracking_no 基础上扩展:
- 新增轨迹表记录节点时间与状态;
- 通过外部回调更新轨迹与订单签收状态;
- 结合售后状态机进行签收后的业务联动(如自动评价、结算分佣等)。
退货物流
- 用户提交退货物流:写入 dou_aftersale_return(shipping_company、tracking_no、shipped_at),并推进售后状态至“返回已发货”。
- 后台展示:售后详情页显示退货公司、运单号与寄出时间。
sequenceDiagram
participant User as "用户"
participant ASvc as "售后服务中心"
participant DB as "数据库"
participant Status as "售后状态机"
User->>ASvc : 提交退货物流公司、运单号
ASvc->>DB : 写入/更新 aftersale_return
ASvc->>Status : changeStatus(RETURN_SHIPPED)
Status-->>ASvc : 成功
ASvc-->>User : 提示成功
多家物流公司集成支持
- 物流公司来源:通过核心订单服务的 getShippingList 获取已启用配送插件列表,后台详情页下拉框渲染。
- 扩展方式:新增配送插件并在系统中启用,即可出现在物流公司选择中;订单主表使用 slug 标识物流公司。
物流轨迹追踪
- 当前实现:订单主表仅记录运单号;未内置轨迹拉取与存储逻辑。
- 建议方案:
- 新增轨迹表(order_id、company_slug、tracking_no、event_time、event_desc、source 等);
- 定时任务或回调接口拉取轨迹并去重入库;
- 前端按时间轴展示轨迹节点。
配送范围限制与运费计算
- 范围限制:建议在配送插件内实现(基于地区、重量、体积等规则),订单主表仅记录最终选择的 shipping_id。
- 运费计算:订单主表记录 shipping_fee,可由结算流程根据插件策略计算并持久化。
依赖关系分析
- 控制器依赖表单校验与服务层:
- 控制器接收物流提交,委托 OrderTrackingFormRequest 校验,再调用 OrderService::tracking。
- 服务层依赖核心订单服务:
- 首次发货调用 changeStatus 推进状态;
- 物流公司列表通过 getShippingList 获取。
- 数据层依赖订单主表、收货地址快照、售后退货表与插件表。
graph TB
Ctrl["订单控制器"] --> Req["表单校验"]
Ctrl --> Svc["后台订单服务"]
Svc --> Core["核心订单服务"]
Svc --> DB["订单/地址/退货/插件表"]
性能与扩展性建议
- 索引优化:
- 对 order.order_sn、order.status、order.shipping_id、order.tracking_no 建立合适索引以提升查询效率。
- 对 order_address.order_id 建立索引以加速地址快照查询。
- 对 aftersale_return.aftersale_id 建立唯一索引以避免重复写入。
- 批量操作:
- 批量取消订单时使用事务保证一致性,减少锁竞争。
- 扩展点:
- 在配送插件中实现范围限制与运费计算,保持订单主表简洁。
- 新增轨迹表与回调接口,解耦第三方物流 API 调用。
故障排查指南
- 物流提交失败:
- 检查表单校验是否通过(order_id、shipping_id、tracking_no)。
- 检查订单是否存在且状态允许更新。
- 状态推进异常:
- 首次发货会推进到已完成并解锁库存,若失败请查看日志与事务回滚情况。
- 退货物流写入异常:
- 检查 aftersale_return 表结构与 shipped_at 字段类型(DATETIME)。
- 确认售后状态机是否允许 RETURN_SHIPPED 转换。
结论
DouPHP 的订单物流体系以订单主表为核心,结合收货地址快照与售后退货表,形成了完整的正向发货与退货物流闭环。通过核心订单服务提供的状态机与配送插件列表,系统具备良好的扩展性,便于接入多家物流公司、实现轨迹追踪、范围限制与运费计算等复杂场景。建议在现有基础上补充轨迹表与回调机制,进一步提升物流可视性与自动化水平。
附录:字段与状态参考
- 订单主表关键字段
- shipping_id:物流公司/配送方式 slug
- tracking_no:运单号
- shipped_at:发货时间
- status:订单状态
- allow_aftersale:是否允许售后
- 收货地址快照关键字段
- contact_name、phone、country、province、address、postcode
- 售后退货表关键字段
- shipping_company、tracking_no、shipped_at(DATETIME)
- 物流公司来源
- 通过核心订单服务的 getShippingList 获取启用插件列表