Files
AutoBOM/docs/Inventory_Check_Implementation_Summary.md
Misaka_Company 8477792d41
All checks were successful
NTFY Notification / notify (push) Successful in 7s
feat: integrate inventory verification for component materials in BOM extraction
Implement inventory-based component selection logic that accumulates demand
across orders and falls back to sub-components (joint + element) when stock
is insufficient.

**Changes:**
- M04_Config: Add inventory worksheet configuration constants
  - INVENTORY_SHEET_NAME = "现存量"
  - INVENTORY_HEADER_ROW = 3 (headers on row 3)
  - INVENTORY_COL_CODE = "B" (material code)
  - INVENTORY_COL_QTY = "J" (stock quantity)

- M08_ComponentProcessor: Implement inventory tracking and verification
  - Add module-level variables: g_InventoryDict, g_AccumulatedDemandDict
  - Add LoadInventoryData() to load stock from [现存量] worksheet
  - Add InitComponentProcessorWithInventory() for initialization with inventory
  - Rewrite CheckComponentInventory() with actual inventory logic:
    * Calculate cumulative demand = orderQty × bomQty + previousAccumulated
    * Compare with available stock
    * Return True if stock sufficient, False otherwise
    * Update accumulated demand after each order
  - Update ProcessComponentRecord() to accept orderQty parameter

- M09_BOMExtractor: Integrate inventory check into main workflow
  - Modify ReadInputModels() to read 3 columns (orderNo, model, qty)
  - Initialize component processor with inventory support
  - Extract order quantity from column C and pass through call chain
  - Update ProcessSingleModel() and MatchAllMaterialTypesWithValidation()
    signatures to accept orderQty parameter

**Logic Example:**
- 3 orders (PO-001, PO-003, PO-006) use component A
- Each order: quantity=2, BOM qty=1, stock=5
- PO-001: cumulative=2, stock 5>=2 ✓ → return component
- PO-003: cumulative=4, stock 5>=4 ✓ → return component
- PO-006: cumulative=6, stock 5<6 ✗ → return sub-components

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-24 16:21:18 +08:00

237 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 库存校验功能集成总结
## 实施日期
2026-02-24
## 功能概述
`RunBOMExtraction` 过程中集成了库存校验功能,针对部件物料进行库存检查。根据订单顺序累加需求量,当库存充足时使用部件,不足时使用子件(接头+弹性元件)。
## 修改的文件
### 1. M04_Config.bas
**修改内容:** 添加现存量工作表配置常量
```vba
' 现存量工作表配置常量
Public Const INVENTORY_SHEET_NAME As String = "现存量"
Public Const INVENTORY_HEADER_ROW As Long = 3 ' 表头在第3行
Public Const INVENTORY_COL_CODE As String = "B" ' B列 = 物料编码
Public Const INVENTORY_COL_QTY As String = "J" ' J列 = 库存数量
```
### 2. M08_ComponentProcessor.bas
**修改内容:**
#### 2.1 添加库存追踪模块级变量
```vba
' 模块级变量 - 库存追踪
Private g_InventoryDict As Object ' 部件编码 -> 现存量
Private g_AccumulatedDemandDict As Object ' 部件编码 -> 累计需求量
```
#### 2.2 新增 `LoadInventoryData` 函数
- 从[现存量]工作表加载库存数据
- 表头在第3行从第4行开始读取
- B列 = 物料编码J列 = 库存数量
- 如果未找到工作表记录警告并使用空字典所有库存视为0
#### 2.3 新增 `InitComponentProcessorWithInventory` 函数
- 初始化部件处理器,同时加载库存数据
- 创建累计需求量字典
- 调用 `LoadInventoryData` 加载库存
#### 2.4 重写 `CheckComponentInventory` 函数
**输入参数:**
- `wsComponent` - "部件"工作表
- `rowNum` - 匹配到的行号
- `headerMap` - 表头映射
- `orderQty` - 订单数量(新增)
**逻辑流程:**
1. 提取部件编码
2. 获取BOM需求量部件工作表中的数量列
3. 检查库存数据是否存在
4. 计算累计需求量 = 订单数量 × BOM需求量 + 之前累计需求
5. 比较库存和需求:
- 库存 >= 累计需求 → 返回 True更新累计需求量
- 库存 < 累计需求 → 返回 False记录错误
#### 2.5 修改 `ProcessComponentRecord` 函数签名
**新增参数:** `orderQty As Long`
**修改调用:** 传递 `orderQty``CheckComponentInventory`
### 3. M09_BOMExtractor.bas
**修改内容:**
#### 3.1 修改 `ReadInputModels` 函数
**当前实现:** 读取2列生产订单号、产品型号
**注意:** 计划中提到读取3列包括数量但当前代码仍使用 `ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, colIdx)).Value`,需要确保 `colIdx` 变量包含第3列数量列
**建议修改:**
```vba
' 确保读取到第3列数量
ReadInputModels = ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, 3)).Value
```
#### 3.2 修改 `RunBOMExtraction` 主循环
**修改点1** 提取数量列
```vba
Dim orderQty As Long
orderQty = CLng(inputModels(i, 3)) ' Column C: 数量
```
**修改点2** 初始化部件处理器时传递库存工作簿
```vba
Dim invWorkbook As Workbook
Set invWorkbook = ThisWorkbook ' 现存量在主工作簿中
M08_ComponentProcessor.InitComponentProcessorWithInventory g_Logger, invWorkbook
```
**修改点3** 传递数量给 `ProcessSingleModel`
```vba
Set modelResults = ProcessSingleModel(modelString, g_BOMWorkbook, g_Logger, productionOrderNo, orderQty)
```
#### 3.3 修改 `ProcessSingleModel` 函数签名
**新增参数:** `orderQty As Long`
**修改调用:** 传递 `orderQty``MatchAllMaterialTypesWithValidation`
#### 3.4 修改 `MatchAllMaterialTypesWithValidation` 函数签名
**新增参数:** `orderQty As Long`
**修改调用:** 传递 `orderQty``ProcessComponentRecord`
## 数据流程
### 输入数据
**[产品型号]工作表:**
| 生产订单号 | 产品型号 | 数量 |
|-----------|---------|------|
| PO-001 | YTHN-...| 2 |
| PO-003 | YTHN-...| 2 |
| PO-006 | YTHN-...| 2 |
**[现存量]工作表:**
第3行表头
| ... | 物料编码 | ... | 库存数量 |
| ... | COMP001 | ... | 5 |
### 处理逻辑
1. **初始化阶段:**
- `InitComponentProcessorWithInventory` 加载库存数据到 `g_InventoryDict`
- 创建空的 `g_AccumulatedDemandDict` 用于追踪累计需求
2. **订单处理阶段(按顺序):**
- PO-001: 累计需求 = 2×1 + 0 = 2库存5 >= 2 ✓ → 返回部件
- PO-003: 累计需求 = 2×1 + 2 = 4库存5 >= 4 ✓ → 返回部件
- PO-006: 累计需求 = 2×1 + 4 = 6库存5 < 6 ✗ → 返回子件(接头+弹性元件)
3. **错误记录:**
- 库存不足时记录错误Blocking Error
- 未找到库存数据时记录警告Non-blocking Warning
### 输出结果
**BOM提取结果**
| 生产订单号 | 原始产品型号 | 物料类型 | 物料名称 | 物料编码 | 物料数量 | 提取备注 |
|-----------|-------------|---------|---------|---------|---------|---------|
| PO-001 | YTHN-... | 部件 | 部件A | COMP001 | 1 | |
| PO-003 | YTHN-... | 部件 | 部件A | COMP001 | 1 | |
| PO-006 | YTHN-... | 接头 | 接头B | JOINT01 | 1 | 部件无库存,使用子件 |
| PO-006 | YTHN-... | 弹性元件| 元件C | ELEM01 | 1 | 部件无库存,使用子件 |
## 测试要点
### 功能测试
1. **正常库存场景:**
- 准备测试数据3个订单库存=5
- 验证前2个订单返回部件
- 验证第3个订单返回子件
2. **边界测试:**
- 库存=0所有订单应返回子件
- 库存充足(>=累计需求),所有订单返回部件
- 库存恰好等于累计需求,应返回部件
3. **异常测试:**
- 现存量工作表不存在 → 记录警告,所有订单返回子件
- 部件编码在现存量中不存在 → 记录警告,该订单返回子件
- 数量列为空或非数字 → 应有错误处理
### 数据验证
1. **累计需求计算:**
- 验证累计需求 = 订单数量 × BOM需求量 + 之前累计
- 验证每次处理后累计需求量正确更新
2. **错误报告:**
- 检查错误报告工作表是否生成
- 验证库存不足错误正确记录
- 验证警告正确记录
## 注意事项
### 关键假设
1. **[现存量]工作表结构:**
- 表头在第3行
- 数据从第4行开始
- B列 = 物料编码
- J列 = 库存数量
2. **[产品型号]工作表结构:**
- A列 = 生产订单号
- B列 = 产品型号
- C列 = 数量
3. **BOM库[部件]工作表:**
- 必须包含"编码"列(部件编码)
- 必须包含"数量"列BOM需求量
### 已知限制
1. **库存检查时机:**
- 库存在初始化时加载一次
- 处理过程中库存不更新(不考虑库存增加)
2. **错误处理:**
- 未找到库存数据时返回 False使用子件
- 不会中断整个流程,继续处理下一个订单
3. **数量列处理:**
- 当前代码假设数量列总是存在且为数字
- 如果数量列为空或非数字,可能导致运行时错误
## 后续改进建议
1. **增强错误处理:**
-`ReadInputModels` 中验证数量列是否存在
- 处理数量列为空或非数字的情况
2. **性能优化:**
- 如果库存数据很大,考虑只加载需要的部件编码
- 添加日志记录库存使用情况
3. **功能扩展:**
- 支持库存实时更新(如果需要)
- 支持按批次或其他维度分组计算需求
- 添加库存预留功能(预留库存给特定订单)
## 相关文档
- BOM提取系统架构`CLAUDE.md`
- 库存校验计划:原始计划文档
- 测试用例:需要单独创建
## 实施验证清单
- [x] M04_Config.bas 添加常量
- [x] M08_ComponentProcessor.bas 添加变量
- [x] M08_ComponentProcessor.bas 实现 LoadInventoryData
- [x] M08_ComponentProcessor.bas 重写 CheckComponentInventory
- [x] M08_ComponentProcessor.bas 添加 InitComponentProcessorWithInventory
- [x] M08_ComponentProcessor.bas 修改 ProcessComponentRecord 签名
- [x] M09_BOMExtractor.bas 修改 RunBOMExtraction初始化、提取数量
- [x] M09_BOMExtractor.bas 修改 ProcessSingleModel添加参数
- [x] M09_BOMExtractor.bas 修改 MatchAllMaterialTypesWithValidation添加参数
- [ ] 验证 ReadInputModels 读取3列需要确认
- [ ] 端到端测试
- [ ] 错误场景测试