diff --git a/.gitignore b/.gitignore
index c0df636..3797fd4 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,5 @@ tmpclaude-*
*workspace*
*.png
data/
-*.xlsm
\ No newline at end of file
+*.xlsm
+*.xlsx
\ No newline at end of file
diff --git a/docs/BIPUploadModule流程图.md b/docs/BIPUploadModule流程图.md
deleted file mode 100644
index eb80938..0000000
--- a/docs/BIPUploadModule流程图.md
+++ /dev/null
@@ -1,226 +0,0 @@
-# BIPUploadModule 流程图文档
-
-## 模块概述
-
-**模块名**: BIPUploadModule
-**功能**: 处理产品订单数据,提取BOM后生成[BIP上传模板]格式数据
-**主入口**: ProcessOrdersToBIP
-
-## ProcessOrdersToBIP 流程图(简化版)
-
-```mermaid
-flowchart TD
- Start([开始处理]) --> Init["初始化
1. 获取工作表
2. 加载BOM库"]
-
- Init --> Loop["循环处理每个订单"]
-
- Loop --> Read["读取订单信息
- 生产订单号
- 产品型号
- 数量
- 产品编码
- 部件优先标志"]
-
- Read --> Parse["解析产品型号
提取规格参数"]
-
- Parse --> Extract["提取BOM物料
根据规格参数匹配物料库"]
-
- Extract --> CheckPriority{"部件优先=否?"}
- CheckPriority -->|是| SkipComponent["排除'部件'类别
只提取子类别物料"]
- CheckPriority -->|否| KeepAll["保留所有物料"]
- SkipComponent --> Generate
- KeepAll --> Generate["生成BIP上传数据
- 订单信息
- 物料清单
- 行号编码"]
-
- Generate --> Collect["收集到内存集合"]
-
- Collect --> NextOrder{"还有订单?"}
- NextOrder -->|是| Loop
- NextOrder -->|否| BatchWrite["批量写入[BIP上传模板]"]
-
- BatchWrite --> Format["格式化表格"]
-
- Format --> End([完成])
-
- style Init fill:#e1f5e1
- style Parse fill:#fff3cd
- style Extract fill:#d1ecf1
- style Generate fill:#d1ecf1
- style BatchWrite fill:#f8d7da
- style End fill:#e1f5e1
-```
-
----
-
-## ProcessSingleOrder 子流程(详细版)
-
-> 注:以下为技术人员提供详细流程图
-
-```mermaid
-flowchart TD
- Start([开始 ProcessSingleOrder]) --> ClearExclude["清空排除类别
ClearExcludeCategories"]
-
- ClearExclude --> CheckPriority{"部件优先?"}
- CheckPriority -->|否/0/FALSE| AddExclude["创建排除类别集合
添加: 部件"]
- AddExclude --> SetExclude["设置排除类别"]
- SetExclude --> ParseModel
- CheckPriority -->|是| ParseModel["解析产品型号
ProductModelParser.Parse"]
-
- ParseModel --> CheckParse{"解析成功?"}
- CheckParse -->|否| CreateError1["创建错误行数据
备注: 解析失败信息"]
- CreateError1 --> AddError1["添加到outputData"] --> End1([返回])
-
- CheckParse -->|是| ExtractBOM["提取BOM
BomExtractor.ExtractBom"]
- ExtractBOM --> GetErrors["获取错误信息摘要"]
-
- GetErrors --> CheckMatch{"匹配到物料?"}
- CheckMatch -->|否| SetError1["设置备注: 未匹配到任何物料"]
- SetError1 --> CreateError2["创建空记录行数据"]
- CreateError2 --> AddError2["添加到outputData"] --> End2([返回])
-
- CheckMatch -->|是| InitLine["初始化行号索引 lineIndex = 1"]
- InitLine --> StartLoop["开始循环物料"]
-
- StartLoop --> GetItem["获取物料项"]
- GetItem --> InitNote["初始化备注 = 提取错误"]
-
- InitNote --> CheckItemError{"物料有错误?"}
- CheckItemError -->|是| AppendError["追加物料错误信息"]
- CheckItemError -->|否| CreateRow
- AppendError --> CreateRow["创建BIP行数据
CreateBIPRowArray"]
-
- CreateRow --> AddRow["添加到outputData"]
- AddRow --> IncLine["lineIndex++"]
- IncLine --> NextLoop{"还有物料?"}
- NextLoop -->|是| StartLoop
- NextLoop -->|否| End3([返回])
-```
-
-## WriteBatchData 批量写入流程
-
-```mermaid
-flowchart TD
- Start([开始 WriteBatchData]) --> CheckData{"outputData为空?"}
- CheckData -->|是| End1([直接返回])
- CheckData -->|否| GetRowCount["获取行数 rowCount"]
-
- GetRowCount --> CreateArray["创建二维数组
resultData1 to rowCount, 1 to 10"]
-
- CreateArray --> StartLoop["开始循环: i = 1 to rowCount"]
- StartLoop --> GetRowArray["获取行数组 rowArray = outputDatai"]
-
- GetRowArray --> FillArray["填充二维数组
resultDatai, 1 to 10 = rowArray1 to 10"]
- FillArray --> NextLoop{"i++ 还有数据?"}
- NextLoop -->|是| StartLoop
- NextLoop -->|否| WriteSheet["一次性写入工作表
A2单元格.Resize rowCount, 10"]
-
- WriteSheet --> End([完成])
-```
-
-## 数据结构说明
-
-### BIP上传模板字段 (10列)
-
-| 列号 | 字段名 | 说明 | 数据来源 |
-|------|--------|------|----------|
-| 1 | 来源单据号(生产订单号) | 订单唯一标识 | [产品订单] A列 |
-| 2 | 产品编码 | 产品代码 | [产品订单] D列 |
-| 3 | 生产数量 | 生产数量 | [产品订单] C列 |
-| 4 | 行号 | BOM行号 = 7000 + 索引 | 自动生成(7001, 7002...) |
-| 5 | 材料编码 | 物料66编码 | BOM提取结果 |
-| 6 | 供应方式 | 固定值 | "一般发料" |
-| 7 | 需用日期 | 日期 | 当天日期 Date |
-| 8 | 发料组织 | 固定值 | "重庆布莱迪仪器仪表有限公司" |
-| 9 | 计划出库数量 | 数量 | 与生产数量一致 |
-| 10 | 备注 | 异常信息 | BOM提取错误/异常 |
-
-### [产品订单] 工作表结构 (5列)
-
-| 列号 | 字段名 | 说明 | 必填 |
-|------|--------|------|------|
-| A | 生产订单号 | 订单唯一标识 | 是 |
-| B | 产品型号 | 产品完整型号 | 是 |
-| C | 数量 | 生产数量 | 是 |
-| D | 产品编码 | 产品代码 | 否 |
-| E | 部件优先 | 是否优先提取部件类别 | 否 |
-
-## 关键特性
-
-### 1. 性能优化
-- **批量写入**: 使用数组一次性写入所有数据,而非逐个单元格写入
-- **内存缓存**: 所有数据先收集到Collection对象,最后统一输出
-- **预期性能提升**: 10-100倍(取决于数据量)
-
-### 2. 部件优先功能
-- 当`部件优先` = "否"/"0"/"FALSE"时:
- - 排除"部件"类别的物料
- - 只提取"部件"的子类别物料(如"接头"、"弹性元件"等)
-- 当`部件优先` = "是"或其他值时:
- - 正常提取所有物料,包括"部件"类别及其子类别
-
-### 3. 错误处理
-- **必填字段验证**: 生产订单号、产品型号、数量
-- **解析失败处理**: 记录错误信息到备注列
-- **BOM提取异常**: 记录匹配失败和异常信息
-- **空行处理**: 自动跳过完全空白的行
-
-### 4. 数据完整性
-- 每次运行前清空旧数据(保留表头)
-- 自动创建[BIP上传模板]工作表(如不存在)
-- 行号自动生成(7001, 7002, 7003...)
-- 日期自动填充为当天日期
-
-## 执行示例
-
-### 正常流程示例
-
-```
-输入: [产品订单] 3行数据
- - 订单001, 型号MD-100, 数量10, 编码P001, 部件优先=是
- - 订单002, 型号MD-200, 数量20, 编码P002, 部件优先=否
- - 订单003, 型号MD-300, 数量30, 编码P003, 部件优先=是
-
-处理流程:
- 1. 读取3行订单数据
- 2. 逐个解析产品型号
- 3. 根据部件优先设置提取BOM
- 4. 订单001: 提取5种物料(包括部件)
- 5. 订单002: 提取4种物料(排除部件,只提取子类别)
- 6. 订单003: 提取6种物料(包括部件)
- 7. 批量写入15行数据到[BIP上传模板]
- 8. 显示完成信息: 处理3个订单,生成15行BOM数据
-
-输出: [BIP上传模板] 15行数据
-```
-
-### 异常处理示例
-
-```
-输入: [产品订单] 包含异常数据
- - 订单A01, 型号INVALID, 数量5 ← 型号解析失败
- - 订单A02, 型号MD-100, 数量0 ← 未匹配到任何物料
- - 订单A03, 型号MD-200, 数量10 ← 正常提取3种物料
-
-输出:
- 第1行: 订单A01, ..., 备注: "解析失败: 无效的型号格式"
- 第2行: 订单A02, ..., 备注: "未匹配到任何物料"
- 第3-5行: 订单A03, 3种物料数据
-```
-
-## 相关模块
-
-### 依赖的类模块
-- **BomExtractor**: BOM提取器,负责从平台配置清单中提取匹配的物料
-- **ProductModelParser**: 产品型号解析器,解析型号字符串为结构化条件
-- **BomItem**: BOM物料项数据模型
-- **ConditionEvaluator**: 条件评估器,评估选择条件和类别条件
-
-### 相关模块
-- **MainModule**: 主控模块,处理产品型号提取和BOM匹配
- - 类似的处理逻辑
- - 输出到[BOM提取结果]工作表
- - 支持部件优先功能
- - 使用相同的批量写入优化
-
-## 版本历史
-
-| 版本 | 日期 | 说明 |
-|------|------|------|
-| 1.0 | 2026-02-01 | 初始版本,实现基本的订单处理和BOM提取功能 |
-| 1.1 | 2026-02-01 | 添加部件优先功能,支持排除特定类别 |
-| 1.2 | 2026-02-01 | 性能优化,使用数组批量写入替代逐个单元格写入 |
-| 1.3 | 2026-02-01 | 修复Mermaid流程图方括号转义问题 |
diff --git a/docs/ComponentInventoryCheckModule流程图.md b/docs/ComponentInventoryCheckModule流程图.md
deleted file mode 100644
index 414f882..0000000
--- a/docs/ComponentInventoryCheckModule流程图.md
+++ /dev/null
@@ -1,443 +0,0 @@
-# ComponentInventoryCheckModule 流程图文档
-
-## 模块概述
-
-**模块名**: ComponentInventoryCheckModule
-**功能**: 部件库存核对模块 - 自动核对产品订单中"部件"类物料的库存情况
-**主入口**: CheckComponentInventory
-**说明**: 当库存不足时,按订单顺序将超出部分的订单的"部件优先"字段标记为"否"
-
----
-
-## 业务流程图(面向非技术人员)
-
-```mermaid
-flowchart TD
- Start([开始核对部件库存]) --> Step1["1. 读取数据
读取产品订单表
读取库存表
读取物料配置表"]
-
- Step1 --> Step2["2. 分析订单
查看每个订单需要哪些部件
计算每个订单需要多少个部件"]
-
- Step2 --> Step3["3. 汇总需求
统计所有订单总共需要多少个部件
按部件种类分别统计"]
-
- Step3 --> Step4["4. 检查库存
对比库存数量和需求数量
找出库存不够的部件"]
-
- Step4 --> Step5["5. 分配库存
按订单从上到下依次分配
库存够的订单→保持不变
库存不够的订单→标记为'否'"]
-
- Step5 --> Step6["6. 完成处理
显示处理结果
多少订单能发货
多少订单缺部件"]
-
- Step6 --> End([完成])
-
- style Step1 fill:#e1f5e1
- style Step2 fill:#d1ecf1
- style Step3 fill:#fff3cd
- style Step4 fill:#ffe5b4
- style Step5 fill:#f8d7da
- style Step6 fill:#e1f5e1
-```
-
-### 业务流程说明
-
-| 步骤 | 做什么 | 为什么 |
-|------|--------|--------|
-| **1. 读取数据** | 从Excel表格中读取订单、库存、配置信息 | 获取处理所需的所有数据 |
-| **2. 分析订单** | 查看每个订单需要什么部件、多少个 | 了解每个订单的部件需求 |
-| **3. 汇总需求** | 把所有订单的相同部件需求加在一起 | 算出总共需要多少部件 |
-| **4. 检查库存** | 对比总需求和实际库存 | 判断库存是否够用 |
-| **5. 分配库存** | 先来先得,库存不够的标记为"否" | 确定哪些订单能按时发货 |
-| **6. 完成处理** | 显示统计结果 | 让用户了解处理情况 |
-
-### 举例说明
-
-假设有3个订单,都需要同一个部件A:
-
-| 订单 | 需要部件A数量 | 库存分配过程 | 最终状态 |
-|------|--------------|--------------|---------|
-| 订单1 | 2个 | 库存剩5个,够用 | ✓ 保持原值 |
-| 订单2 | 2个 | 库存剩3个,够用 | ✓ 保持原值 |
-| 订单3 | 2个 | 库存剩1个,不够 | ✗ 标记为"否" |
-
-> **技术说明**:标记为"否"的订单,在生成BIP上传数据时会跳过部件类物料,优先保证子部件供应。
-
----
-
-## CheckComponentInventory 主流程图(技术版)
-
-> 以下流程图面向技术人员,展示完整的错误处理和验证步骤。
-
----
-
-## CheckComponentInventory 主流程图(详细版)
-
-```mermaid
-flowchart TD
- Start(["开始 CheckComponentInventory"]) --> GetSheet1["获取[产品订单]工作表"]
- GetSheet1 --> CheckSheet1{工作表存在?}
- CheckSheet1 -->|否| ShowMsg1["显示错误消息"] --> End1(["结束"])
- CheckSheet1 -->|是| GetSheet2["获取[现存量]工作表"]
-
- GetSheet2 --> CheckSheet2{工作表存在?}
- CheckSheet2 -->|否| ShowMsg2["显示错误消息"] --> End2(["结束"])
- CheckSheet2 -->|是| GetSheet3["获取[平台配置清单]工作表"]
-
- GetSheet3 --> CheckSheet3{工作表存在?}
- CheckSheet3 -->|否| ShowMsg3["显示错误消息"] --> End3(["结束"])
- CheckSheet3 -->|是| CheckData{订单数据存在?}
-
- CheckData -->|否| ShowMsg4["显示无数据消息"] --> End4(["结束"])
- CheckData -->|是| InitBOM["初始化BOM提取器
LoadBomData"]
-
- InitBOM --> CheckBOM{BOM加载成功?}
- CheckBOM -->|否| ShowMsg5["显示BOM错误"] --> End5(["结束"])
- CheckBOM -->|是| LoadInv["LoadInventoryData
读取库存数据到字典"]
-
- LoadInv --> CheckInv{库存数据有效?}
- CheckInv -->|否| ShowMsg6["显示无库存消息"] --> End6(["结束"])
- CheckInv -->|是| LoadOrders["LoadOrderData
读取订单数据"]
-
- LoadOrders --> CheckOrders{订单数据有效?}
- CheckOrders -->|否| ShowMsg7["显示无订单消息"] --> End7(["结束"])
- CheckOrders -->|是| ParseAll["ParseAllOrdersBOM
解析所有订单的BOM"]
-
- ParseAll --> CalcDemand["CalculateComponentDemand
统计部件总需求"]
-
- CalcDemand --> CheckDemand{有部件需求?}
- CheckDemand -->|否| ShowMsg8["显示无部件消息"] --> End8(["结束"])
- CheckDemand -->|是| Validate["ValidateInventory
验证库存数据"]
-
- Validate --> Allocate["AllocateInventory
按订单顺序分配库存"]
-
- Allocate --> ShowResult["显示结果统计
总订单数、包含部件订单数
库存充足/不足订单数"]
-
- ShowResult --> End9(["完成"])
-
- style InitBOM fill:#e1f5e1
- style LoadInv fill:#d1ecf1
- style LoadOrders fill:#d1ecf1
- style ParseAll fill:#fff3cd
- style CalcDemand fill:#fff3cd
- style Validate fill:#ffe5b4
- style Allocate fill:#f8d7da
- style End9 fill:#e1f5e1
-```
-
----
-
-## AllocateInventory 库存分配详细流程
-
-```mermaid
-flowchart TD
- AllocStart([开始 AllocateInventory]) --> InitStats[初始化统计信息
TotalOrders, OrdersWithComponent
OrdersSufficient, OrdersInsufficient, OrdersSkipped]
-
- InitStats --> LoopStart{遍历订单
i = 1 to orders.Count}
-
- LoopStart -->|有订单| GetOrder[获取订单 order = orders i]
- GetOrder --> CheckParse{解析失败?}
- CheckParse -->|ORDER_PARSE_ERR <> ""| Skip1[跳过订单
OrdersSkipped++]
- CheckParse -->|无错误| CheckHasComp{包含部件?}
-
- CheckHasComp -->|ORDER_HAS_COMP = False| Skip2[跳过订单
OrdersSkipped++]
- CheckHasComp -->|HasComponent = True| CheckQty{数量为0?}
-
- CheckQty -->|ORDER_QUANTITY = 0| Skip3[跳过订单
OrdersSkipped++]
- CheckQty -->|数量 > 0| UpdateComp[OrdersWithComponent++]
-
- UpdateComp --> GetComp[获取部件库存信息
compInv = componentDemands compCode]
- GetComp --> CalcReq[计算需求量
requiredQty = CompQty × OrderQty]
-
- CalcReq --> CheckStock{库存充足?
compInv.STOCK >= requiredQty}
-
- CheckStock -->|是| DeductSufficient[扣减库存
compInv.STOCK -= requiredQty
OrdersSufficient++]
- CheckStock -->|否| MarkNo[标记E列为"否"
orderSheet.Cells Row, 5 = "否"
compInv.STOCK -= requiredQty
OrdersInsufficient++]
-
- DeductSufficient --> NextOrder[继续下一个订单]
- MarkNo --> NextOrder
- Skip1 --> NextOrder
- Skip2 --> NextOrder
- Skip3 --> NextOrder
-
- NextOrder --> LoopStart
-
- style UpdateComp fill:#e1f5e1
- style DeductSufficient fill:#e1f5e1
- style MarkNo fill:#f8d7da
-```
-
----
-
-## ParseOrderBOM 解析详细流程
-
-```mermaid
-flowchart TD
- ParseStart([开始 ParseOrderBOM]) --> CreateParser[创建ProductModelParser]
- CreateParser --> ParseModel[解析型号
parser.Parse model]
-
- ParseModel --> CheckParse{解析成功?}
- CheckParse -->|否| SetError[设置解析错误
ORDER_PARSE_ERR = "解析失败: ..."]
- SetError --> ParseEnd([结束返回])
-
- CheckParse -->|是| ExtractBOM[提取BOM
bomExtractor.ExtractBom conditions]
-
- ExtractBOM --> LoopComp{遍历BOM项目
For Each item In matchedItems}
-
- LoopComp -->|有项目| CheckCat{item.category = "部件"?}
-
- CheckCat -->|否| NextItem[继续下一个项目]
- CheckCat -->|是| SetCompInfo[设置部件信息
ORDER_COMP_CODE = item.Code66
ORDER_COMP_QTY = item.quantity
ORDER_HAS_COMP = True]
-
- SetCompInfo --> ParseEnd
- NextItem --> LoopComp
-
- style SetCompInfo fill:#d1ecf1
- style SetError fill:#f8d7da
-```
-
----
-
-## 数据处理序列图
-
-```mermaid
-sequenceDiagram
- participant Main as CheckComponentInventory
- participant Loader as 数据加载器
- participant Parser as BOM解析器
- participant Calc as 需求计算器
- participant Validator as 库存验证器
- participant Allocator as 库存分配器
-
- Main->>Loader: LoadInventoryData(ws)
- Loader-->>Main: 库存字典 Dictionary(编码 -> 数量)
-
- Main->>Loader: LoadOrderData(ws)
- Loader-->>Main: 订单集合 Collection(Of Dictionary)
-
- loop 每个订单
- Main->>Parser: ParseOrderBOM(order, bomExtractor)
- Parser->>Parser: ProductModelParser.Parse(model)
- Parser->>Parser: BomExtractor.ExtractBom(conditions)
- Parser->>Parser: 查找 category="部件" 的物料
- Parser-->>Main: 设置订单部件信息
- end
-
- Main->>Calc: CalculateComponentDemand(orders)
- Calc->>Calc: 累加每个订单的部件需求
- Note over Calc: 需求 = CompQty × OrderQty
- Calc-->>Main: 部件需求字典 Dictionary(编码 -> 库存信息)
-
- Main->>Validator: ValidateInventory(demands, inventoryData)
- Validator->>Validator: 检查每个部件是否存在
- Validator->>Validator: 计算是否短缺
- Validator-->>Main: 警告集合 Collection
-
- Main->>Allocator: AllocateInventory(orders, demands, sheet)
- loop 按订单顺序遍历
- Allocator->>Allocator: 获取订单部件需求
- Allocator->>Allocator: 检查库存是否充足
- alt 库存充足
- Allocator->>Allocator: 扣减库存,保持原值
- Note over Allocator: OrdersSufficient++
- else 库存不足
- Allocator->>Allocator: 标记 E5 = "否"
- Note over Allocator: OrdersInsufficient++
- end
- end
- Allocator-->>Main: 统计信息 Statistics
-
- Main-->>Main: 显示结果消息框
-```
-
----
-
-## 数据结构说明
-
-### 订单字典结构 (Dictionary Object)
-
-| 键名 | 常量 | 类型 | 说明 |
-|------|------|------|------|
-| RowNumber | ORDER_ROW | Long | 订单所在行号 |
-| ProductModel | ORDER_MODEL | String | 产品型号 |
-| Quantity | ORDER_QUANTITY | Double | 产品数量 |
-| ComponentCode | ORDER_COMP_CODE | String | 部件66编码 |
-| ComponentQty | ORDER_COMP_QTY | Double | 部件BOM数量 |
-| HasComponent | ORDER_HAS_COMP | Boolean | 是否包含部件 |
-| ParseError | ORDER_PARSE_ERR | String | 解析错误信息 |
-
-### 部件库存字典结构 (Dictionary Object)
-
-| 键名 | 常量 | 类型 | 说明 |
-|------|------|------|------|
-| ComponentCode | INV_CODE | String | 部件66编码 |
-| TotalDemand | INV_DEMAND | Double | 总需求量 |
-| AvailableStock | INV_STOCK | Double | 可用库存(动态扣减) |
-| IsShortage | INV_SHORTAGE | Boolean | 是否短缺 |
-
-### 统计信息结构 (Statistics Type)
-
-| 字段 | 类型 | 说明 |
-|------|------|------|
-| TotalOrders | Long | 总订单数 |
-| OrdersWithComponent | Long | 包含部件的订单数 |
-| OrdersSufficient | Long | 库存充足订单数 |
-| OrdersInsufficient | Long | 库存不足订单数 |
-| OrdersSkipped | Long | 跳过订单数 |
-
----
-
-## 关键特性
-
-### 1. 库存分配策略
-- **按订单顺序分配**: 从上到下遍历订单,先到先得
-- **动态库存扣减**: 库存充足时扣减,不足时标记为负数
-- **只标记不跳过**: 即使库存不足也继续处理后续订单
-
-### 2. 部件识别机制
-- 通过 `BomExtractor` 提取完整BOM
-- 遍历BOM项目,查找 `category = "部件"` 的物料
-- 只记录第一个匹配到的部件(假设每个产品只有一个主部件)
-
-### 3. 错误处理
-- **工作表缺失**: 提前验证,友好提示
-- **BOM加载失败**: 显示错误摘要,终止处理
-- **型号解析失败**: 记录错误,跳过该订单
-- **部件找不到库存**: 添加警告,继续处理(库存设为0)
-
-### 4. 数据完整性
-- 使用 `Dictionary` 实现库存的引用更新
-- 使用 `Collection` 保持订单顺序
-- 统计跳过的订单(解析失败、无部件、数量为0)
-
----
-
-## 执行示例
-
-### 正常流程示例
-
-```
-输入数据:
- [产品订单]
- 第2行: MD-100, 数量2, 部件A(编码661001, 用量1)
- 第3行: MD-200, 数量2, 部件A(编码661001, 用量1)
- 第4行: MD-300, 数量2, 部件A(编码661001, 用量1)
-
- [现存量]
- 661001: 5
-
-处理流程:
- 1. 读取3个订单
- 2. 解析BOM,识别部件661001
- 3. 统计需求: 1×2 + 1×2 + 1×2 = 6
- 4. 验证库存: 6 > 5,短缺
- 5. 分配库存:
- - 订单2: 需求2,库存5→3,充足
- - 订单3: 需求2,库存3→1,充足
- - 订单4: 需求2,库存1→-1,不足,标记E4="否"
-
-输出结果:
- [产品订单]
- 第2行: E列保持原值
- 第3行: E列保持原值
- 第4行: E列 = "否"
-
- 统计信息:
- 处理订单数: 3
- 包含部件订单: 3
- 库存充足订单: 2
- 库存不足订单: 1
-```
-
-### 异常处理示例
-
-```
-输入数据:
- [产品订单]
- 第2行: INVALID-MODEL, 数量5 ← 型号解析失败
- 第3行: MD-100, 数量0 ← 数量为0
- 第4行: MD-200, 数量2, 部件669999 (库存中不存在)
-
- [现存量]
- 661001: 10
-
-输出结果:
- 第2行: 跳过(解析失败)
- 第3行: 跳过(数量为0)
- 第4行: 标记E4="否",但添加警告 "部件 '669999' 在[现存量]中未找到"
-
- 统计信息:
- 处理订单数: 3
- 包含部件订单: 1
- 库存充足订单: 0
- 库存不足订单: 1
- 跳过订单数: 2
-
- 警告信息:
- 部件 '669999' 在[现存量]中未找到
-```
-
----
-
-## 工作表结构要求
-
-### [产品订单] 工作表
-
-| 列号 | 字段名 | 说明 | 必填 |
-|------|--------|------|------|
-| A | 生产订单号 | 订单唯一标识 | 否 |
-| B | 产品型号 | 产品完整型号 | 是 |
-| C | 数量 | 生产数量 | 是 |
-| D | 产品编码 | 产品代码 | 否 |
-| E | 部件优先 | 是否优先提取部件类别(输出字段) | - |
-
-- **表头**: 第1行
-- **数据起始**: 第2行
-- **输出位置**: E列(第5列)
-
-### [现存量] 工作表
-
-| 列号 | 字段名 | 说明 |
-|------|--------|------|
-| B | 物料编码 | 对应BOM中的66代码 |
-| J | 结存主数量 | 库存数量 |
-
-- **表头**: 第3行
-- **数据起始**: 第4行
-
-### [平台配置清单] 工作表
-
-标准的BOM配置清单,用于提取物料信息。
-
----
-
-## 相关模块
-
-### 依赖的类模块
-- **BomExtractor**: BOM提取器,负责从平台配置清单中提取匹配的物料
-- **ProductModelParser**: 产品型号解析器,解析型号字符串为结构化条件
-- **BomItem**: BOM物料项数据模型
-
-### 相关模块
-- **BIPUploadModule**: 生成BIP上传模板
- - 读取"部件优先"字段
- - 当值为"否"时排除"部件"类别物料
- - 与本模块功能互补
-
----
-
-## 算法复杂度
-
-| 操作 | 时间复杂度 | 说明 |
-|------|-----------|------|
-| LoadInventoryData | O(n) | n = 库存行数 |
-| LoadOrderData | O(m) | m = 订单行数 |
-| ParseAllOrdersBOM | O(m × p) | p = 平均BOM物料数 |
-| CalculateComponentDemand | O(m) | 遍历订单统计需求 |
-| ValidateInventory | O(k) | k = 不同部件数 |
-| AllocateInventory | O(m) | 遍历订单分配库存 |
-
-**总体复杂度**: O(m × p),主要由BOM解析决定
-
----
-
-## 版本历史
-
-| 版本 | 日期 | 说明 |
-|------|------|------|
-| 1.0 | 2026-02-03 | 初始版本,实现部件库存核对功能 |
diff --git a/docs/执行计划-部件数量核对.md b/docs/执行计划-部件数量核对.md
deleted file mode 100644
index 9726a3d..0000000
--- a/docs/执行计划-部件数量核对.md
+++ /dev/null
@@ -1,391 +0,0 @@
-# 执行计划:部件数量核对功能
-
-## 一、需求概述
-
-### 1.1 功能描述
-自动核对产品订单中"部件"类物料的库存情况,当库存不足时,按订单顺序将超出部分的订单的"部件优先"字段标记为"否"。
-
-### 1.2 数据源
-
-#### [产品订单]工作表
-- **表头位置**:第1行
-- **数据起始行**:第2行
-- **关键列**:
- - B列:产品型号
- - C列:产品数量
- - E列:部件优先(输出字段)
-
-#### [现存量]工作表
-- **表头位置**:第3行
-- **数据起始行**:第4行
-- **关键列**:
- - B列:物料编码(对应BOM中的66代码)
- - J列:结存主数量(库存数量)
-
----
-
-## 二、业务逻辑
-
-### 2.1 核心流程
-
-```
-1. 读取所有订单 → 2. 解析型号提取BOM → 3. 识别部件物料
-↓
-4. 统计部件总需求 → 5. 查询库存 → 6. 库存充足性检查
-↓
-7. 按订单顺序分配库存 → 8. 修改部件优先字段
-```
-
-### 2.2 计算规则
-
-#### 部件总需求量
-```
-部件总需求 = Σ(订单i的BOM中部件数量 × 订单i的产品数量)
-```
-
-#### 示例
-```
-订单1:产品数量=2,部件A的BOM数量=1 → 需求 = 1 × 2 = 2
-订单2:产品数量=2,部件A的BOM数量=1 → 需求 = 1 × 2 = 2
-订单3:产品数量=2,部件A的BOM数量=1 → 需求 = 1 × 2 = 2
---------------------------------------------------------
-部件A总需求 = 2 + 2 + 2 = 6
-部件A库存 = 5
-库存不足 = 6 - 5 = 1
-```
-
-### 2.3 分配策略
-
-**原则**:按订单自上而下的顺序分配库存
-
-| 订单 | 需求量 | 分配前库存 | 分配后库存 | 部件优先 |
-|------|--------|-----------|-----------|---------|
-| 订单1 | 2 | 5 | 3 | 保持不变 |
-| 订单2 | 2 | 3 | 1 | 保持不变 |
-| 订单3 | 2 | 1 | -1(不足) | **改为"否"** |
-
----
-
-## 三、处理规则
-
-### 3.1 正常情况
-- 订单包含"部件"物料,库存充足 → 保持原值
-- 订单包含"部件"物料,库存不足 → 改为"否"
-- 订单不包含"部件"物料 → **保持原值不变**
-
-### 3.2 异常情况
-- **部件在[现存量]中找不到** → 报错提示,终止处理
-- **型号解析失败** → 跳过该订单,记录错误
-- **未匹配到任何物料** → 跳过该订单(无部件)
-
-### 3.3 字段修改规则
-- **基于现有值进行修改**(不清空原有值)
-- **只修改E列"部件优先"字段**
-- 修改格式:`是`、`否`、`1`、`0`、`TRUE`、`FALSE` 均可识别
-
----
-
-## 四、数据结构设计
-
-### 4.1 订单数据结构
-```vba
-Type OrderInfo
- RowNumber As Long ' 行号
- ProductModel As String ' 产品型号
- Quantity As Long ' 产品数量
- ComponentCode As String ' 部件66编码
- ComponentQty As Double ' 部件BOM数量
- HasComponent As Boolean ' 是否包含部件
- ParseError As String ' 解析错误信息
-End Type
-```
-
-### 4.2 部件库存结构
-```vba
-Type ComponentInventory
- ComponentCode As String ' 部件66编码
- TotalDemand As Double ' 总需求量
- AvailableStock As Double ' 可用库存
- IsShortage As Boolean ' 是否短缺
-End Type
-```
-
----
-
-## 五、实现方案
-
-### 5.1 新建模块
-
-**文件名**:`ComponentInventoryCheckModule.bas`
-
-**主要过程**:
-```vba
-Public Sub CheckComponentInventory()
- ' 主入口程序
-End Sub
-```
-
-### 5.2 核心函数
-
-#### 5.2.1 读取订单数据
-```vba
-Private Function LoadOrderData(ws As Worksheet) As Collection
- ' 返回 Collection(Of OrderInfo)
- ' 读取[产品订单]的B、C列数据
-End Function
-```
-
-#### 5.2.2 读取库存数据
-```vba
-Private Function LoadInventoryData(ws As Worksheet) As Object
- ' 返回 Dictionary(物料编码 -> 库存数量)
- ' 读取[现存量]的B、J列数据
-End Function
-```
-
-#### 5.2.3 解析订单BOM
-```vba
-Private Sub ParseOrderBOM(orderInfo As OrderInfo, _
- bomExtractor As BomExtractor, _
- parser As ProductModelParser)
- ' 解析型号,提取BOM
- ' 识别"部件"类别物料
- ' 填充 orderInfo.ComponentCode 和 orderInfo.ComponentQty
-End Sub
-```
-
-#### 5.2.4 统计部件需求
-```vba
-Private Function CalculateComponentDemand( _
- orders As Collection) As Object
- ' 返回 Dictionary(部件编码 -> ComponentInventory)
- ' 累加所有订单的部件需求量
-End Function
-```
-
-#### 5.2.5 检查库存充足性
-```vba
-Private Sub ValidateInventory( _
- componentDemands As Object, _
- inventoryData As Object)
- ' 检查每个部件的库存是否充足
- ' 如果找不到或不足,报错提示
-End Sub
-```
-
-#### 5.2.6 分配库存并标记
-```vba
-Private Sub AllocateInventory( _
- orders As Collection, _
- componentDemands As Object, _
- orderSheet As Worksheet)
- ' 按订单顺序分配库存
- ' 库存不足时,修改E列"部件优先"为"否"
-End Sub
-```
-
----
-
-## 六、详细实现步骤
-
-### 6.1 主流程(CheckComponentInventory)
-
-```
-1. 获取工作表对象
- ├─ [产品订单]工作表
- ├─ [现存量]工作表
- └─ [平台配置清单]工作表
-
-2. 初始化BOM提取器
- └─ 加载BOM数据
-
-3. 读取库存数据到字典
- └─ Dictionary(66编码 -> 库存数量)
-
-4. 读取订单数据
- └─ Collection(Of OrderInfo)
-
-5. 解析所有订单的BOM
- └─ 识别部件,填充ComponentCode和ComponentQty
-
-6. 统计部件总需求
- └─ Dictionary(部件编码 -> ComponentInventory)
-
-7. 验证库存
- └─ 检查部件是否存在于[现存量]中
-
-8. 按订单顺序分配库存
- └─ 修改E列"部件优先"字段
-
-9. 输出结果统计
- └─ MsgBox显示处理结果
-```
-
-### 6.2 分配算法(伪代码)
-
-```vba
-For Each order In orders
- If order.HasComponent Then
- Dim demand As ComponentInventory
- demand = componentDemands(order.ComponentCode)
-
- Dim requiredQty As Double
- requiredQty = order.ComponentQty * order.Quantity
-
- If demand.AvailableStock >= requiredQty Then
- ' 库存充足,保持原值
- demand.AvailableStock = demand.AvailableStock - requiredQty
- Else
- ' 库存不足,标记为"否"
- orderSheet.Cells(order.RowNumber, 5).Value = "否"
- demand.AvailableStock = demand.AvailableStock - requiredQty
- End If
- End If
-Next order
-```
-
----
-
-## 七、边界情况处理
-
-### 7.1 无部件的订单
-```
-条件:订单的BOM中没有"类别=部件"的物料
-处理:跳过该订单,E列保持原值
-```
-
-### 7.2 多个订单使用不同部件
-```
-订单1:部件A
-订单2:部件B
-处理:分别统计A和B的需求,独立核算库存
-```
-
-### 7.3 库存为0的情况
-```
-条件:[现存量]中某部件的结存主数量 = 0
-处理:所有需要该部件的订单都标记为"否"
-```
-
-### 7.4 产品数量为0的情况
-```
-条件:订单的C列产品数量 = 0
-处理:该订单的部件需求 = 0,不影响库存
-```
-
-### 7.5 部件优先字段原有值
-```
-可能的值:"是"、"否"、1、0、TRUE、FALSE、空
-处理:基于现有值修改,不清空
-```
-
----
-
-## 八、测试用例
-
-### 8.1 基本功能测试
-
-| 测试场景 | 订单数 | 部件 | 总需求 | 库存 | 预期结果 |
-|---------|--------|------|--------|------|---------|
-| 库存充足 | 3 | A(1) | 6 | 10 | 全部保持原值 |
-| 库存不足 | 3 | A(1) | 6 | 5 | 第3个订单改为"否" |
-| 库存刚好 | 3 | A(1) | 6 | 6 | 全部保持原值 |
-| 无部件订单 | 2 | - | - | - | 保持原值 |
-| 库存为0 | 2 | A(1) | 4 | 0 | 全部改为"否" |
-
-### 8.2 异常情况测试
-
-| 测试场景 | 预期行为 |
-|---------|---------|
-| 部件在[现存量]中不存在 | 报错提示,终止处理 |
-| 型号解析失败 | 跳过该订单,记录错误 |
-| [产品订单]为空 | 提示无数据,退出 |
-| [现存量]为空 | 报错提示,退出 |
-
-### 8.3 边界值测试
-
-| 测试场景 | 输入值 | 预期结果 |
-|---------|--------|---------|
-| 产品数量为1 | 所有订单数量=1 | 正常计算 |
-| 产品数量为大数 | 订单数量=1000 | 正常计算 |
-| 部件BOM数量为小数 | 0.5 | 正确计算总需求 |
-| 库存数量为小数 | 2.5 | 正确判断库存 |
-
----
-
-## 九、用户界面设计
-
-### 9.1 执行入口
-
-建议在主界面添加按钮:
-```
-[部件库存核对]
-```
-
-### 9.2 结果提示
-
-执行完成后显示:
-```
-✓ 部件库存核对完成!
-
-处理订单数:10
-包含部件订单:8
-库存充足订单:6
-库存不足订单:2
-
-耗时:0.50秒
-```
-
-### 9.3 错误提示
-
-格式:
-```
-✗ 部件库存核对失败!
-
-错误信息:
-- 订单第5行:部件 '661234' 在[现存量]中未找到
-
-请检查数据后重试。
-```
-
----
-
-## 十、实施步骤
-
-1. **创建新模块**
- - 文件名:`ComponentInventoryCheckModule.bas`
- - 位置:`VBA/Modules/`
-
-2. **实现核心函数**
- - LoadOrderData
- - LoadInventoryData
- - ParseOrderBOM
- - CalculateComponentDemand
- - ValidateInventory
- - AllocateInventory
-
-3. **实现主流程**
- - CheckComponentInventory
-
-4. **测试验证**
- - 基本功能测试
- - 异常情况测试
- - 边界值测试
-
-5. **集成到主界面**
- - 添加按钮或菜单项
-
----
-
-## 十一、风险评估
-
-| 风险 | 影响 | 缓解措施 |
-|------|------|---------|
-| 库存数据不准确 | 导致错误的分配结果 | 执行前提示用户确认库存数据 |
-| 订单量大导致性能问题 | 处理时间长 | 优化算法,使用批量操作 |
-| BOM解析失败 | 无法识别部件 | 记录错误日志,跳过该订单 |
-| 部件编码不一致 | 无法匹配库存 | 严格验证,报错提示 |
-
----
-
-**是否批准此执行计划?确认后我将开始代码实现。**
diff --git a/docs/执行计划-附加功能支持.md b/docs/执行计划-附加功能支持.md
deleted file mode 100644
index 6ac4b72..0000000
--- a/docs/执行计划-附加功能支持.md
+++ /dev/null
@@ -1,199 +0,0 @@
-# 执行计划:添加附加功能(fjgn)支持
-
-## 一、需求概述
-
-### 1.1 新增条件字段
-- **条件代码**:`fjgn`
-- **条件名称**:`附加功能`
-- **提取位置**:从型号表头的[仪表特性]字段中提取(第6个位置,索引5)
-
-### 1.2 型号结构
-```
-[型号]-[公称外径].[安装形式].[壳体形式].[过程连接&接液材质].[量程范围].[仪表特性]
-```
-
-### 1.3 仪表特性解析规则
-- **充油类型**:位于最后,格式为 `Y`+一位数字(如 Y3)
-- **附加功能**:在充油类型前面的内容
- - 分隔符可能是 `,` 或 `.`(如 `N2,N3` 或 `N2.N3`)
- - 可能为空(如仪表特性只有 `Y3`)
-
-### 1.4 示例
-| 型号 | 仪表特性 | 充油类型 | 附加功能 |
-|------|----------|----------|----------|
-| PYTHN-100.A0.541.M201.M06.N2,N3.Y3 | N2,N3.Y3 | Y3 | N2,N3 |
-| YTHN-100.A0.531.M201.M08.Y3 | Y3 | Y3 | (空) |
-
----
-
-## 二、条件评估规则
-
-### 2.1 fjgn 条件的特殊处理
-
-| 条件表达式 | 型号中的 fjgn | 评估结果 | 说明 |
-|-----------|--------------|---------|------|
-| fjgn=N1 | N1,N2 | ✅ True | 包含 N1 |
-| fjgn=N1 | N2,N3 | ❌ False | 不包含 N1 |
-| fjgn=N1 | (空) | ❌ False | 空值不包含任何值 |
-| fjgn!=N1 | N1,N2 | ❌ False | 包含 N1,不满足!= |
-| fjgn!=N1 | N2,N3 | ✅ True | 不包含 N1 |
-| fjgn!=N1 | (空) | ✅ True | 空值不包含 N1 |
-
-### 2.2 匹配逻辑
-- **等值匹配(fjgn=XX)**:fjgn 字符串中包含指定值即为真
-- **不等匹配(fjgn!=XX)**:fjgn 字符串中不包含指定值即为真
-- **空值处理**:空字符串不包含任何值
-
----
-
-## 三、代码修改方案
-
-### 3.1 ProductModelParser.cls
-
-**修改位置**:`ParseHeader()` 方法
-
-**新增内容**:
-```vba
-' 仪表特性 - 第6个位置(索引5),可能不存在
-If UBound(dotParts) >= 5 Then
- Dim instrumentFeature As String
- instrumentFeature = Trim(dotParts(5))
-
- ' 提取附加功能
- Dim fjgn As String
- fjgn = ExtractAdditionalFeatures(instrumentFeature)
-
- pConditions.Add "fjgn", fjgn
-Else
- ' 如果没有仪表特性字段,fjgn为空
- pConditions.Add "fjgn", ""
-End If
-```
-
-**新增方法**:`ExtractAdditionalFeatures()`
-```vba
-Private Function ExtractAdditionalFeatures(instrumentFeature As String) As String
- ' 1. 检查是否以Y+数字结尾(充油类型)
- Dim lastTwoChars As String
- If Len(instrumentFeature) >= 2 Then
- lastTwoChars = Right(instrumentFeature, 2)
- If UCase(Left(lastTwoChars, 1)) = "Y" And IsNumeric(Right(lastTwoChars, 1)) Then
- ' 去掉充油类型
- instrumentFeature = Left(instrumentFeature, Len(instrumentFeature) - 2)
- instrumentFeature = Trim(instrumentFeature)
- End If
- End If
-
- ' 2. 处理可能的分隔符(,或.)
- ' 将可能的.替换为,,统一处理
- instrumentFeature = Replace(instrumentFeature, ".", ",")
-
- ' 3. 去除可能的后缀分隔符
- If Right(instrumentFeature, 1) = "," Then
- instrumentFeature = Left(instrumentFeature, Len(instrumentFeature) - 1)
- End If
-
- ExtractAdditionalFeatures = Trim(instrumentFeature)
-End Function
-```
-
----
-
-### 3.2 BIPUploadModule.bas
-
-**修改位置**:第12行常量定义
-
-**修改内容**:
-```vba
-' 修改前
-Private Const CONDITION_CONFIG = "azxs,安装形式|bkxs,表壳形式|gclj,过程连接|jycz,接液材质|lcfw,量程范围"
-
-' 修改后
-Private Const CONDITION_CONFIG = "azxs,安装形式|bkxs,表壳形式|gclj,过程连接|jycz,接液材质|lcfw,量程范围|fjgn,附加功能"
-```
-
----
-
-### 3.3 ConditionEvaluator.cls
-
-**修改位置**:`EvaluateSingleCondition()` 方法
-
-**修改内容**:在现有的 `=` 和 `!=` 运算符处理后,添加 fjgn 特殊处理
-
-```vba
-' 在现有的 actualValue = Conditions(varName) 之后添加
-actualValue = Conditions(varName)
-
-' fjgn 字段特殊处理(多值匹配)
-If varName = "fjgn" Then
- If operator = "=" Then
- ' fjgn=N1:检查actualValue中是否包含value
- EvaluateSingleCondition = InStr(actualValue, value) > 0
- ElseIf operator = "!=" Then
- ' fjgn!=N1:检查actualValue中是否不包含value
- EvaluateSingleCondition = InStr(actualValue, value) = 0
- End If
- Exit Function
-End If
-
-' 其他字段使用原有逻辑
-EvaluateSingleCondition = (actualValue = value)
-```
-
----
-
-## 四、测试用例
-
-### 4.1 解析测试
-
-| 测试型号 | 预期 fjgn | 预期其他条件 |
-|---------|----------|-------------|
-| PYTHN-100.A0.541.M201.M06.N2,N3.Y3 | N2,N3 | azxs=A0, bkxs=541, gclj=M20, jycz=1, lcfw=M06 |
-| YTHN-100.A0.531.M201.M08.Y3 | (空) | azxs=A0, bkxs=531, gclj=M20, jycz=1, lcfw=M08 |
-| BP-088.2312.M08.0A3.N1.N2.Y2 | N1,N2 | azxs=23, bkxs=12, gclj=M08, jycz=0, lcfw=A3 |
-| BP-088.2312.M08.0A3.Y2 | (空) | azxs=23, bkxs=12, gclj=M08, jycz=0, lcfw=A3 |
-
-### 4.2 条件评估测试
-
-| fjgn值 | 选用条件 | 预期结果 |
-|-------|---------|---------|
-| N1,N2 | fjgn=N1 | True |
-| N1,N2 | fjgn=N3 | False |
-| (空) | fjgn=N1 | False |
-| N1,N2 | fjgn!=N1 | False |
-| N1,N2 | fjgn!=N3 | True |
-| (空) | fjgn!=N1 | True |
-
----
-
-## 五、实施步骤
-
-1. **修改 ProductModelParser.cls**
- - 在 `ParseHeader()` 方法中添加仪表特性提取逻辑
- - 新增 `ExtractAdditionalFeatures()` 方法
-
-2. **修改 BIPUploadModule.bas**
- - 更新 `CONDITION_CONFIG` 常量
-
-3. **修改 ConditionEvaluator.cls**
- - 在 `EvaluateSingleCondition()` 方法中添加 fjgn 特殊处理逻辑
-
-4. **测试验证**
- - 测试型号解析是否正确
- - 测试条件评估是否符合预期
- - 测试边界情况(空值、多个附加功能等)
-
----
-
-## 六、风险评估
-
-| 风险 | 影响 | 缓解措施 |
-|------|------|---------|
-| 旧型号缺少仪表特性字段 | 解析失败 | 判断字段是否存在,不存在时 fjgn 为空 |
-| 充油类型识别错误 | 提取错误 | 严格匹配 Y+一位数字的格式 |
-| 分隔符不一致 | 解析错误 | 统一将 `.` 替换为 `,` 处理 |
-| 条件评估逻辑错误 | 匹配错误 | 充分测试各种边界情况 |
-
----
-
-**是否批准此执行计划?确认后我将开始代码实现。**