Files
server-configs/物控学习笔记/README.md
2026-02-03 15:35:04 +08:00

24 KiB
Raw Blame History

物控学习笔记 📚

物料控制Material Control学习笔记与最佳实践


📖 目录


基础知识

什么是物控?

物料控制Material Control是生产管理中的核心环节主要负责

  • 物料需求计划MRP
  • 库存管理与优化
  • 采购计划制定
  • 物料追溯与盘点
  • 成本控制

物控的核心指标

  1. 库存周转率 = 年销售成本 / 平均库存
  2. 库存天数 = 365 / 库存周转率
  3. 缺料率 = 缺料次数 / 总领料次数
  4. 呆滞料比例 = 呆滞料金额 / 总库存金额
  5. 物料齐套率 = 齐套订单数 / 总订单数

物控工作流程

1. 接收生产计划
   ↓
2. 计算物料需求BOM展开
   ↓
3. 检查库存状态
   ↓
4. 制定采购计划
   ↓
5. 跟踪物料到货
   ↓
6. 物料发放与追溯
   ↓
7. 库存盘点与优化

Excel VBA 工具库

现有工具

本仓库包含以下 Excel VBA 物控工具:

1. vba-mc-toolkit

Excel VBA 物控小程序库

功能模块

  • 物料需求计算
  • 库存报表生成
  • 采购订单管理
  • 盘点表自动生成
  • 呆滞料分析

使用方法

' 导入工具库
Sub Import_MC_Toolkit()
    Workbooks.Open "vba-mc-toolkit.xlsm"
    Application.Run "Initialize_MC_System"
End Sub

VBA 物控常用代码片段

1. 自动计算安全库存

Function Calculate_Safety_Stock(avg_demand As Double, lead_time As Double, service_level As Double) As Double
    ' avg_demand: 平均日需求
    ' lead_time: 采购提前期(天)
    ' service_level: 服务水平0.95 = 95%
    
    Dim z_score As Double
    Select Case service_level
        Case 0.90: z_score = 1.28
        Case 0.95: z_score = 1.65
        Case 0.98: z_score = 2.05
        Case 0.99: z_score = 2.33
        Case Else: z_score = 1.65
    End Select
    
    Calculate_Safety_Stock = avg_demand * lead_time * z_score
End Function

2. 库存预警

Sub Inventory_Alert()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets("库存")
    
    Dim last_row As Long
    last_row = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    For i = 2 To last_row
        Dim current_qty As Double
        Dim min_qty As Double
        Dim max_qty As Double
        
        current_qty = ws.Cells(i, "D").Value  ' 当前库存
        min_qty = ws.Cells(i, "E").Value      ' 最低库存
        max_qty = ws.Cells(i, "F").Value      ' 最高库存
        
        If current_qty < min_qty Then
            ws.Cells(i, "G").Value = "⚠️ 需补货"
            ws.Cells(i, "G").Interior.Color = RGB(255, 200, 200)
        ElseIf current_qty > max_qty Then
            ws.Cells(i, "G").Value = "📦 库存过高"
            ws.Cells(i, "G").Interior.Color = RGB(255, 255, 200)
        Else
            ws.Cells(i, "G").Value = "✅ 正常"
            ws.Cells(i, "G").Interior.Color = RGB(200, 255, 200)
        End If
    Next i
End Sub

3. 物料需求计算MRP

Sub Calculate_MRP()
    Dim ws_bom As Worksheet, ws_inventory As Worksheet, ws_mrp As Worksheet
    Set ws_bom = ThisWorkbook.Sheets("BOM")
    Set ws_inventory = ThisWorkbook.Sheets("库存")
    Set ws_mrp = ThisWorkbook.Sheets("MRP")
    
    ' 清空 MRP 表
    ws_mrp.Cells.Clear
    
    ' 设置表头
    ws_mrp.Range("A1:F1").Value = Array("物料编码", "物料名称", "需求量", "库存量", "净需求", "建议采购")
    
    ' 计算逻辑
    Dim last_row As Long
    last_row = ws_bom.Cells(ws_bom.Rows.Count, "A").End(xlUp).Row
    
    For i = 2 To last_row
        Dim part_no As String
        Dim qty_needed As Double
        Dim qty_in_stock As Double
        Dim net_qty As Double
        
        part_no = ws_bom.Cells(i, "A").Value
        qty_needed = ws_bom.Cells(i, "C").Value
        
        ' 查找库存
        qty_in_stock = Application.WorksheetFunction.VLookup(part_no, ws_inventory.Range("A:D"), 4, False)
        
        net_qty = qty_needed - qty_in_stock
        
        If net_qty > 0 Then
            ws_mrp.Cells(i, 1).Value = part_no
            ws_mrp.Cells(i, 3).Value = qty_needed
            ws_mrp.Cells(i, 4).Value = qty_in_stock
            ws_mrp.Cells(i, 5).Value = net_qty
            ws_mrp.Cells(i, 6).Value = net_qty * 1.1  ' 建议采购量(含 10% 安全系数)
        End If
    Next i
End Sub

4. 盘点表生成

Sub Generate_Inventory_Count_Sheet()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets.Add
    ws.Name = "盘点表_" & Format(Date, "yyyy-mm-dd")
    
    ' 设置表头
    ws.Range("A1:H1").Value = Array("序号", "物料编码", "物料名称", "规格", "单位", "账面数量", "实盘数量", "差异")
    ws.Range("A1:H1").Font.Bold = True
    
    ' 从库存表复制数据
    Dim ws_stock As Worksheet
    Set ws_stock = ThisWorkbook.Sheets("库存")
    
    Dim last_row As Long
    last_row = ws_stock.Cells(ws_stock.Rows.Count, "A").End(xlUp).Row
    
    For i = 2 To last_row
        ws.Cells(i, 1).Value = i - 1
        ws.Cells(i, 2).Value = ws_stock.Cells(i, "A").Value
        ws.Cells(i, 3).Value = ws_stock.Cells(i, "B").Value
        ws.Cells(i, 4).Value = ws_stock.Cells(i, "C").Value
        ws.Cells(i, 5).Value = ws_stock.Cells(i, "G").Value
        ws.Cells(i, 6).Value = ws_stock.Cells(i, "D").Value
    Next i
    
    ' 格式化
    ws.Columns("A:H").AutoFit
    ws.Range("H2:H" & last_row).Formula = "=F2-G2"
    
    MsgBox "盘点表生成完成!"
End Sub

5. 呆滞料分析

Sub Analyze_Stagnant_Inventory()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets("库存")
    
    Dim last_row As Long
    last_row = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row
    
    ' 添加呆滞料标识列
    ws.Cells(1, "I").Value = "呆滞状态"
    ws.Cells(1, "J").Value = "呆滞天数"
    
    For i = 2 To last_row
        Dim last_move_date As Date
        Dim days_stagnant As Long
        
        last_move_date = ws.Cells(i, "H").Value  ' 最后移动日期
        days_stagnant = Date - last_move_date
        
        ws.Cells(i, "J").Value = days_stagnant
        
        Select Case days_stagnant
            Case Is > 365
                ws.Cells(i, "I").Value = "🔴 严重呆滞(>1年"
                ws.Cells(i, "I").Interior.Color = RGB(255, 150, 150)
            Case Is > 180
                ws.Cells(i, "I").Value = "🟡 中度呆滞6-12月"
                ws.Cells(i, "I").Interior.Color = RGB(255, 220, 150)
            Case Is > 90
                ws.Cells(i, "I").Value = "⚠️ 轻度呆滞3-6月"
                ws.Cells(i, "I").Interior.Color = RGB(255, 255, 150)
            Case Else
                ws.Cells(i, "I").Value = "✅ 正常"
                ws.Cells(i, "I").Interior.Color = RGB(200, 255, 200)
        End Select
    Next i
    
    ' 统计
    Dim stagnant_count As Long
    Dim stagnant_value As Double
    
    For i = 2 To last_row
        If ws.Cells(i, "J").Value > 90 Then
            stagnant_count = stagnant_count + 1
            stagnant_value = stagnant_value + ws.Cells(i, "D").Value * ws.Cells(i, "E").Value
        End If
    Next i
    
    MsgBox "呆滞料分析完成!" & vbCrLf & _
           "呆滞物料数量:" & stagnant_count & vbCrLf & _
           "呆滞料金额:$" & Format(stagnant_value, "#,##0.00")
End Sub

库存管理

库存分类方法

ABC 分析法

  • A 类:价值占比 70-80%,数量占比 10-20% → 重点管理,高频盘点
  • B 类:价值占比 15-25%,数量占比 20-30% → 中等管理,中频盘点
  • C 类:价值占比 5-10%,数量占比 50-70% → 简化管理,低频盘点

VED 分类法(关键性)

  • VVital:关键物料,缺料导致停产
  • EEssential:重要物料,缺料影响生产
  • DDesirable:一般物料,缺料影响较小

库存优化策略

  1. 安全库存计算

    安全库存 = 平均日需求 × 安全天数 × 波动系数
    
    其中:
    - 安全天数 = 采购提前期 + 缓冲天数
    - 波动系数 = 1.2 ~ 1.5(根据历史数据调整)
    
  2. 订货点ROP

    订货点 = 平均日需求 × 采购提前期 + 安全库存
    
  3. 经济订货量EOQ

    EOQ = √(2 × 年需求量 × 单次订货成本 / 单位持有成本)
    

库存盘点方法

盘点方式 适用场景 优点 缺点
全面盘点 年度/半年度 准确性高 耗时耗力
循环盘点 日常管理 持续监控 覆盖不全
ABC 分类盘点 A类物料高频 重点突出 B/C类可能遗漏
随机抽样盘点 月度抽查 效率高 准确性较低

生产计划

MRP 计算逻辑

毛需求 = 生产计划 × BOM 用量

净需求 = 毛需求 - 现有库存 - 在途库存 + 安全库存

建议采购量 = 净需求 × 订货倍数MOQ

生产排程原则

  1. 优先级规则

    • 交期优先EDD
    • 最短加工时间SPT
    • 关键比率CR
  2. 产能平衡

    产能负荷 = 标准工时 × 数量 / 有效工时
    
    负荷率 = 产能负荷 / 总产能
    
  3. 瓶颈管理

    • 识别瓶颈工序
    • 瓶颈前缓冲库存
    • 瓶颈后拉式生产

数据分析

关键指标仪表板

# Python 物控数据分析示例
import pandas as pd
import matplotlib.pyplot as plt

# 1. 库存周转率分析
def inventory_turnover_analysis(df):
    """
    df: 包含 '物料编码', '期初库存', '期末库存', '销售成本' 的 DataFrame
    """
    df['平均库存'] = (df['期初库存'] + df['期末库存']) / 2
    df['库存周转率'] = df['销售成本'] / df['平均库存']
    df['库存天数'] = 365 / df['库存周转率']
    
    return df

# 2. 呆滞料分析
def stagnant_inventory_analysis(df, days_threshold=90):
    """
    分析呆滞料
    """
    df['呆滞天数'] = (pd.Timestamp.now() - df['最后移动日期']).dt.days
    df['呆滞状态'] = pd.cut(df['呆滞天数'], 
                           bins=[0, 30, 90, 180, 365, float('inf')],
                           labels=['正常', '预警', '轻度呆滞', '中度呆滞', '严重呆滞'])
    
    return df

# 3. 库存结构分析
def inventory_structure_analysis(df):
    """
    ABC 分类
    """
    df['物料价值'] = df['库存数量'] * df['单价']
    df_sorted = df.sort_values('物料价值', ascending=False)
    df_sorted['累计价值占比'] = df_sorted['物料价值'].cumsum() / df_sorted['物料价值'].sum()
    
    def abc_class(cum_ratio):
        if cum_ratio <= 0.8:
            return 'A'
        elif cum_ratio <= 0.95:
            return 'B'
        else:
            return 'C'
    
    df_sorted['ABC分类'] = df_sorted['累计价值占比'].apply(abc_class)
    
    return df_sorted

可视化仪表板

# 库存仪表板
def create_inventory_dashboard(df):
    fig, axes = plt.subplots(2, 2, figsize=(15, 10))
    
    # 1. 库存结构饼图
    abc_counts = df['ABC分类'].value_counts()
    axes[0, 0].pie(abc_counts.values, labels=abc_counts.index, autopct='%1.1f%%')
    axes[0, 0].set_title('ABC 库存结构')
    
    # 2. 库存周转率柱状图
    top_items = df.nlargest(10, '库存周转率')
    axes[0, 1].bar(top_items['物料编码'], top_items['库存周转率'])
    axes[0, 1].set_title('Top 10 库存周转率')
    axes[0, 1].tick_params(axis='x', rotation=45)
    
    # 3. 呆滞料分布
    stagnant_counts = df['呆滞状态'].value_counts()
    axes[1, 0].bar(stagnant_counts.index, stagnant_counts.values)
    axes[1, 0].set_title('呆滞料分布')
    
    # 4. 库存价值分布
    axes[1, 1].hist(df['物料价值'], bins=20, edgecolor='black')
    axes[1, 1].set_title('库存价值分布')
    axes[1, 1].set_xlabel('物料价值')
    axes[1, 1].set_ylabel('频次')
    
    plt.tight_layout()
    plt.savefig('inventory_dashboard.png', dpi=300, bbox_inches='tight')
    plt.show()

自动化脚本

Python 物控自动化工具

1. 库存报表自动生成

# inventory_report.py
import pandas as pd
import openpyxl
from datetime import datetime

class InventoryReporter:
    def __init__(self, data_file):
        self.data = pd.read_excel(data_file)
        self.report_date = datetime.now()
    
    def generate_daily_report(self):
        """生成日报"""
        report = {
            '日期': self.report_date.strftime('%Y-%m-%d'),
            '库存总金额': self.data['库存金额'].sum(),
            '库存物料数': len(self.data),
            '呆滞料金额': self.data[self.data['呆滞天数'] > 90]['库存金额'].sum(),
            '缺料物料数': len(self.data[self.data['库存数量'] < self.data['安全库存']]),
            '库存周转率': self.data['销售成本'].sum() / self.data['平均库存'].sum()
        }
        return pd.DataFrame([report])
    
    def export_to_excel(self, output_path):
        """导出到 Excel"""
        with pd.ExcelWriter(output_path, engine='openpyxl') as writer:
            # 汇总表
            summary = self.generate_daily_report()
            summary.to_excel(writer, sheet_name='汇总', index=False)
            
            # 明细表
            self.data.to_excel(writer, sheet_name='库存明细', index=False)
            
            # 呆滞料表
            stagnant = self.data[self.data['呆滞天数'] > 90]
            stagnant.to_excel(writer, sheet_name='呆滞料', index=False)
            
            # 缺料表
            shortage = self.data[self.data['库存数量'] < self.data['安全库存']]
            shortage.to_excel(writer, sheet_name='缺料预警', index=False)
        
        print(f"报表已生成:{output_path}")

2. 自动补货计算

# auto_replenishment.py
import pandas as pd
import numpy as np

class AutoReplenishment:
    def __init__(self, inventory_data, demand_data):
        self.inventory = inventory_data
        self.demand = demand_data
    
    def calculate_reorder_point(self, lead_time_days, service_level=0.95):
        """计算订货点"""
        # 计算平均日需求和标准差
        avg_daily_demand = self.demand['日需求量'].mean()
        std_daily_demand = self.demand['日需求量'].std()
        
        # Z 值(服务水平)
        z_values = {0.90: 1.28, 0.95: 1.65, 0.98: 2.05, 0.99: 2.33}
        z = z_values.get(service_level, 1.65)
        
        # 安全库存
        safety_stock = z * std_daily_demand * np.sqrt(lead_time_days)
        
        # 订货点
        reorder_point = avg_daily_demand * lead_time_days + safety_stock
        
        return {
            '平均日需求': avg_daily_demand,
            '安全库存': safety_stock,
            '订货点': reorder_point
        }
    
    def generate_purchase_plan(self):
        """生成采购计划"""
        purchase_list = []
        
        for _, item in self.inventory.iterrows():
            if item['当前库存'] < item['订货点']:
                # 计算建议采购量
                lead_time = item['采购提前期']
                avg_demand = self.demand[self.demand['物料编码'] == item['物料编码']]['日需求量'].mean()
                
                # 建议采购量 = (提前期需求 + 安全库存) - 当前库存
                suggested_qty = (avg_demand * lead_time + item['安全库存']) - item['当前库存']
                
                # 考虑最小订货量MOQ
                moq = item.get('最小订货量', 1)
                if suggested_qty < moq:
                    suggested_qty = moq
                
                purchase_list.append({
                    '物料编码': item['物料编码'],
                    '物料名称': item['物料名称'],
                    '当前库存': item['当前库存'],
                    '订货点': item['订货点'],
                    '建议采购量': suggested_qty,
                    '供应商': item.get('供应商', ''),
                    '预计到货日期': pd.Timestamp.now() + pd.Timedelta(days=item['采购提前期'])
                })
        
        return pd.DataFrame(purchase_list)

3. 库存预警系统

# inventory_alert.py
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import pandas as pd

class InventoryAlert:
    def __init__(self, smtp_config):
        self.smtp_server = smtp_config['server']
        self.smtp_port = smtp_config['port']
        self.email_user = smtp_config['user']
        self.email_password = smtp_config['password']
    
    def check_inventory_status(self, inventory_df):
        """检查库存状态"""
        alerts = []
        
        for _, item in inventory_df.iterrows():
            # 缺料预警
            if item['当前库存'] < item['安全库存']:
                alerts.append({
                    '类型': '缺料预警',
                    '物料编码': item['物料编码'],
                    '物料名称': item['物料名称'],
                    '当前库存': item['当前库存'],
                    '安全库存': item['安全库存'],
                    '缺口': item['安全库存'] - item['当前库存']
                })
            
            # 呆滞料预警
            if item['呆滞天数'] > 90:
                alerts.append({
                    '类型': '呆滞料预警',
                    '物料编码': item['物料编码'],
                    '物料名称': item['物料名称'],
                    '呆滞天数': item['呆滞天数'],
                    '库存金额': item['库存金额']
                })
            
            # 库存过高预警
            if item['当前库存'] > item['最高库存']:
                alerts.append({
                    '类型': '库存过高',
                    '物料编码': item['物料编码'],
                    '物料名称': item['物料名称'],
                    '当前库存': item['当前库存'],
                    '最高库存': item['最高库存']
                })
        
        return pd.DataFrame(alerts)
    
    def send_alert_email(self, alerts_df, recipient):
        """发送预警邮件"""
        if alerts_df.empty:
            return
        
        msg = MIMEMultipart('alternative')
        msg['Subject'] = f'库存预警报告 - {pd.Timestamp.now().strftime("%Y-%m-%d")}'
        msg['From'] = self.email_user
        msg['To'] = recipient
        
        # 生成 HTML
        html = f"""
        <html>
        <head>
            <style>
                body {{ font-family: Arial, sans-serif; }}
                table {{ border-collapse: collapse; width: 100%; }}
                th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
                th {{ background-color: #f2f2f2; }}
                .alert-high {{ background-color: #ffcccc; }}
                .alert-medium {{ background-color: #fff3cd; }}
            </style>
        </head>
        <body>
            <h2>库存预警报告</h2>
            <p>生成时间:{pd.Timestamp.now().strftime("%Y-%m-%d %H:%M")}</p>
            <table>
                <tr>
                    <th>类型</th>
                    <th>物料编码</th>
                    <th>物料名称</th>
                    <th>数值</th>
                    <th>状态</th>
                </tr>
        """
        
        for _, row in alerts_df.iterrows():
            row_class = "alert-high" if row['类型'] in ['缺料预警', '呆滞料预警'] else "alert-medium"
            value = row.get('缺口', row.get('呆滞天数', row.get('当前库存', '')))
            html += f"""
                <tr class="{row_class}">
                    <td>{row['类型']}</td>
                    <td>{row['物料编码']}</td>
                    <td>{row['物料名称']}</td>
                    <td>{value}</td>
                    <td>需要处理</td>
                </tr>
            """
        
        html += """
            </table>
            <p>请及时处理预警事项!</p>
        </body>
        </html>
        """
        
        msg.attach(MIMEText(html, 'html'))
        
        # 发送邮件
        with smtplib.SMTP_SSL(self.smtp_server, self.smtp_port) as server:
            server.login(self.email_user, self.email_password)
            server.send_message(msg)
        
        print(f"预警邮件已发送至 {recipient}")

案例研究

案例 1降低库存周转天数

背景

  • 某电子厂库存周转天数90 天
  • 目标:降低至 60 天

措施

  1. ABC 分类管理
  2. 优化安全库存
  3. 实施 VMI供应商管理库存
  4. 定期盘点与清理呆滞料

结果

  • 库存周转天数降至 55 天
  • 库存资金占用减少 38%
  • 缺料率从 5% 降至 1.5%

案例 2呆滞料清理

背景

  • 呆滞料金额:$500,000
  • 占总库存15%

措施

  1. 呆滞料分析与分类
  2. 制定清理计划(折价销售、退供应商、报废)
  3. 优化采购策略
  4. 建立呆滞料预警机制

结果

  • 呆滞料减少 70%
  • 释放资金 $350,000
  • 库存结构优化

资源推荐

书籍

  1. 《物料管理实务》 - 作者:王文信
  2. 《生产与运营管理》 - 作者Richard B. Chase
  3. 《供应链管理:战略、规划与运作》 - 作者Sunil Chopra

在线课程

  1. Coursera - Supply Chain Management Specialization
  2. Udemy - Inventory Management and Control
  3. edX - Operations Management

工具软件

  1. ERP 系统SAP、Oracle、金蝶、用友
  2. WMS 系统:仓库管理系统
  3. Excel VBA:自定义工具开发

行业标准

  1. ISO 9001 - 质量管理体系
  2. ISO 28000 - 供应链安全管理体系
  3. APICS CPIM - 生产与库存管理认证

快速开始

1. 安装依赖

# Python 环境
pip install pandas openpyxl matplotlib

# Excel VBA
# 打开 Excel → 开发工具 → Visual Basic → 导入模块

2. 使用示例

# 导入工具库
from inventory_report import InventoryReporter
from auto_replenishment import AutoReplenishment

# 生成日报
reporter = InventoryReporter('inventory_data.xlsx')
reporter.export_to_excel('daily_report.xlsx')

# 自动补货
replenishment = AutoReplenishment(inventory_data, demand_data)
purchase_plan = replenishment.generate_purchase_plan()
purchase_plan.to_excel('purchase_plan.xlsx', index=False)

3. Excel VBA 使用

' 打开工具库
Sub Open_MC_Toolkit()
    Workbooks.Open "vba-mc-toolkit.xlsm"
End Sub

' 运行库存预警
Sub Run_Inventory_Alert()
    Call Inventory_Alert
End Sub

' 生成盘点表
Sub Run_Generate_Count_Sheet()
    Call Generate_Inventory_Count_Sheet
End Sub

贡献指南

欢迎贡献你的物控经验和工具!

如何贡献

  1. Fork 本仓库
  2. 创建你的分支 (git checkout -b feature/your-feature)
  3. 提交你的更改 (git commit -m 'Add some feature')
  4. 推送到分支 (git push origin feature/your-feature)
  5. 创建 Pull Request

贡献内容

  • Excel VBA 工具脚本
  • Python 自动化工具
  • 物控案例分析
  • 最佳实践文档
  • 数据分析模板

许可证

本项目采用 MIT 许可证 - 详见 LICENSE 文件


联系方式

如有问题或建议,请通过以下方式联系:


更新日志

v1.0.0 (2026-02-03)

  • 创建物控学习笔记仓库
  • 添加基础知识文档
  • 添加 Excel VBA 工具库
  • 添加 Python 自动化脚本
  • 添加案例研究
  • 添加资源推荐

最后更新: 2026-02-03
维护者: 1803560007
版本: v1.0.0