个人编程网站

进销存(JXC)软件开发技术积累与分享

进销存系统智能补货算法与库存优化

智能补货概述

智能补货是进销存系统的核心功能,通过算法预测未来需求,自动生成采购建议,实现库存的最优化管理。本文介绍多种智能补货算法,包括安全库存计算、订货点法、经济订货量、JIT 补货等方案。

补货算法对比

算法 适用场景 优点 缺点
安全库存 需求波动大 防止缺货 占用资金
订货点法 稳定需求 自动触发 需要准确预测
EOQ 经济订货量 批量采购 成本最优 假设理想化
JIT 补货 供应商稳定 库存最小化 风险较高

安全库存计算

基于服务水平和需求波动计算安全库存:

// 安全库存计算器
class SafetyStockCalculator {
  constructor(config) {
    this.serviceLevel = config.serviceLevel || 0.95; // 服务水平 95%
    this.leadTimeDays = config.leadTimeDays || 7; // 采购提前期
  }

  // 正态分布分位点
  getZScore(serviceLevel) {
    const zScores = {
      0.90: 1.28,
      0.95: 1.65,
      0.97: 1.88,
      0.99: 2.33
    };
    return zScores[serviceLevel] || 1.65;
  }

  // 计算安全库存
  calculate(dailyDemand, demandStdDev, leadTimeDays = this.leadTimeDays) {
    const z = this.getZScore(this.serviceLevel);

    // 安全库存 = Z值 * 需求标准差 * sqrt(采购提前期)
    const safetyStock = Math.ceil(z * demandStdDev * Math.sqrt(leadTimeDays));

    return safetyStock;
  }

  // 使用历史数据计算
  calculateFromHistory(salesData, leadTimeDays = this.leadTimeDays) {
    // 计算日均需求
    const avgDaily = salesData.reduce((sum, d) => sum + d.quantity, 0) / salesData.length;

    // 计算需求标准差
    const variance = salesData.reduce((sum, d) =>
      sum + Math.pow(d.quantity - avgDaily, 2), 0) / salesData.length;
    const stdDev = Math.sqrt(variance);

    return this.calculate(avgDaily, stdDev, leadTimeDays);
  }
}

// 订货点计算
class ReorderPointCalculator {
  constructor() {
    this.safetyStock = new SafetyStockCalculator({ serviceLevel: 0.95 });
  }

  // 订货点 = 日均需求 * 采购提前期 + 安全库存
  calculate(avgDailyDemand, leadTimeDays, currentStock = 0) {
    // 计算安全库存
    const safety = this.safetyStock.calculate(avgDailyDemand, avgDailyDemand * 0.3, leadTimeDays);

    // 订货点
    const reorderPoint = Math.ceil(avgDailyDemand * leadTimeDays + safety);

    return {
      reorderPoint,
      safetyStock: safety,
      currentStock: currentStock,
      needReorder: currentStock <= reorderPoint,
      suggestedQuantity: Math.max(0, reorderPoint - currentStock + safety * 2)
    };
  }
}

// 使用示例
const calculator = new ReorderPointCalculator();

// 根据历史销售计算
const salesHistory = [
  { date: '2025-06-01', quantity: 120 },
  { date: '2025-06-02', quantity: 95 },
  { date: '2025-06-03', quantity: 110 },
  { date: '2025-06-04', quantity: 130 },
  { date: '2025-06-05', quantity: 85 },
  { date: '2025-06-06', quantity: 105 },
  { date: '2025-06-07', quantity: 115 }
];

const safetyCalc = new SafetyStockCalculator({ serviceLevel: 0.95, leadTimeDays: 7 });
const safetyStock = safetyCalc.calculateFromHistory(salesHistory, 7);

const avgDaily = salesHistory.reduce((s, d) => s + d.quantity, 0) / salesHistory.length;
const result = calculator.calculate(avgDaily, 7, 50); // 当前库存 50

console.log('安全库存:', safetyStock);
console.log('订货点:', result.reorderPoint);
console.log('建议补货量:', result.suggestedQuantity);

经济订货量(EOQ)模型

平衡采购成本和库存持有成本:

// 经济订货量 (EOQ) 计算
class EOQCalculator {
  constructor(annualDemand, unitCost, orderingCost, holdingCostRate) {
    this.annualDemand = annualDemand; // 年需求量
    this.unitCost = unitCost; // 单位采购成本
    this.orderingCost = orderingCost; // 每次订货成本
    this.holdingCostRate = holdingCostRate; // 库存持有成本率
  }

  // EOQ = sqrt(2 * 年需求量 * 订货成本 / 单位持有成本)
  calculate() {
    const holdingCostPerUnit = this.unitCost * this.holdingCostRate;
    const eoq = Math.sqrt(
      (2 * this.annualDemand * this.orderingCost) / holdingCostPerUnit
    );

    return Math.ceil(eoq);
  }

  // 计算总成本
  calculateTotalCost(orderQuantity) {
    // 订货次数
    const ordersPerYear = this.annualDemand / orderQuantity;

    // 订货成本
    const totalOrderingCost = ordersPerYear * this.orderingCost;

    // 持有成本(平均库存 * 单位持有成本)
    const avgInventory = orderQuantity / 2;
    const holdingCostPerUnit = this.unitCost * this.holdingCostRate;
    const totalHoldingCost = avgInventory * holdingCostPerUnit;

    // 采购成本
    const purchaseCost = this.annualDemand * this.unitCost;

    return {
      purchaseCost,
      orderingCost: totalOrderingCost,
      holdingCost: totalHoldingCost,
      totalCost: purchaseCost + totalOrderingCost + totalHoldingCost,
      ordersPerYear: Math.ceil(ordersPerYear)
    };
  }
}

// 批量折扣模型
class QuantityDiscountEOQ {
  constructor(annualDemand, orderingCost, discountTiers) {
    this.annualDemand = annualDemand;
    this.orderingCost = orderingCost;
    this.discountTiers = discountTiers.sort((a, b) => b.discount - a.discount);
  }

  findOptimalOrder() {
    const results = [];

    // 1. 计算 EOQ
    const eoq = Math.sqrt(
      (2 * this.annualDemand * this.orderingCost) /
      (this.discountTiers[0].price * 0.2) // 假设持有成本率 20%
    );

    // 2. 检查 EOQ 是否在某个折扣区间
    const eoqTier = this.discountTiers.find(t => eoq >= t.minQuantity);

    // 3. 计算每个折扣级别的最优订货量
    for (const tier of this.discountTiers) {
      const holdingRate = 0.2;
      const holdingCost = tier.price * holdingRate;
      const eoqForTier = Math.sqrt(
        (2 * this.annualDemand * this.orderingCost) / holdingCost
      );

      // 限制在最小数量
      const orderQty = Math.max(eoqForTier, tier.minQuantity);
      const calc = new EOQCalculator(
        this.annualDemand,
        tier.price,
        this.orderingCost,
        holdingRate
      );
      const costInfo = calc.calculateTotalCost(orderQty);

      results.push({
        discount: tier.discount,
        price: tier.price,
        orderQuantity: orderQty,
        ...costInfo
      });
    }

    // 4. 选择总成本最低的方案
    results.sort((a, b) => a.totalCost - b.totalCost);

    return results[0];
  }
}

// 折扣级别定义
const discountTiers = [
  { minQuantity: 1, discount: 0, price: 100 },
  { minQuantity: 100, discount: 0.05, price: 95 },
  { minQuantity: 500, discount: 0.10, price: 90 },
  { minQuantity: 1000, discount: 0.15, price: 85 }
];

const solver = new QuantityDiscountEOQ(10000, 500, discountTiers);
const optimal = solver.findOptimalOrder();
console.log('最优方案:', optimal);

智能需求预测

结合多种算法预测未来需求:

// 需求预测器
class DemandForecaster {
  constructor() {
    this.models = {
      movingAverage: this.movingAverage.bind(this),
      weightedMovingAverage: this.weightedMovingAverage.bind(this),
      exponentialSmoothing: this.exponentialSmoothing.bind(this)
    };
  }

  // 移动平均
  movingAverage(data, period = 7) {
    if (data.length < period) return null;
    const recent = data.slice(-period);
    return recent.reduce((sum, v) => sum + v, 0) / period;
  }

  // 加权移动平均(近期权重更大)
  weightedMovingAverage(data, weights) {
    if (data.length < weights.length) return null;
    const recent = data.slice(-weights.length);
    const weightedSum = recent.reduce((sum, v, i) => sum + v * weights[i], 0);
    return weightedSum / weights.reduce((s, w) => s + w, 0);
  }

  // 指数平滑
  exponentialSmoothing(data, alpha = 0.3) {
    if (data.length === 0) return null;

    let forecast = data[0];
    for (let i = 1; i < data.length; i++) {
      forecast = alpha * data[i] + (1 - alpha) * forecast;
    }
    return forecast;
  }

  // 综合预测(结合多种方法)
  ensembleForecast(data) {
    const predictions = [];

    // 移动平均
    const ma = this.movingAverage(data, 7);
    if (ma) predictions.push({ method: 'MA7', value: ma, weight: 0.2 });

    // 加权移动平均(4周权重)
    const wma = this.weightedMovingAverage(data, [0.1, 0.15, 0.25, 0.5]);
    if (wma) predictions.push({ method: 'WMA', value: wma, weight: 0.3 });

    // 指数平滑
    const es = this.exponentialSmoothing(data, 0.3);
    if (es) predictions.push({ method: 'ES', value: es, weight: 0.5 });

    // 加权平均
    const totalWeight = predictions.reduce((s, p) => s + p.weight, 0);
    const forecast = predictions.reduce((s, p) => s + p.value * p.weight, 0) / totalWeight;

    return {
      forecast: Math.round(forecast),
      details: predictions
    };
  }
}

// 智能补货建议生成
class SmartReplenishment {
  constructor(config) {
    this.forecaster = new DemandForecaster();
    this.safetyStockCalc = new SafetyStockCalculator({
      serviceLevel: config.serviceLevel || 0.95,
      leadTimeDays: config.leadTimeDays || 7
    });
  }

  generateRecommendation(productId, salesHistory, currentStock, leadTimeDays) {
    // 1. 预测未来需求
    const demand = salesHistory.map(s => s.quantity);
    const forecast = this.forecaster.ensembleForecast(demand);

    // 2. 计算安全库存
    const demandStdDev = this.calculateStdDev(demand);
    const safetyStock = this.safetyStockCalc.calculate(
      forecast.forecast,
      demandStdDev,
      leadTimeDays
    );

    // 3. 计算订货点
    const avgDemand = demand.reduce((s, v) => s + v, 0) / demand.length;
    const reorderPoint = Math.ceil(avgDemand * leadTimeDays + safetyStock);

    // 4. 计算建议补货量(考虑目标库存)
    const targetStock = safetyStock + avgDemand * 14; // 目标库存 = 安全库存 + 14天销量
    const suggestedQty = Math.max(0, Math.ceil(targetStock - currentStock));

    // 5. 紧急程度判断
    const urgency = this.calculateUrgency(currentStock, reorderPoint, avgDemand);

    return {
      productId,
      currentStock,
      forecast: forecast.forecast,
      safetyStock,
      reorderPoint,
      suggestedQuantity: suggestedQty,
      urgency,
      daysUntilStockout: currentStock / avgDemand
    };
  }

  calculateStdDev(data) {
    const avg = data.reduce((s, v) => s + v, 0) / data.length;
    const variance = data.reduce((s, v) => s + Math.pow(v - avg, 2), 0) / data.length;
    return Math.sqrt(variance);
  }

  calculateUrgency(currentStock, reorderPoint, avgDaily) {
    if (currentStock <= 0) return 'CRITICAL';
    if (currentStock <= reorderPoint * 0.5) return 'HIGH';
    if (currentStock <= reorderPoint) return 'MEDIUM';
    return 'LOW';
  }
}

总结

智能补货算法是进销存系统的核心功能,合理的补货策略可以:

建议根据企业实际情况选择合适的算法,并持续优化参数。

← 下一篇:进销存系统智能销售预测与需求预测算法