diff --git a/VBA_BOMConverter/Modules/M04_Config.bas b/VBA_BOMConverter/Modules/M04_Config.bas index b84f01b..aab3d10 100644 --- a/VBA_BOMConverter/Modules/M04_Config.bas +++ b/VBA_BOMConverter/Modules/M04_Config.bas @@ -22,6 +22,12 @@ Public Const BOMLIB_FILENAME As String = "BOM库.xlsx" Public Const BOMLIB_START_ROW As Long = 2 ' BOM库数据起始行(第1行是表头) Public Const OUTPUT_SHEET_NAME As String = "BOM提取结果" +' BIP上传工作表配置 +Public Const BIP_UPLOAD_SHEET_NAME As String = "BIP上传" +Public Const BIP_ROW_NUMBER_BASE As Long = 7000 +Public Const BIP_SUPPLY_MODE As String = "一般发料" +Public Const BIP_ISSUE_ORG As String = "重庆布莱迪仪器仪表有限公司" + ' 输入列名称配置 Public Const INPUT_COL_MODEL As String = "型号" Public Const INPUT_COL_PRODUCT_MODEL As String = "产品型号" diff --git a/VBA_BOMConverter/Modules/M09_BOMExtractor.bas b/VBA_BOMConverter/Modules/M09_BOMExtractor.bas index c7a2c8e..7a2556d 100644 --- a/VBA_BOMConverter/Modules/M09_BOMExtractor.bas +++ b/VBA_BOMConverter/Modules/M09_BOMExtractor.bas @@ -117,6 +117,10 @@ Public Function RunBOMExtraction() As String Dim allResults As Collection Set allResults = New Collection + ' 产品编码映射(用于BIP上传工作表生成) + Dim productCodeMap As Object + Set productCodeMap = CreateObject("Scripting.Dictionary") + Dim i As Long Dim totalModels As Long totalModels = UBound(inputModels, 1) @@ -134,10 +138,17 @@ Public Function RunBOMExtraction() As String Dim productionOrderNo As String Dim modelString As String Dim orderQty As Long + Dim productCode As String productionOrderNo = CStr(inputModels(i, 1)) ' Column A: 生产订单号 modelString = CStr(inputModels(i, 2)) ' Column B: 产品型号 orderQty = CLng(inputModels(i, 3)) ' Column C: 数量 + productCode = CStr(inputModels(i, 4)) ' Column D: 产品编码 + + ' 存储产品编码映射(用于BIP上传) + If Not productCodeMap.Exists(productionOrderNo) Then + productCodeMap.Add productionOrderNo, productCode + End If Dim modelResults As Collection Set modelResults = ProcessSingleModel(modelString, g_BOMWorkbook, g_Logger, productionOrderNo, orderQty) @@ -155,6 +166,17 @@ Public Function RunBOMExtraction() As String Dim wsOutput As Worksheet Set wsOutput = WriteExtractionResults(allResults) + ' 步骤5.5: 生成BIP上传工作表 + Application.StatusBar = "正在生成BIP上传数据..." + + Dim wsBIPUpload As Worksheet + Set wsBIPUpload = WriteBIPUploadResults(allResults, inputModels, productCodeMap) + + If wsBIPUpload Is Nothing Then + RunBOMExtraction = "错误:无法生成BIP上传工作表。" + GoTo ExitHandler + End If + ' 步骤6: 生成错误报告 If g_Logger.HasIssues Then g_Logger.PrintReport ActiveWorkbook @@ -301,9 +323,9 @@ Private Function ReadInputModels(ByVal ws As Worksheet) As Variant Exit Function End If - ' 读取数据到数组(返回3列:生产订单号、产品型号、数量) - ' 假设:A列(1)=生产订单号, B列(2)=产品型号, C列(3)=数量 - ReadInputModels = ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, 3)).Value + ' 读取数据到数组(返回4列:生产订单号、产品型号、数量、产品编码) + ' 假设:A列(1)=生产订单号, B列(2)=产品型号, C列(3)=数量, D列(4)=产品编码 + ReadInputModels = ws.Range(ws.Cells(2, 1), ws.Cells(lastRow, 4)).Value Exit Function ErrorHandler: @@ -1140,6 +1162,208 @@ ErrorHandler: Set WriteExtractionResults = Nothing End Function +' ------------------------------------------------------------------------------ +' 写入BIP上传数据到工作表 +' +' 输入: +' results - 提取结果集合(来自BOM提取结果) +' inputModels - 输入数据数组(包含订单号、型号、数量、产品编码) +' productCodeMap - 产品编码映射字典(订单号 -> 产品编码) +' +' 输出: +' Worksheet - BIP上传工作表 +' +' 逻辑: +' 1. 创建或清空"BIP上传"工作表 +' 2. 写入表头(9列) +' 3. 构建输出数据: +' - 检测订单号变化(重置物料行号计数器) +' - 生成行号:7000 + 物料流水号(1, 2, 3...) +' - 查找产品编码和订单数量 +' - 提取物料编码和数量 +' - 填充固定值字段 +' 4. 批量写入数据 +' 5. 格式化工作表(边框、列宽、数字格式) +' +' 输出格式(9列): +' 1: 来源单据号(生产订单号) +' 2: 产品编码 +' 3: 生产数量(订单数量×物料数量) +' 4: 行号(7000 + 流水号) +' 5: 材料编码 +' 6: 供应方式(固定值:"一般发料") +' 7: 需用日期(当前日期,格式:yyyy/m/d) +' 8: 发料组织(固定值:"重庆布莱迪仪器仪表有限公司") +' 9: 计划出库数量(与生产数量相同) +' ------------------------------------------------------------------------------ +Private Function WriteBIPUploadResults( _ + ByVal results As Collection, _ + ByVal inputModels As Variant, _ + ByVal productCodeMap As Object _ +) As Worksheet + On Error GoTo ErrorHandler + + Dim ws As Worksheet + + ' 创建或获取工作表 + On Error Resume Next + Set ws = ThisWorkbook.Sheets(BIP_UPLOAD_SHEET_NAME) + On Error GoTo ErrorHandler + + If ws Is Nothing Then + Set ws = ThisWorkbook.Worksheets.Add(After:=ActiveWorkbook.Sheets(ActiveWorkbook.Sheets.count)) + ws.Name = BIP_UPLOAD_SHEET_NAME + Else + ws.Cells.Clear + End If + + ' 写入表头(9列) + Dim headers As Variant + headers = Array("来源单据号(生产订单号)", "产品编码", "生产数量", "行号", "材料编码", _ + "供应方式", "需用日期", "发料组织", "计划出库数量") + + Dim c As Long + For c = 1 To 9 + ws.Cells(1, c).Value = headers(c - 1) + Next c + + ' 格式化表头 + With ws.Range("A1:I1") + .Font.Bold = True + .Interior.Color = RGB(217, 217, 217) + .HorizontalAlignment = xlCenter + End With + + ' 写入数据 + If results.count > 0 Then + ' 先设置材料编码列(第5列,E列)为文本格式 + ws.Range("E2:E" & (results.count + 1)).NumberFormat = "@" + + ' 准备输出数组 + Dim outputArr() As Variant + ReDim outputArr(1 To results.count, 1 To 9) + + ' 行号生成变量 + Dim currentOrderNo As String + Dim materialSeqNum As Long + materialSeqNum = 0 + currentOrderNo = "" + + Dim i As Long + Dim result As Variant + + For i = 1 To results.count + result = results(i) + + ' 提取订单号(注意:result(1)在非第一行时为空,需要从第2列获取原始型号来判断) + Dim resultOrderNo As String + Dim resultModel As String + resultOrderNo = CStr(result(1)) ' 第1列:生产订单号(仅第一条记录有值) + resultModel = CStr(result(2)) ' 第2列:原始产品型号 + + ' 检测新订单,重置计数器 + ' 如果resultOrderNo不为空,说明是新订单的第一条记录 + If Len(Trim(resultOrderNo)) > 0 And resultOrderNo <> currentOrderNo Then + currentOrderNo = resultOrderNo + materialSeqNum = 0 + End If + + ' 行号计数器递增 + materialSeqNum = materialSeqNum + 1 + + ' 生成行号:7000 + 流水号 + Dim bipRowNum As Long + bipRowNum = BIP_ROW_NUMBER_BASE + materialSeqNum + + ' 查找产品编码(使用currentOrderNo) + Dim currentProductCode As String + If productCodeMap.Exists(currentOrderNo) Then + currentProductCode = CStr(productCodeMap(currentOrderNo)) + Else + currentProductCode = "" + End If + + ' 【新增】查找订单数量(使用currentOrderNo) + Dim currentOrderQty As Long + currentOrderQty = 1 ' 默认值 + + ' 遍历inputModels查找订单数量 + Dim j As Long + For j = LBound(inputModels, 1) To UBound(inputModels, 1) + If CStr(inputModels(j, 1)) = currentOrderNo Then + currentOrderQty = CLng(inputModels(j, 3)) ' 第3列是订单数量 + Exit For + End If + Next j + + ' 提取物料编码和BOM库基础数量 + Dim materialCode As String + Dim bomQty As Long + Dim finalQty As Long + Dim isErrorRow As Boolean + + materialCode = CStr(result(11)) ' 第11列:物料编码 + + ' 检查是否为错误行(物料编码为空) + isErrorRow = (Len(Trim(materialCode)) = 0) + + ' 第12列:BOM库基础数量(需要乘以订单数量) + If Not isErrorRow Then + bomQty = CLng(result(12)) + Else + bomQty = 0 + End If + + ' 【新增】计算最终数量 = 订单数量 × BOM数量 + finalQty = bomQty * currentOrderQty + + ' 填充输出数组(使用currentOrderNo确保每一行都有订单号) + outputArr(i, 1) = currentOrderNo ' 来源单据号(生产订单号) + outputArr(i, 2) = currentProductCode ' 产品编码 + outputArr(i, 3) = finalQty ' 生产数量 = 订单数量 × BOM数量 + outputArr(i, 4) = bipRowNum ' 行号 + outputArr(i, 5) = materialCode ' 材料编码 + outputArr(i, 6) = BIP_SUPPLY_MODE ' 供应方式 + outputArr(i, 7) = Format(Date, "yyyy/m/d") ' 需用日期 + outputArr(i, 8) = BIP_ISSUE_ORG ' 发料组织 + outputArr(i, 9) = finalQty ' 计划出库数量 = 订单数量 × BOM数量 + Next i + + ' 批量写入数据 + ws.Range("A2").Resize(results.count, 9).Value = outputArr + + ' 格式化数据区域 + With ws.Range("A2:I" & (results.count + 1)) + .Borders.LineStyle = xlContinuous + .Borders.Weight = xlThin + End With + + ' 设置列宽 + ws.Columns("A").ColumnWidth = 15 ' 来源单据号 + ws.Columns("B").ColumnWidth = 15 ' 产品编码 + ws.Columns("C").ColumnWidth = 10 ' 生产数量 + ws.Columns("D").ColumnWidth = 8 ' 行号 + ws.Columns("E").ColumnWidth = 15 ' 材料编码 + ws.Columns("F").ColumnWidth = 12 ' 供应方式 + ws.Columns("G").ColumnWidth = 12 ' 需用日期 + ws.Columns("H").ColumnWidth = 25 ' 发料组织 + ws.Columns("I").ColumnWidth = 12 ' 计划出库数量 + + ' 冻结首行 + ws.Activate + ActiveWindow.FreezePanes = False + ws.Rows(2).Select + ActiveWindow.FreezePanes = True + ws.Cells(1, 1).Select + End If + + Set WriteBIPUploadResults = ws + Exit Function + +ErrorHandler: + Set WriteBIPUploadResults = Nothing +End Function + ' ------------------------------------------------------------------------------ ' 打开BOM库文件 '