From 8545177bd52115421f6bb9a36f4d5307fb556bce Mon Sep 17 00:00:00 2001 From: Misaka_Company Date: Tue, 3 Feb 2026 09:32:07 +0800 Subject: [PATCH] docs: add ComponentInventoryCheckModule flowchart documentation Add comprehensive flowchart documentation for the component inventory check module: - Business flowchart (for non-technical users) - Technical flowchart (for developers) - Detailed inventory allocation process - BOM parsing process - Data processing sequence diagram - Data structure documentation and execution examples Co-Authored-By: Claude Sonnet 4.5 --- docs/ComponentInventoryCheckModule流程图.md | 443 ++++++++++++++++++++ docs/执行计划-部件数量核对.md | 391 +++++++++++++++++ docs/执行计划-附加功能支持.md | 199 +++++++++ 3 files changed, 1033 insertions(+) create mode 100644 docs/ComponentInventoryCheckModule流程图.md create mode 100644 docs/执行计划-部件数量核对.md create mode 100644 docs/执行计划-附加功能支持.md diff --git a/docs/ComponentInventoryCheckModule流程图.md b/docs/ComponentInventoryCheckModule流程图.md new file mode 100644 index 0000000..414f882 --- /dev/null +++ b/docs/ComponentInventoryCheckModule流程图.md @@ -0,0 +1,443 @@ +# 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 new file mode 100644 index 0000000..9726a3d --- /dev/null +++ b/docs/执行计划-部件数量核对.md @@ -0,0 +1,391 @@ +# 执行计划:部件数量核对功能 + +## 一、需求概述 + +### 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 new file mode 100644 index 0000000..6ac4b72 --- /dev/null +++ b/docs/执行计划-附加功能支持.md @@ -0,0 +1,199 @@ +# 执行计划:添加附加功能(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+一位数字的格式 | +| 分隔符不一致 | 解析错误 | 统一将 `.` 替换为 `,` 处理 | +| 条件评估逻辑错误 | 匹配错误 | 充分测试各种边界情况 | + +--- + +**是否批准此执行计划?确认后我将开始代码实现。**