Efficient Algorithms for the Joint Replenishment Problem with Minimum Order Quantities
Skill-Dynamic-Lot-Sizing-MOQ · 04-供应链
experimentforecastingpricing供应链与补货定价与利润WF-A 智能补货WF-F 动态定价
收录于大促备货决策手册
年化 ROI3×$800 - $1,200 = $1,200/批次,年节省约 $8,000
实现难度⭐⭐☆☆☆
业务视角
适用角色供应链负责人 · 采购负责人 · CEO / 运营 VP
适用平台Amazon FBA · 海外仓 · 多国仓位(美/欧/日)
什么情况下用库存周转率低,资金压在海外仓出不来;SKU 断货紧急空运,物流成本吃掉毛利;多仓库存分布不均
成功是什么样的库存周转天数从 90 天降到 60 天,断货率 <3%,海外仓综合成本降低 15-25%
业务痛点
1. 解决的问题
核心思想:供应商的 MOQ(最低起订量)和价格阶梯(all-units discount)把补货决策从"按需订货"变成了一个权衡题——少订安全但单价高,多订便宜但压库存。Q-jump (s,S) 策略给出了在随机需求+all-units折扣下的最优解:当库存触发订货点 s 时,根据「凑量判据」决定是按实际需求量订还是直接跳到折扣门槛 Q。
2. 核心算法逻辑
核心思想:供应商的 MOQ(最低起订量)和价格阶梯(allunits discount)把补货决策从"按需订货"变成了一个权衡题——少订安全但单价高,多订便宜但压库存。Qjump (s,S) 策略给出了在随机需求+allunits折扣下的最优解:当库存触发订货点 s 时,根据「凑量判据」决定是按实际需求量订还是直接跳到折扣门槛 Q。
3. 业务应用场景
场景 A:MOQ=500,1000件降12%,3月需求700件
场景 B:三个 SKU 联合订货决策(合并运费 vs 分批)
- 独立运费:每 SKU $800/次;联合运费:一票 $1,200 - 三 SKU 月需求:A=200件@$35,B=150件@$28,C=80件@$42 - 联合最优间隔 T* = 1.8 个月(每 1.8 月联合下一次单) - 节省:3×$800 - $1,200 = $1,200/批次,年节省约 $8,000
4. 输入数据要求
请查看原始代码模板获取输入规格。
5. 输出结果
请查看原始代码模板获取输出规格。
6. 业务价值 / ROI
- ROI 预估:
- 母婴场景典型案例(MOQ=500,3月需求700件):方案C vs 方案B 节省 ¥6,681 = $930/次
- 10 个 SKU × 年均 4 次采购决策 = 40 次 = 年节省约 $37,200
- 三 SKU 联合订货:年节省运费约 $8,000-$12,000
- 实施难度:⭐⭐☆☆☆(2/5)— 纯数学计算,无需机器学习
- 优先级评分:⭐⭐⭐⭐⭐(5/5)— 每次采购都需要,ROI 直接可量化
7. 代码模板
代码块数量:6 · 路径:paper2skills-code/supply_chain/dynamic_lot_sizing_moq
"""
Skill-Dynamic-Lot-Sizing-MOQ
基于 EJOR 2018 Q-jump (s,S) (All-Units Discount) +
EJOR 2022 JRP with MOQ (Chugh et al.) +
Wagner-Whitin DP (经典,1958)
母婴跨境 DTC 供应商 MOQ/价格阶梯下的动态批量决策
"""
import numpy as np
from dataclasses import dataclass
from scipy import stats
@dataclass
class LotSizingParams:
sku_id: str
demand_mean: float
demand_std: float
unit_price_normal: float
unit_price_discount: float
discount_moq: int
min_order_qty: int
holding_cost_rate: float = 0.20
fixed_order_cost: float = 800.0
stockout_cost_per_unit: float = 15.0
discount_factor_per_period: float = 0.97
@property
def holding_cost_per_unit_per_period(self):
return self.unit_price_normal * self.holding_cost_rate / 4
def should_jump_to_discount(params: LotSizingParams) -> tuple[bool, dict]:
"""
EJOR 2018 凑量判据:h + p' >= α·p → 不值得凑量
返回 (should_jump, 计算细节)
"""
h = params.holding_cost_per_unit_per_period
p_prime = params.unit_price_discount
alpha = params.discount_factor_per_period
p = params.unit_price_normal
lhs = h + p_prime
rhs = alpha * p
should_jump = lhs < rhs
return should_jump, {
"h": round(h, 4),
"p_prime": p_prime,
"alpha_times_p": round(rhs, 4),
"lhs": round(lhs, 4),
"verdict": "凑量有利 ✅" if should_jump else "不值得凑量 ❌"
}
def breakeven_demand(params: LotSizingParams) -> float:
"""
计算凑量盈亏平衡需求量:方案B(凑至折扣MOQ)vs 方案C(多次按小MOQ订)。
"""
Q = params.discount_moq
8. 论文来源
未自动抽取;请查看原始 Skill 卡片。