mcpField
O
order-fulfillment

order-fulfillment

github.com/kishorkukreja其他8448 次安装3 周前更新
代码仓库

关于 order-fulfillment

order-fulfillment 是面向仓储履约运营与优化的技能,帮助规划高效、准确且控制成本的订单处理流程。内容涵盖拣选策略、路径、包装、运输和绩效指标。

主要功能

  1. 01梳理订单与服务要求
  2. 02比较多种拣选策略
  3. 03介绍拣选路径优化
  4. 04规划包装与箱型选择
  5. 05评估运输与履约指标

适用场景

  1. 01为仓库选择拣选作业方式
  2. 02规划订单波次与拣选路线
  3. 03估算包装人力与箱型
  4. 04分析履约准确率和准时率

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kishorkukreja/awesome-supply-chain --skill order-fulfillment

安装后在 Claude Code 中输入/order-fulfillment确认已加载。

详细介绍

订单履行

你是订单履行运营与优化方面的专家。你的目标是帮助设计高效、准确且经济的履行流程,在满足客户服务预期的同时,尽量降低人工和运营成本。

初步评估

在优化履行流程之前,先了解以下内容:

  1. 订单概况

    • 订单量是多少?(每日订单数、峰值与平均值)
    • 订单特征如何?(每单行数、每单件数)
    • 订单类型有哪些?(B2B 托盘、B2C 单件、混合)
    • SKU 数量和周转速度分布如何?
  2. 服务要求

    • 配送速度要求是什么?(当日达、次日达、2 日达、标准配送)
    • 发货截单时间是什么?
    • 订单准确率目标是多少?(99.5% 以上)
    • 是否需要特殊服务?(礼品包装、套件组装、定制)
  3. 当前运营情况

    • 当前的履行流程和流转方式是什么?
    • 拣货准确率和生产率如何?
    • 正在使用哪些技术?(WMS、自动化、RF 扫描器)
    • 有哪些痛点和瓶颈?
  4. 约束条件

    • 人力是否充足,成本如何?
    • 设施布局和空间如何?
    • 改进的资本预算是多少?
    • IT 系统和集成能力如何?

订单履行框架

核心履行流程

1. 接收与验证订单

  • 从各个渠道接收订单(网站、EDI、电话)
  • 检查库存可用量(ATP)
  • 验证信用额度和付款
  • 确定订单优先级并进行批次处理

2. 拣货

  • 从存储位置取出商品
  • 核对 SKU 和数量是否准确
  • 采用多种策略(单单拣货、批量拣货、分区拣货、波次拣货)

3. 包装

  • 选择合适的包装材料
  • 妥善包装商品
  • 放入文件(装箱单、退货资料)
  • 生成运输标签

4. 发货

  • 选择承运商并制作货运清单
  • 装载拖车并发车
  • 更新跟踪信息

5. 退货处理

  • 接收并检查退货
  • 确定处理方式(重新入库、清算、销毁)
  • 处理客户退款或换货

拣货策略

策略比较
策略每小时订单数人力效率准确率复杂度适用场景
单单拣货(单个订单)20-40低高低低订单量、高价值
批量拣货60-100中中中中等订单量
分区拣货80-150高中高SKU 数量多
波次拣货100-200+很高中很高订单量大
集群拣货100-150高高中多订单拣货
单单拣货

说明:

  • 一次拣选一个订单
  • 完成一个订单后再开始下一个
  • 简单、准确,但效率低

适用场景:

  • 订单量较低(每日少于 500 单)
  • 需要确保准确性的高价值订单
  • 需要定制化处理的复杂订单
import numpy as np
import pandas as pd

def discrete_picking_capacity(orders_per_day, lines_per_order,
                              pick_rate_per_hour=100,
                              working_hours=8):
    """
    Calculate labor requirements for discrete picking

    Parameters:
    - orders_per_day: Daily order volume
    - lines_per_order: Average lines per order
    - pick_rate_per_hour: Picks per person per hour (includes travel)
    - working_hours: Working hours per shift
    """

    picks_per_day = orders_per_day * lines_per_order

    # Labor hours needed
    labor_hours_needed = picks_per_day / pick_rate_per_hour

    # Pickers needed
    pickers_needed = labor_hours_needed / working_hours

    # Orders per picker per day
    orders_per_picker = orders_per_day / pickers_needed

    return {
        'picks_per_day': picks_per_day,
        'labor_hours_needed': round(labor_hours_needed, 1),
        'pickers_needed': round(pickers_needed, 1),
        'orders_per_picker_per_day': round(orders_per_picker, 0),
        'picks_per_picker_per_hour': pick_rate_per_hour
    }

# Example
discrete = discrete_picking_capacity(
    orders_per_day=500,
    lines_per_order=5,
    pick_rate_per_hour=100,
    working_hours=8
)

print(f"Pickers needed: {discrete['pickers_needed']}")
print(f"Orders per picker: {discrete['orders_per_picker_per_day']}")
批量拣货

说明:

  • 同时拣选多个订单
  • 每批次中每个 SKU 只需拣选一次,供所有订单使用
  • 拣货后将商品分配到各个订单

优势:

  • 减少行走时间(每个库位只需经过一次)
  • 与单单拣货相比,生产率提高 40-60%

实施方式:

def batch_picking_optimization(orders_df, batch_size=10, sort_time_per_unit=3):
    """
    Optimize batch picking

    Parameters:
    - orders_df: DataFrame with columns ['order_id', 'sku', 'quantity', 'location']
    - batch_size: Orders per batch
    - sort_time_per_unit: Seconds to sort each unit to order

    Returns:
    - Batch assignments and performance metrics
    """

    # Create batches
    orders_df = orders_df.copy()
    orders_df['batch'] = (orders_df.index // batch_size) + 1

    # Calculate picks per batch
    batch_summary = orders_df.groupby('batch').agg({
        'order_id': 'nunique',
        'sku': 'count',
        'quantity': 'sum',
        'location': 'nunique'
    }).rename(columns={
        'order_id': 'orders',
        'sku': 'pick_lines',
        'location': 'unique_locations'
    })

    # Estimate time savings
    # Discrete: visit each location for each order
    # Batch: visit each location once per batch

    discrete_picks = len(orders_df)
    batch_picks = batch_summary['unique_locations'].sum()

    pick_reduction_pct = (discrete_picks - batch_picks) / discrete_picks

    # Sort time required
    total_units = batch_summary['quantity'].sum()
    sort_time_hours = (total_units * sort_time_per_unit) / 3600

    return {
        'total_batches': len(batch_summary),
        'avg_orders_per_batch': batch_summary['orders'].mean(),
        'discrete_picks': discrete_picks,
        'batch_picks': batch_picks,
        'pick_reduction_%': round(pick_reduction_pct * 100, 1),
        'sort_time_hours': round(sort_time_hours, 2),
        'batch_summary': batch_summary
    }

# Example
orders_df = pd.DataFrame({
    'order_id': [f'ORD_{i}' for i in range(1, 101)],
    'sku': np.random.choice(['SKU_A', 'SKU_B', 'SKU_C', 'SKU_D'], 100),
    'quantity': np.random.randint(1, 5, 100),
    'location': np.random.choice(['A1', 'A2', 'B1', 'B2', 'C1'], 100)
})

batch_result = batch_picking_optimization(orders_df, batch_size=10)
print(f"Pick reduction: {batch_result['pick_reduction_%']}%")
print(f"Sort time required: {batch_result['sort_time_hours']} hours")
分区拣货

说明:

  • 将仓库划分为多个区域
  • 每位拣货员负责一个区域
  • 订单依次经过各个区域,或在末端集中处理

类型:

  • 顺序分区拣货:订单依次经过各个区域
  • 批量分区拣货:先将商品拣入料箱,之后再集中处理

优势:

  • 拣货员可熟练掌握其负责的区域
  • 并行处理(可同时拣选多个订单)
  • 减少拥堵
def zone_picking_design(warehouse_sq_ft, num_pickers, orders_per_day,
                       lines_per_order, sku_distribution):
    """
    Design zone picking system

    Parameters:
    - warehouse_sq_ft: Total picking area
    - num_pickers: Available pickers
    - orders_per_day: Daily order volume
    - lines_per_order: Average lines per order
    - sku_distribution: Dict with zone: % of picks
    """

    picks_per_day = orders_per_day * lines_per_order

    # Allocate zones based on pick volume
    zone_allocation = {}

    for zone, pct in sku_distribution.items():
        picks_in_zone = picks_per_day * pct
        pickers_needed = picks_in_zone / (100 * 8)  # 100 picks/hr, 8 hrs

        zone_allocation[zone] = {
            'pick_volume': round(picks_in_zone, 0),
            'pickers_needed': round(pickers_needed, 1),
            'sq_ft': round(warehouse_sq_ft * pct, 0)
        }

    return zone_allocation

# Example
sku_dist = {
    'Zone_A_Fast': 0.40,  # 40% of picks
    'Zone_B_Medium': 0.35,
    'Zone_C_Slow': 0.25
}

zones = zone_picking_design(
    warehouse_sq_ft=50000,
    num_pickers=20,
    orders_per_day=2000,
    lines_per_order=5,
    sku_distribution=sku_dist
)

print("Zone Allocation:")
for zone, data in zones.items():
    print(f"\n  {zone}:")
    print(f"    Pick volume: {data['pick_volume']}")
    print(f"    Pickers needed: {data['pickers_needed']}")
    print(f"    Square footage: {data['sq_ft']}")
波次拣货

说明:

  • 将一组订单作为一个“波次”同时放行
  • 优化波次组成以提高效率
  • 协调拣货、包装和发货

波次设计因素:

  • 承运商时间表(UPS 于下午 5 点揽件)
  • 订单优先级(SLA 要求)
  • 资源可用情况(拣货员、包装员)
  • 仓库容量(暂存空间)
def wave_planning(orders_df, waves_per_day=4, target_wave_size=500):
    """
    Plan picking waves

    Parameters:
    - orders_df: DataFrame with ['order_id', 'priority', 'lines', 'carrier', 'cutoff_time']
    - waves_per_day: Number of waves per day
    - target_wave_size: Target orders per wave

    Returns:
    - Wave assignments
    """

    orders_df = orders_df.copy()

    # Sort by priority and cutoff time
    orders_df = orders_df.sort_values(['priority', 'cutoff_time'], ascending=[False, True])

    # Assign to waves
    orders_df['wave'] = (orders_df.index // target_wave_size) % waves_per_day + 1

    # Wave summary
    wave_summary = orders_df.groupby('wave').agg({
        'order_id': 'count',
        'lines': 'sum',
        'cutoff_time': 'max'
    }).rename(columns={
        'order_id': 'orders',
        'lines': 'total_picks'
    })

    # Estimate time required per wave
    wave_summary['pick_hours'] = wave_summary['total_picks'] / 100  # 100 picks/hr
    wave_summary['pickers_needed'] = np.ceil(wave_summary['pick_hours'] / 2)  # 2 hr wave

    return orders_df[['order_id', 'wave', 'priority']], wave_summary

# Example
orders_data = pd.DataFrame({
    'order_id': [f'ORD_{i}' for i in range(1, 2001)],
    'priority': np.random.choice([1, 2, 3], 2000, p=[0.1, 0.3, 0.6]),
    'lines': np.random.poisson(5, 2000),
    'carrier': np.random.choice(['UPS', 'FedEx', 'USPS'], 2000),
    'cutoff_time': np.random.choice(['12:00', '15:00', '17:00'], 2000)
})

wave_assignments, wave_summary = wave_planning(orders_data, waves_per_day=4)
print("Wave Summary:")
print(wave_summary)
集群拣选

描述:

  • 将多个订单拣选到多格料车中
  • 每个格位对应一个订单
  • 同时拣选所有订单

优势:

  • 生产率高(兼具批量拣选和离散拣选的优势)
  • 保持订单完整性
  • 非常适合电商(订单小、SKU 多)

设备:

  • 配备 4-12 个周转箱/格位的拣选料车
  • 语音或 RF 引导拣选

拣选路径优化

路线策略

1. S 形路线

  • 进入有拣选任务的巷道,跳过空巷道
  • 最常见,易于实施

2. 折返路线

  • 从巷道同一端进入和离开
  • 适用于拣选任务较少的选择性巷道

3. 中点路线

  • 从巷道最近的一端进入
  • 对随机分布的拣选位置而言效率最高

4. 最大间隔法

  • 跳过巷道内拣选点之间最大的间隔
  • 在大多数情况下效果最佳
def calculate_pick_path_distance(pick_locations, aisle_length_ft=100,
                                aisle_width_ft=10, routing='s-shape'):
    """
    Calculate travel distance for pick path

    Parameters:
    - pick_locations: List of tuples [(aisle, position_pct), ...]
    - aisle_length_ft: Length of aisle
    - aisle_width_ft: Width between aisles
    - routing: 's-shape', 'return', 'largest-gap'

    Returns:
    - Total travel distance
    """

    # Group picks by aisle
    aisles_with_picks = {}
    for aisle, position in pick_locations:
        if aisle not in aisles_with_picks:
            aisles_with_picks[aisle] = []
        aisles_with_picks[aisle].append(position)

    total_distance = 0

    if routing == 's-shape':
        # Traverse aisles with picks, skip empty
        for aisle, positions in sorted(aisles_with_picks.items()):
            # Full aisle length + cross-aisle
            total_distance += aisle_length_ft + aisle_width_ft

    elif routing == 'return':
        # Enter and exit same end
        for aisle, positions in aisles_with_picks.items():
            max_position = max(positions)
            # Go to furthest pick and return
            total_distance += (max_position * aisle_length_ft * 2) + aisle_width_ft

    elif routing == 'largest-gap':
        # Optimal routing (simplified)
        for aisle, positions in aisles_with_picks.items():
            positions_sorted = sorted(positions)

            # Find largest gap
            gaps = [positions_sorted[i+1] - positions_sorted[i]
                   for i in range(len(positions_sorted)-1)]

            if gaps:
                largest_gap = max(gaps)
                # Distance = full aisle - largest gap
                distance_in_aisle = aisle_length_ft * (1 - largest_gap)
            else:
                distance_in_aisle = positions_sorted[0] * aisle_length_ft

            total_distance += distance_in_aisle + aisle_width_ft

    return round(total_distance, 1)

# Example pick path
picks = [
    (1, 0.2),   # Aisle 1, 20% down
    (1, 0.8),   # Aisle 1, 80% down
    (3, 0.5),   # Aisle 3, 50% down
    (5, 0.3),   # Aisle 5, 30% down
]

for routing in ['s-shape', 'return', 'largest-gap']:
    distance = calculate_pick_path_distance(picks, routing=routing)
    print(f"{routing}: {distance} ft")

包装作业

包装策略

1. 单次包装

  • 直接将商品拣选到运输箱中
  • 速度最快,但需要预先知道箱子尺寸
  • 适用于单件商品订单

2. 包装工作站(传统方式)

  • 集中式包装区域
  • 拣选员将商品送到包装员处
  • 箱子选择更灵活

3. 线内包装

  • 拣选时同步包装
  • 需要采用拣选到输送带或料车系统

4. 自动化包装

  • 自动选择箱子并封箱
  • 吞吐量高(每小时 500+ 箱)
  • 资本投入大($500K+)
箱子选择优化
def optimize_box_selection(order_items, box_inventory):
    """
    Select optimal box size for order

    Parameters:
    - order_items: List of dicts [{'sku': 'A', 'qty': 2, 'dims': (10,8,4)}, ...]
    - box_inventory: List of available boxes [{'box_id': 'Small', 'dims': (12,10,8), 'cost': 0.50}, ...]

    Returns:
    - Optimal box selection
    """

    # Calculate total volume needed
    total_volume = sum(
        item['qty'] * item['dims'][0] * item['dims'][1] * item['dims'][2]
        for item in order_items
    )

    # Find boxes that fit (with utilization target)
    target_utilization = 0.80  # 80% full
    required_volume = total_volume / target_utilization

    suitable_boxes = [
        box for box in box_inventory
        if box['dims'][0] * box['dims'][1] * box['dims'][2] >= required_volume
    ]

    if not suitable_boxes:
        return None

    # Select smallest suitable box (minimize cost)
    optimal_box = min(suitable_boxes,
                     key=lambda b: b['dims'][0] * b['dims'][1] * b['dims'][2])

    actual_volume = optimal_box['dims'][0] * optimal_box['dims'][1] * optimal_box['dims'][2]
    utilization = total_volume / actual_volume

    return {
        'box_id': optimal_box['box_id'],
        'box_dims': optimal_box['dims'],
        'box_cost': optimal_box['cost'],
        'utilization_%': round(utilization * 100, 1)
    }

# Example
order = [
    {'sku': 'A', 'qty': 1, 'dims': (10, 8, 4)},
    {'sku': 'B', 'qty': 2, 'dims': (6, 6, 3)}
]

boxes = [
    {'box_id': 'Small', 'dims': (12, 10, 8), 'cost': 0.50},
    {'box_id': 'Medium', 'dims': (18, 14, 12), 'cost': 0.75},
    {'box_id': 'Large', 'dims': (24, 18, 16), 'cost': 1.00}
]

result = optimize_box_selection(order, boxes)
if result:
    print(f"Optimal box: {result['box_id']}")
    print(f"Utilization: {result['utilization_%']}%")
    print(f"Cost: ${result['box_cost']}")
包装人力需求
def packing_labor_requirements(orders_per_day, packing_rate_per_hour=40,
                               working_hours=8, multi_item_pct=0.60):
    """
    Calculate packing labor needs

    Parameters:
    - orders_per_day: Daily order volume
    - packing_rate_per_hour: Orders packed per person per hour
    - working_hours: Working hours per shift
    - multi_item_pct: % of orders with multiple items (slower to pack)

    Returns:
    - Packing labor requirements
    """

    # Adjust rate for multi-item orders
    multi_item_orders = orders_per_day * multi_item_pct
    single_item_orders = orders_per_day * (1 - multi_item_pct)

    # Multi-item takes ~1.5x longer
    equivalent_orders = single_item_orders + (multi_item_orders * 1.5)

    # Labor hours needed
    labor_hours = equivalent_orders / packing_rate_per_hour

    # Packers needed
    packers_needed = labor_hours / working_hours

    # Packing stations needed (assume 80% utilization)
    stations_needed = packers_needed / 0.80

    return {
        'orders_per_day': orders_per_day,
        'equivalent_orders': round(equivalent_orders, 0),
        'labor_hours_needed': round(labor_hours, 1),
        'packers_needed': round(packers_needed, 1),
        'packing_stations_needed': int(np.ceil(stations_needed))
    }

# Example
packing = packing_labor_requirements(
    orders_per_day=2000,
    packing_rate_per_hour=40,
    working_hours=8,
    multi_item_pct=0.60
)

print(f"Packers needed: {packing['packers_needed']}")
print(f"Packing stations: {packing['packing_stations_needed']}")

发运作业

承运商选择与费率比价
def carrier_rate_shopping(order_weight_lbs, order_dims, destination_zip,
                         origin_zip, delivery_speed='ground'):
    """
    Compare carrier rates (simplified example)

    In practice, integrate with carrier APIs:
    - UPS API
    - FedEx API
    - USPS API
    """

    # Simplified rate tables (actual rates vary by contract, zone, etc.)
    rates = {
        'UPS': {
            'ground': 8.50 + (order_weight_lbs * 0.50),
            '2day': 15.00 + (order_weight_lbs * 0.75),
            'overnight': 35.00 + (order_weight_lbs * 1.50)
        },
        'FedEx': {
            'ground': 8.75 + (order_weight_lbs * 0.48),
            '2day': 14.50 + (order_weight_lbs * 0.70),
            'overnight': 32.00 + (order_weight_lbs * 1.40)
        },
        'USPS': {
            'ground': 7.50 + (order_weight_lbs * 0.45),
            '2day': 13.00 + (order_weight_lbs * 0.65),
            'overnight': 30.00 + (order_weight_lbs * 1.30)
        }
    }

    # Calculate dimensional weight
    dim_weight = (order_dims[0] * order_dims[1] * order_dims[2]) / 139
    billable_weight = max(order_weight_lbs, dim_weight)

    carrier_quotes = {}
    for carrier, speeds in rates.items():
        if delivery_speed in speeds:
            cost = speeds[delivery_speed]
            # Adjust for dimensional weight
            if billable_weight > order_weight_lbs:
                cost += (billable_weight - order_weight_lbs) * 0.50

            carrier_quotes[carrier] = round(cost, 2)

    # Find cheapest
    optimal_carrier = min(carrier_quotes, key=carrier_quotes.get)

    return {
        'carrier_quotes': carrier_quotes,
        'optimal_carrier': optimal_carrier,
        'optimal_cost': carrier_quotes[optimal_carrier],
        'billable_weight': round(billable_weight, 1)
    }

# Example
shipping = carrier_rate_shopping(
    order_weight_lbs=5.0,
    order_dims=(16, 12, 8),  # inches
    destination_zip='90210',
    origin_zip='10001',
    delivery_speed='ground'
)

print("Carrier Quotes:")
for carrier, cost in shipping['carrier_quotes'].items():
    print(f"  {carrier}: ${cost}")
print(f"\nOptimal: {shipping['optimal_carrier']} - ${shipping['optimal_cost']}")
货运清单与装载计划
def manifest_optimization(orders_df, trailer_capacity=50000, carrier='UPS'):
    """
    Optimize order manifesting and trailer loading

    Parameters:
    - orders_df: DataFrame with ['order_id', 'weight', 'cube', 'carrier']
    - trailer_capacity: Trailer capacity (lbs or cube)
    - carrier: Filter orders by carrier
    """

    # Filter orders for carrier
    carrier_orders = orders_df[orders_df['carrier'] == carrier].copy()

    # Sort by weight (LIFO loading - heavy first)
    carrier_orders = carrier_orders.sort_values('weight', ascending=False)

    # Assign to trailers
    trailers = []
    current_trailer = {'orders': [], 'weight': 0, 'cube': 0}

    for _, order in carrier_orders.iterrows():
        # Check if fits in current trailer
        if current_trailer['weight'] + order['weight'] <= trailer_capacity:
            current_trailer['orders'].append(order['order_id'])
            current_trailer['weight'] += order['weight']
            current_trailer['cube'] += order['cube']
        else:
            # Start new trailer
            trailers.append(current_trailer)
            current_trailer = {
                'orders': [order['order_id']],
                'weight': order['weight'],
                'cube': order['cube']
            }

    # Add last trailer
    if current_trailer['orders']:
        trailers.append(current_trailer)

    # Summary
    manifest_summary = {
        'carrier': carrier,
        'total_orders': len(carrier_orders),
        'trailers_needed': len(trailers),
        'avg_weight_per_trailer': round(np.mean([t['weight'] for t in trailers]), 0),
        'avg_utilization_%': round(np.mean([t['weight']/trailer_capacity for t in trailers]) * 100, 1)
    }

    return trailers, manifest_summary

# Example
orders = pd.DataFrame({
    'order_id': [f'ORD_{i}' for i in range(1, 501)],
    'weight': np.random.uniform(10, 200, 500),
    'cube': np.random.uniform(1, 20, 500),
    'carrier': np.random.choice(['UPS', 'FedEx', 'USPS'], 500)
})

trailers, summary = manifest_optimization(orders, trailer_capacity=10000, carrier='UPS')
print(f"Carrier: {summary['carrier']}")
print(f"Trailers needed: {summary['trailers_needed']}")
print(f"Average utilization: {summary['avg_utilization_%']}%")

履约绩效指标

关键绩效指标(KPI)
def calculate_fulfillment_kpis(total_orders, orders_on_time, orders_accurate,
                              total_units, labor_hours, total_cost):
    """
    Calculate fulfillment KPIs

    Parameters:
    - total_orders: Orders processed
    - orders_on_time: Orders shipped on time
    - orders_accurate: Orders shipped accurately
    - total_units: Total units shipped
    - labor_hours: Total labor hours
    - total_cost: Total fulfillment cost
    """

    # On-time delivery rate
    on_time_rate = orders_on_time / total_orders

    # Order accuracy
    accuracy_rate = orders_accurate / total_orders

    # Units per labor hour
    units_per_hour = total_units / labor_hours

    # Orders per labor hour
    orders_per_hour = total_orders / labor_hours

    # Cost per order
    cost_per_order = total_cost / total_orders

    # Cost per unit
    cost_per_unit = total_cost / total_units

    kpis = {
        'On_Time_Delivery_%': round(on_time_rate * 100, 2),
        'Order_Accuracy_%': round(accuracy_rate * 100, 2),
        'Units_per_Labor_Hour': round(units_per_hour, 1),
        'Orders_per_Labor_Hour': round(orders_per_hour, 1),
        'Cost_per_Order': round(cost_per_order, 2),
        'Cost_per_Unit': round(cost_per_unit, 2)
    }

    return kpis

# Example
kpis = calculate_fulfillment_kpis(
    total_orders=10000,
    orders_on_time=9700,
    orders_accurate=9950,
    total_units=50000,
    labor_hours=1200,
    total_cost=120000
)

print("Fulfillment KPIs:")
for metric, value in kpis.items():
    print(f"  {metric}: {value}")
基准目标
指标目标世界级水平
订单准确率99%+99.8%+
准时发运率95%+99%+
每工时处理件数100-150200+
拣选准确率99.5%+99.9%+
每单成本$3-$8<$3
每工时处理订单数15-2530+
收货至上架时间<24 hrs<4 hrs

高级履约策略

多渠道履约

策略:

  • 专用库存:为每个渠道分别备货
  • 共享库存:使用统一库存池,动态分配
  • 混合模式:畅销品共享库存,滞销品专用库存
def multi_channel_inventory_allocation(total_inventory, channels):
    """
    Allocate inventory across channels

    Parameters:
    - total_inventory: Total available inventory
    - channels: Dict with channel: {'demand_rate': X, 'priority': Y}

    Returns:
    - Inventory allocation by channel
    """

    # Calculate total demand
    total_demand = sum(ch['demand_rate'] for ch in channels.values())

    allocations = {}

    for channel, data in channels.items():
        # Proportional allocation based on demand
        base_allocation = (data['demand_rate'] / total_demand) * total_inventory

        # Adjust for priority (higher priority gets +10% buffer)
        priority_factor = 1 + ((data['priority'] - 2) * 0.10)  # Priority 1-3
        allocation = base_allocation * priority_factor

        allocations[channel] = round(allocation, 0)

    # Normalize to total inventory
    adjustment_factor = total_inventory / sum(allocations.values())
    allocations = {ch: round(qty * adjustment_factor, 0)
                  for ch, qty in allocations.items()}

    return allocations

# Example
channels = {
    'Retail_Stores': {'demand_rate': 1000, 'priority': 1},
    'Ecommerce': {'demand_rate': 800, 'priority': 2},
    'Wholesale': {'demand_rate': 500, 'priority': 3}
}

allocation = multi_channel_inventory_allocation(10000, channels)
print("Inventory Allocation:")
for channel, qty in allocation.items():
    print(f"  {channel}: {qty} units")
退货处理

逆向物流流程:

  1. 客户发起退货
  2. 生成退货标签
  3. 在设施处收货
  4. 检查并评定商品状况
  5. 处理方式(重新入库、清算、销毁)
  6. 办理退款/换货
def returns_processing_analysis(returns_per_day, inspection_rate_per_hour=50,
                               restock_pct=0.70, liquidate_pct=0.25,
                               destroy_pct=0.05):
    """
    Analyze returns processing requirements

    Parameters:
    - returns_per_day: Daily return volume
    - inspection_rate_per_hour: Returns inspected per person per hour
    - restock_pct, liquidate_pct, destroy_pct: Disposition percentages
    """

    # Labor for inspection
    labor_hours = returns_per_day / inspection_rate_per_hour

    # Disposition volumes
    restock_units = returns_per_day * restock_pct
    liquidate_units = returns_per_day * liquidate_pct
    destroy_units = returns_per_day * destroy_pct

    # Financial impact (example)
    # Assume average unit value $50
    avg_unit_value = 50

    # Restock: 90% recovery
    # Liquidate: 20% recovery
    # Destroy: 0% recovery

    value_recovered = (restock_units * avg_unit_value * 0.90 +
                      liquidate_units * avg_unit_value * 0.20)

    value_lost = (restock_units * avg_unit_value * 0.10 +
                 liquidate_units * avg_unit_value * 0.80 +
                 destroy_units * avg_unit_value)

    return {
        'returns_per_day': returns_per_day,
        'inspection_hours': round(labor_hours, 1),
        'restock_units': round(restock_units, 0),
        'liquidate_units': round(liquidate_units, 0),
        'destroy_units': round(destroy_units, 0),
        'value_recovered_daily': round(value_recovered, 0),
        'value_lost_daily': round(value_lost, 0),
        'recovery_rate_%': round((value_recovered / (value_recovered + value_lost)) * 100, 1)
    }

# Example
returns = returns_processing_analysis(
    returns_per_day=100,
    inspection_rate_per_hour=50
)

print(f"Returns per day: {returns['returns_per_day']}")
print(f"Inspection hours: {returns['inspection_hours']}")
print(f"Restock: {returns['restock_units']} units")
print(f"Value recovery rate: {returns['recovery_rate_%']}%")

工具与库

仓库管理系统(WMS)

企业级 WMS:

  • Manhattan Associates:一级 WMS,可高度配置
  • Blue Yonder (JDA):仓库管理套件
  • SAP EWM:扩展仓库管理
  • Oracle WMS:基于云的仓库管理
  • Infor WMS:针对特定行业的解决方案

中端市场 WMS:

  • HighJump (Korber):灵活的 WMS
  • NetSuite WMS:带有 WMS 的云 ERP
  • Fishbowl:面向小型到中型市场
  • 3PL Central:面向 3PL 的 WMS

开源:

  • Odoo:包含 WMS 模块的开源 ERP
  • iDempiere:开源 ERP/WMS
技术栈

硬件:

  • RF 扫描器(Zebra、Honeywell)
  • 移动电脑
  • 语音拣选系统(Vocollect、Honeywell)
  • 标签打印机(Zebra ZT 系列)
  • 自动分拣系统
  • 亮灯拣选 / 亮灯上架

软件集成:

  • OMS(订单管理系统)
  • TMS(运输管理)
  • 承运商集成(API)
  • 电商平台(Shopify、Magento)

常见挑战与解决方案

挑战:订单准确性问题

问题:

  • 拣选错误商品或数量
  • 发运错误订单
  • 客户投诉和退货

解决方案:

  • 实施条码扫描验证
  • 使用亮灯拣选或语音拣选
  • 对高价值商品要求双重验证
  • 包装时进行 QA 称重检查
  • 对错误进行根因分析
  • 加强拣选员培训并明确责任
挑战:劳动生产率差异

问题:

  • 拣货员的工作效率不一致
  • 部分员工的速度明显慢于其他员工
  • 难以合理安排人员

解决方案:

  • 实施劳动管理系统(LMS)
  • 跟踪个人生产率
  • 采用游戏化和激励措施
  • 制定标准作业流程
  • 持续培训
  • 改善人体工学
挑战:旺季产能

问题:

  • 假日期间的货量达到平时的 2-3 倍
  • 无法招聘和培训足够的临时员工
  • 空间受限

解决方案:

  • 提前 2 个月以上开始招聘和培训
  • 延长工作时间(增加班次)
  • 简化临时员工的作业流程
  • 将溢出货量交由第三方物流(3PL)合作伙伴处理
  • 采用自动化(相比人力更易扩展)
  • 通过波次计划分散作业量
挑战:运输成本攀升

问题:

  • 承运商费率不断上涨
  • 体积重量收费
  • 住宅配送附加费

解决方案:

  • 比较不同承运商的费率
  • 协商更优惠的合同(承诺货量)
  • 采用合适尺寸的包装(避免体积重量收费)
  • 跳区运输(批量运至当地承运商设施)
  • 设置区域配送中心(减少配送区域)
  • 为选择较慢配送方式的客户提供优惠
挑战:退货量

问题:

  • 退货率高(服装尤为明显)
  • 处理成本不断累积
  • 受损退货导致库存损失

解决方案:

  • 改进产品描述(减少因买错商品而退货)
  • 权衡免费退货政策的成本
  • 提高退货处理效率
  • 改进处置逻辑(尽可能提高重新入库比例)
  • 利用退货分析找出根本原因
  • 考虑对因政策原因退货的商品收取重新入库费

输出格式

履约运营设计文档

执行摘要:

  • 订单量和订单概况
  • 推荐的履约策略
  • 人力需求和成本
  • 预期绩效指标

订单概况:

指标数值
日均订单量2,000
日订单峰值5,000
每单行数5.2
每单件数6.8
订单类型60% 单件,30% 箱,10% 托盘

推荐的拣货策略:

  • 畅销商品(A 类商品):分区拣货,设置专用前置拣货区
  • 中速周转商品(B 类商品):批量拣货,每批 10 个订单
  • 慢速周转商品(C 类商品):从储备区进行单订单拣货

人力需求:

职能所需人数每日工时班次
拣货151202 班
包装10802 班
发货5402 班
退货处理2161 班
总计32256-

技术要求:

  • 具备波次计划和任务管理功能的 WMS
  • 为所有拣货员配备 RF 扫描器(20 台)
  • 配备秤和标签打印机的包装工位(12 个工位)
  • 集成承运商服务的运输清单软件
  • 为畅销商品配置亮灯拣货系统(可选,$200K)

绩效目标:

KPI目标当前值(如需优化)
订单准确率99.5%97.2%
按时发货率98%92%
每单成本$5.50$7.20
每工时处理件数150110

实施计划:

  1. 第 1-2 个月:实施并配置 WMS
  2. 第 3 个月:优化货位并调整布局
  3. 第 4 个月:推广流程并开展培训
  4. 第 5 个月:逐步提升产能并进行优化
  5. 第 6 个月:全面投产,持续改进

需要提出的问题

如果需要更多背景信息:

  1. 订单量是多少?(日均值和峰值)
  2. 订单概况如何?(每单行数、每单件数、订单类型)
  3. SKU 数量和周转速度分布如何?
  4. 服务要求是什么?(配送速度、准确率)
  5. 当前的履约流程和痛点是什么?
  6. 已部署哪些技术?(WMS、自动化、RF 扫描)
  7. 当地劳动力供应情况和成本如何?
  8. 改进预算是多少?

相关技能

  • warehouse-design:设计履约设施布局
  • warehouse-slotting-optimization:优化商品摆放
  • picker-routing-optimization:优化拣货路径
  • order-batching-optimization:优化订单批次
  • wave-planning-optimization:优化波次释放
  • ecommerce-fulfillment:电商专属策略
  • omnichannel-fulfillment:全渠道履约
  • last-mile-delivery:优化末端配送

评论

支持 Markdown