feat: Add GetValidMaterialsByModel and completeness check

Implemented logic to retrieve materials based on a model string and verify if the resulting set is complete.

Added:
- `GetValidMaterialsByModel`: Parses the model, extracts conditions, and matches materials against root categories.
- `CheckCategoryCompleteness`: Recursively validates categories to ensure exactly one material match per required category (leaf or parent).

This enables the BOM Manager to return a collection of materials alongside a boolean flag indicating if the collection satisfies the structural completeness rules.
This commit is contained in:
Misaka_Company
2026-01-20 18:13:11 +08:00
parent f3fc5b4cbd
commit 112a89a2a4
2 changed files with 378 additions and 0 deletions

View File

@@ -681,4 +681,230 @@ Public Function ParseModelAndExtractConditions(modelStr As String) As Object
End If
Set ParseModelAndExtractConditions = conditions
End Function
' ========================================
' GetValidMaterialsByModel 方法
' 功能: 根据产品型号获取物料,并判断是否为完整的物料集合
' 参数:
' modelStr - 产品型号字符串
' 返回: Collection对象
' Collection中包含两个元素:
' (1) "Materials" - Collection, clsMaterialItem
' (2) "IsComplete" - Boolean,
'
' 完整性判断规则:
' - 对于每个需要领料的类别(顶层类别或其需要领取的子类别)
' - 必须有且仅有一个物料被匹配
' - 如果某个类别有0个或多于1个物料,则视为不完整
'
' 示例:
' Dim result As Collection
' Set result = bomMgr.GetValidMaterialsByModel("YTHN-100.A0.532.M203.M16.Y3")
' Dim materials As Collection
' Dim isComplete As Boolean
' Set materials = result("Materials")
' isComplete = result("IsComplete")
' ========================================
Public Function GetValidMaterialsByModel(modelStr As String) As collection
Dim result As New collection
Dim allMaterials As New collection
Dim isComplete As Boolean
'
Dim parser As New clsModelParser
If Not parser.ParseModel(modelStr) Then
Debug.Print "型号解析失败: " & parser.ErrorMessage
isComplete = False
result.Add allMaterials, "Materials"
result.Add isComplete, "IsComplete"
Set GetValidMaterialsByModel = result
Exit Function
End If
Dim extractor As New clsConditionExtractor
Dim conditions As Object
Set conditions = extractor.ExtractConditions(parser)
'
Debug.Print "【GetValidMaterialsByModel】"
Debug.Print "型号: " & modelStr
Debug.Print "提取的条件:"
Dim key As Variant
For Each key In conditions.Keys
Debug.Print " " & key & " = " & conditions(key)
Next key
Debug.Print ""
' 条件匹配器
Dim matcher As New clsConditionMatcher
' ,
isComplete = True
Dim categoryCheckResults As Object
Set categoryCheckResults = CreateObject("Scripting.Dictionary")
Dim rootCat As clsCategory
Dim i As Long
For i = 1 To rootCategories.count
Set rootCat = rootCategories(i)
' 检查该类别及其子类别的完整性
Dim catResult As Object
Set catResult = CheckCategoryCompleteness(rootCat, matcher, conditions)
'
Dim mat As clsMaterialItem
Dim matCollection As collection
Set matCollection = catResult("Materials")
For Each mat In matCollection
allMaterials.Add mat
Next mat
'
If Not catResult("IsComplete") Then
isComplete = False
Debug.Print "【不完整】类别 """ & rootCat.categoryName & """ 物料不完整"
End If
' ()
categoryCheckResults(rootCat.categoryName) = catResult("IsComplete")
Next i
'
Debug.Print ""
Debug.Print "【完整性检查结果】"
Debug.Print "总物料数: " & allMaterials.count
Debug.Print "是否完整: " & IIf(isComplete, "是", "否")
For Each key In categoryCheckResults.Keys
Debug.Print " " & key & ": " & IIf(categoryCheckResults(key), "完整", "不完整")
Next key
Debug.Print String(60, "=")
'
result.Add allMaterials, "Materials"
result.Add isComplete, "IsComplete"
Set GetValidMaterialsByModel = result
End Function
' ========================================
' CheckCategoryCompleteness 方法 (私有)
' 功能: 检查单个类别的完整性(递归处理子类别)
' 参数:
' cat - 类别对象
' matcher - 条件匹配器
' conditions - 提取的条件字典
' 返回: Dictionary对象
' "Materials" - Collection,
' "IsComplete" - Boolean,
'
' 完整性判断逻辑:
' 1. 如果类别没有子类别(叶子类别):
' - 必须有且仅有1个物料匹配 → 完整
' - 0个或多于1个物料 → 不完整
'
' 2. 如果类别有子类别:
' a) 先尝试在父类别查找物料
' b) 如果父类别有且仅有1个匹配物料 → 使用父类别,完整
' c) 如果父类别没有匹配物料 → 降级到所有子类别
' - 每个子类别都必须有且仅有1个匹配物料 → 完整
' - 任一子类别不满足 → 不完整
' ========================================
Private Function CheckCategoryCompleteness(cat As clsCategory, _
matcher As clsConditionMatcher, _
conditions As Object) As Object
Dim result As Object
Set result = CreateObject("Scripting.Dictionary")
Dim materials As New collection
Dim isComplete As Boolean
' 首先在当前类别查找匹配的物料
Dim mat As clsMaterialItem
Dim matchCount As Long
matchCount = 0
Dim i As Long
For i = 1 To cat.materials.count
Set mat = cat.materials(i)
If matcher.IsMatch(mat.Condition, conditions) Then
materials.Add mat
matchCount = matchCount + 1
End If
Next i
' 判断完整性
If Not cat.HasSubCategories Then
' ========================================
' 情况1: 叶子类别(无子类别)
' 必须有且仅有1个物料
' ========================================
If matchCount = 1 Then
isComplete = True
Debug.Print "【完整】叶子类别 """ & cat.categoryName & """ 有1个匹配物料"
Else
isComplete = False
If matchCount = 0 Then
Debug.Print "【不完整】叶子类别 """ & cat.categoryName & """ 无匹配物料"
Else
Debug.Print "【不完整】叶子类别 """ & cat.categoryName & """ 有" & matchCount & "个匹配物料(应为1个)"
End If
End If
Else
' ========================================
' 情况2: 有子类别
' 先检查父类别,如果父类别满足则使用父类别
' 否则降级到子类别,每个子类别都必须满足
' ========================================
If matchCount = 1 Then
' 1,使
isComplete = True
Debug.Print "【完整】父类别 """ & cat.categoryName & """ 有1个匹配物料,使用父类别"
ElseIf matchCount = 0 Then
' ,
Debug.Print "【降级】父类别 """ & cat.categoryName & """ 无匹配物料,检查子类别..."
' 清空物料集合,准备收集子类别物料
Set materials = New collection
isComplete = True ' 假设完整,如果任一子类别不完整则设为False
Dim subCat As clsCategory
Dim j As Long
For j = 1 To cat.SubCategories.count
Set subCat = cat.SubCategories(j)
' 递归检查子类别
Dim subResult As Object
Set subResult = CheckCategoryCompleteness(subCat, matcher, conditions)
'
Dim subMaterials As collection
Set subMaterials = subResult("Materials")
Dim k As Long
For k = 1 To subMaterials.count
materials.Add subMaterials(k)
Next k
'
If Not subResult("IsComplete") Then
isComplete = False
End If
Next j
If isComplete Then
Debug.Print "【完整】类别 """ & cat.categoryName & """ 所有子类别都完整"
Else
Debug.Print "【不完整】类别 """ & cat.categoryName & """ 存在不完整的子类别"
End If
Else
' ,
isComplete = False
Debug.Print "【不完整】父类别 """ & cat.categoryName & """ 有" & matchCount & "个匹配物料(应为0或1个)"
End If
End If
'
Set result("Materials") = materials
result("IsComplete") = isComplete
Set CheckCategoryCompleteness = result
End Function