4. 特殊订单:赠品订单、补发订单、拆单与合单、跨境订单、企业采购订单
前面聊了那么多常规订单,今天咱们来点「不按套路出牌」的。特殊订单,说白了就是那些让系统架构师头疼、让开发同学加班的订单类型。我这些年踩过的坑,有一半都跟这些特殊场景有关。
嗯,咱们一个一个来看。
4.1 赠品订单
赠品订单,听着简单吧?不就是白送东西嘛。但实际做起来,坑多着呢。
核心问题:赠品要不要走库存?
我个人习惯是:走,必须走。不走库存的赠品,财务对账时就是一笔糊涂账。
- 买一送一:主商品正常下单,赠品以0元子订单形式关联
- 满赠活动:达到门槛后自动生成赠品订单
- 注册礼/生日礼:独立发放,不依赖主订单
我在项目中遇到过一种情况:运营搞了个「买手机送耳机」活动,结果赠品耳机没扣库存,导致超卖2000单。最后只能给用户发道歉券,亏了十几万。
赠品订单的数据结构,我建议这样设计:
// 赠品订单核心字段
{
"orderId": "G20240315001", // 赠品订单号,前缀区分
"parentOrderId": "M20240315001", // 主订单ID
"giftType": "PURCHASE_GIFT", // 赠品类型
"price": 0, // 金额为0
"inventoryDeducted": true, // 是否已扣库存
"returnPolicy": "WITH_MAIN" // 退货策略:随主单
}
4.2 补发订单
补发订单,说白了就是「上次没发对,这次补给你」。但系统层面,它可不是简单的重新发一次货。
补发的几种原因:
- 物流丢件:快递弄丢了,用户没收到
- 商品破损:收到时坏了,需要换新
- 漏发少发:仓库少装了东西
- 地址错误:用户写错地址,退回重发
你想想看,补发订单要不要重新支付?当然不要。那财务怎么记账?
我建议的做法是:补发订单作为原订单的「售后子单」,不走正向支付流程。
补发订单的状态机,比普通订单复杂得多:
// 补发订单状态流转
PENDING_APPROVE → APPROVED → WAITING_SEND → SHIPPED → RECEIVED
↓ ↓
REJECTED CANCELLED
4.3 拆单与合单
拆单和合单,是电商系统里最考验架构设计能力的环节。说白了就是:一个订单怎么拆成多个包裹发?多个订单怎么合并成一个包裹发?
拆单的场景
- 仓库拆单:商品在不同仓库,必须分开发
- 品类拆单:生鲜和日用品不能混装
- 供应商拆单:自营和第三方商品分开
- 物流拆单:大件商品走物流,小件走快递
我记得有一次做跨境项目,一个订单里有3件商品,分别在上海、广州、宁波三个保税仓。如果不拆单,系统直接报错——因为没有一个仓库能同时发这三件货。
合单的场景
- 同一用户、同一地址:30分钟内下的两个订单,合并发货
- 预售尾款+现货:付尾款时和现货合并
- 凑单满减:用户为了凑满减分开下单,系统自动合单
拆合单的核心逻辑,我画了一张图:
// 拆合单决策树(伪代码)
function decideSplitOrMerge(order) {
if (order.items 跨仓库) {
return SPLIT_BY_WAREHOUSE
}
if (order.items 跨品类且不能混装) {
return SPLIT_BY_CATEGORY
}
if (同一用户30分钟内多单且地址相同) {
return MERGE
}
return SINGLE_PACKAGE
}
4.4 跨境订单
跨境订单,是我做过最复杂的订单类型,没有之一。为什么?因为涉及的东西太多了:海关、税率、身份证信息、物流追踪、多币种...
跨境订单的核心差异:
- 实名认证:必须上传身份证正反面
- 三单对碰:订单、支付单、物流单,三单信息必须一致才能清关
- 税费计算:跨境综合税 = 关税 + 增值税 + 消费税
- 物流分段:国内段 + 国际段 + 清关
我个人习惯把跨境订单的状态机设计成两段式:
// 跨境订单状态
国内段: PENDING_PAY → PAID → WAITING_CUSTOMS → CUSTOMS_CLEARED
国际段: CUSTOMS_CLEARED → INTERNATIONAL_SHIPPING → DOMESTIC_DELIVERY → RECEIVED
跨境订单的税费计算,我建议用独立服务来做:
// 跨境税费计算
function calculateCrossBorderTax(product, user) {
const dutyRate = getDutyRate(product.category) // 关税税率
const vatRate = 0.13 // 增值税率
const consumptionRate = getConsumptionRate(product) // 消费税率
const duty = product.price * dutyRate
const vat = (product.price + duty) * vatRate
const consumption = (product.price + duty) / (1 - consumptionRate) * consumptionRate
return {
totalTax: duty + vat + consumption,
duty, vat, consumption
}
}
4.5 企业采购订单
企业采购订单,跟个人订单完全是两码事。你想想看,企业买东西要什么?发票、对公转账、审批流程、合同...
企业订单的核心特征:
- 对公支付:支持银行转账、承兑汇票
- 专票需求:必须开具增值税专用发票
- 多级审批:采购员下单 → 部门经理审批 → 财务审批
- 合同绑定:大额采购需要关联采购合同
- 账期支持:先发货后付款,30天/60天账期
我在做企业采购平台时,最头疼的是价格体系。企业用户看到的价格和个人用户不一样,而且不同企业还有不同的协议价。
企业订单的审批流程,我建议用工作流引擎来处理:
// 企业采购审批流程
ORDER_CREATED → PENDING_APPROVAL → APPROVED → WAITING_PAYMENT → PAID → SHIPPED
↓
REJECTED → ORDER_CLOSED
这里有个细节:审批中的订单,库存要不要预占? 我个人习惯是预占,但设置一个超时释放时间。比如24小时内未审批,自动释放库存。否则采购员下一堆单不审批,库存全锁死了。
知识体系总览
最后,我把这五种特殊订单的核心逻辑画了张图,方便你理解它们之间的关系:
这五种特殊订单,说白了就是常规订单的「变体」。但正是这些变体,决定了你的电商系统到底能不能扛住真实业务。我见过太多系统,常规订单跑得飞起,一到赠品、跨境就崩了。
嗯,今天就聊到这儿。这些特殊订单的处理逻辑,建议你在设计系统时提前规划好,别等到业务来了再补,那可就晚了。