Files
AutoBOM/docs/BOM_Matching_Fix_Summary.md
Misaka_Company 78241f2b8d
Some checks failed
NTFY Notification / notify (push) Failing after 3s
fix: component worksheet rowCount false positive validation error
Fix critical bug in BOM matching validation: when [部件] worksheet matches 1 record
but returns 2 sub-components, system incorrectly reports "matched 2 records".

Root Cause:
- matchResult("rowCount") incorrectly used componentMaterials.count (material count)
- instead of bomMatchResult("rowCount") (worksheet row count)
- Caused 1-row match returning 2 sub-components to be misreported as "2 matches"

Solution:
1. M08_ComponentProcessor.ProcessComponentRecord: Add matchedRowNum parameter,
   receive matched row number from caller, avoid redundant internal matching

2. M09_BOMExtractor: Implement two-phase matching flow
   - Phase 1: Call MatchBOMRecord to get standard match result (with correct rowCount)
   - Phase 2: If match succeeds, call ProcessComponentRecord to process component logic
   - matchResult("rowCount") always uses standard match's rowCount (worksheet row count)

Fix Results:
- Scenario 1: [部件] matches 1 row, returns 1 component → rowCount=1 
- Scenario 2: [部件] matches 1 row, returns 2 sub-components → rowCount=1  (no false positive)
- Scenario 3: [部件] matches 0 rows → rowCount=0, correct error 
- Scenario 4: [部件] matches 2+ rows → rowCount=2, correct error 

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-12 15:54:50 +08:00

213 lines
7.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.
# BOM匹配验证逻辑修复总结
## 问题描述
### Bug表现
当[部件]工作表匹配到**1条记录**但返回**2个子件**(接头+弹性元件)时,系统错误地报告"[部件]工作表匹配到2条记录"。
### 具体场景
1. 某个型号在[部件]工作表匹配到 **1条记录**
2. 该记录的"部件"物料库存不足
3. M08_ComponentProcessor 返回 **2个子件**1个接头 + 1个弹性元件
4. 验证逻辑误报:`[部件]工作表匹配到2条记录`**这是误报!**
### 根本原因
**位置:** `M09_BOMExtractor.bas` 第428行修复前
**错误代码:**
```vba
' 当处理[部件]工作表时
matchResult("rowCount") = componentMaterials.count ' ❌ 错误:这是物料数量,不是匹配行数
```
**问题分析:**
- `rowCount` 应该表示**工作表匹配的行数**应该是1
- 但代码错误地使用了**返回的物料数量**变成2
- 当库存不足返回2个子件时`rowCount=2` 被错误理解为"匹配了2行"
## 解决方案
### 修改文件1: `M08_ComponentProcessor.bas`
#### 修改内容:函数签名变更
**修改前:**
```vba
Public Function ProcessComponentRecord( _
ByVal wsComponent As Worksheet, _
ByVal params As Object, _
ByVal logger As clsErrorLogger _
) As Collection
```
**修改后:**
```vba
Public Function ProcessComponentRecord( _
ByVal wsComponent As Worksheet, _
ByVal params As Object, _
ByVal logger As clsErrorLogger, _
ByVal matchedRowNum As Long _ ' ✅ 新增参数:匹配的行号
) As Collection
```
#### 修改原因
- 传递匹配行号,让 ProcessComponentRecord 知道要处理哪一行
- 避免内部重复调用 `MatchBOMRecord`(去除冗余匹配逻辑)
- 使用传入的行号而不是内部重新匹配
#### 内部逻辑变更
- **移除:** 内部的 `MatchBOMRecord` 调用
- **新增:** `matchedRowNum` 参数验证
- **修改:** 所有 `rowNum` 变量引用改为 `matchedRowNum`
- **修改:** 错误处理器使用传入的 `matchedRowNum`
### 修改文件2: `M09_BOMExtractor.bas`
#### 修改位置:`MatchAllMaterialTypesWithValidation` 函数 (约第417-448行)
**修改前逻辑:**
```vba
' "部件"工作表特殊处理
If sheetName = BOMLIB_SHEET_COMPONENT Then
Debug.Print " -> 使用部件处理逻辑"
Dim componentMaterials As Collection
Set componentMaterials = M08_ComponentProcessor.ProcessComponentRecord( _
ws, params, logger)
Debug.Print " -> 返回物料数: " & componentMaterials.count
matchResult("success") = (componentMaterials.count > 0)
matchResult("rowCount") = componentMaterials.count ' ❌ 错误:物料数量
' 添加物料...
End If
```
**修改后逻辑:**
```vba
' "部件"工作表特殊处理
If sheetName = BOMLIB_SHEET_COMPONENT Then
Debug.Print " -> 使用部件处理逻辑"
' 步骤1: 先调用标准匹配获取匹配行数(这是工作表匹配的行数,不是物料数量)
Dim bomMatchResult As Object
Set bomMatchResult = M07_BOMMatcher.MatchBOMRecord(ws, params)
Debug.Print " -> 标准匹配: success=" & bomMatchResult("success") & ", rowCount=" & bomMatchResult("rowCount")
' 步骤2: 如果标准匹配成功,调用部件处理器
Dim componentMaterials As Collection
Set componentMaterials = New Collection
If bomMatchResult("success") Then
Set componentMaterials = M08_ComponentProcessor.ProcessComponentRecord( _
ws, params, logger, bomMatchResult("rowNums")(1))
Debug.Print " -> 返回物料数: " & componentMaterials.count
End If
' 步骤3: 创建匹配结果对象使用标准匹配的rowCount工作表行数不是物料数
matchResult("success") = bomMatchResult("success")
matchResult("rowCount") = bomMatchResult("rowCount") ' ✅ 修复使用标准匹配的rowCount
Set matchResult("rowNums") = bomMatchResult("rowNums")
' 步骤4: 添加物料到匹配结果
Dim compMat As Variant
For Each compMat In componentMaterials
Debug.Print " [" & compMat("materialType") & "] 名称=[" & compMat("materialName") & "] 编码=[" & compMat("materialCode") & "]"
matchResult("materials").Add compMat
Next compMat
End If
```
### 关键变化
1. **两阶段匹配流程:**
- **Phase 1:** 调用 `MatchBOMRecord` 获取标准匹配结果(包含正确的 `rowCount`
- **Phase 2:** 如果匹配成功,调用 `ProcessComponentRecord` 处理部件逻辑
2. **rowCount 修复:**
- `matchResult("rowCount")` 使用标准匹配的 `rowCount`(始终是工作表行数)
- 不再使用 `componentMaterials.count`(这是物料数量)
3. **参数传递:**
- 将匹配的行号 `bomMatchResult("rowNums")(1)` 传递给 `ProcessComponentRecord`
- 避免了部件处理器内部的重复匹配
## 预期效果对比
### 修复前
```
场景:[部件]匹配1行库存不足返回2个子件
结果rowCount = 2 (物料数量)
验证:❌ "[部件]工作表匹配到2条记录" (误报)
```
### 修复后
```
场景:[部件]匹配1行库存不足返回2个子件
结果rowCount = 1 (工作表行数) ✅
验证:✅ 正确识别为1行匹配返回2个物料
```
## 验证清单
### 场景1部件工作表返回1个部件
- [ ] 匹配1行 → rowCount=1 ✅
- [ ] 返回1个部件物料 → materials.count=1
- [ ] 验证通过 ✅
### 场景2部件工作表返回2个子件核心修复场景
- [ ] 匹配1行 → rowCount=1 ✅ (不再误报为2)
- [ ] 返回2个子件接头+弹性元件)→ materials.count=2
- [ ] 验证通过 ✅ (不再报错"匹配到2条记录")
### 场景3部件工作表匹配0条
- [ ] 匹配0行 → rowCount=0
- [ ] 返回0个物料 → materials.count=0
- [ ] 正确报错:"[部件]工作表未匹配到记录" ✅
### 场景4部件工作表匹配2条
- [ ] 匹配2行 → rowCount=2
- [ ] 正确报错:"[部件]工作表匹配到2条记录" ✅
### 场景5其他工作表的多条匹配
- [ ] [接头]工作表匹配2条 → 正确报错 ✅
- [ ] [弹性元件]工作表匹配2条 → 正确报错 ✅
- [ ] 验证逻辑不受影响 ✅
## 技术要点
### rowCount 的语义
- **定义:** `rowCount` 表示**工作表中匹配的行数**
- **不是:** 返回的物料数量
- **关键区别:** 1行匹配可能返回0个、1个或多个物料
### 两阶段匹配模式
```
阶段1: 标准匹配 → MatchBOMRecord
├─ 返回: success, rowCount, rowNums
└─ rowCount = 工作表行数 (始终正确)
阶段2: 部件处理 → ProcessComponentRecord(matchedRowNum)
├─ 输入: matchedRowNum (从阶段1获取)
├─ 返回: Collection of materials
└─ materials.count = 物料数量 (可能≠rowCount)
```
### 避免重复匹配
- **旧模式:** `M09``M08.ProcessComponentRecord``M07.MatchBOMRecord`
- **新模式:** `M09``M07.MatchBOMRecord``M08.ProcessComponentRecord(rowNum)`
- **优势:** 减少冗余匹配调用,代码更清晰
## 相关文档
- `docs/BOM匹配错误判断机制详解.md` - 完整的验证规则说明
- `docs/M09_BOMExtractor_Flow.md` - BOM提取流程图
- `docs/M08_ComponentProcessor_Design.md` - 部件处理器设计文档
## 修改历史
- **2025-02-12:** 初始版本 - 修复部件工作表rowCount误报问题