Загрузка данных
## ConsumerPickerPresenter.bas
```vb
Attribute VB_Name = "ConsumerPickerPresenter"
Option Explicit
' Presenter logic for the consumer picker form.
' Keeps UserForm1 handlers thin and uses a separate prompt dialog for custom naming.
Private mSyncingSpecial As Boolean
Private mUserSpecialChoice As Boolean
Public Sub InitializeForm(ByVal frm As Object)
If frm Is Nothing Then Exit Sub
SelectionSession.CancelSelection
SelectionSession.SetSelectionLevelCode vbNullString
mUserSpecialChoice = SelectionSession.GetSelectionSpecial()
SyncSpecialControls frm, mUserSpecialChoice
frm.cmdDelete.Enabled = SelectionSession.CanDeleteSelectedRow()
frm.cmdBack.Visible = False
LoadLevel1 frm
UpdateOkButtonState frm
End Sub
Public Sub HandleSpecialToggle(ByVal frm As Object)
If frm Is Nothing Then Exit Sub
If mSyncingSpecial Then Exit Sub
mUserSpecialChoice = CBool(frm.chkSpecial.Value)
SyncSpecialControls frm, mUserSpecialChoice
End Sub
Public Sub HandleListSelectionChanged(ByVal frm As Object)
Dim rowNorms As Long
Dim targetSpecial As Boolean
If frm Is Nothing Then Exit Sub
rowNorms = GetSelectedNormRow(frm)
targetSpecial = mUserSpecialChoice
If rowNorms > 0 Then
If NormsCatalog.IsNormDefaultSpecial(rowNorms) Then
targetSpecial = True
End If
End If
SyncSpecialControls frm, targetSpecial
UpdateOkButtonState frm
End Sub
Public Sub HandleBack(ByVal frm As Object)
If frm Is Nothing Then Exit Sub
SelectionSession.SetSelectionLevelCode vbNullString
LoadLevel1 frm
UpdateOkButtonState frm
End Sub
Public Function HandleListDoubleClick(ByVal frm As Object) As Boolean
HandleListDoubleClick = FinalizeCurrentSelection(frm)
End Function
Public Function HandleOkClick(ByVal frm As Object) As Boolean
HandleOkClick = FinalizeCurrentSelection(frm)
End Function
Public Function HandleCustomClick(ByVal frm As Object) As Boolean
Dim customName As String
If frm Is Nothing Then Exit Function
If Not CustomConsumerPresenter.ShowCustomConsumerPrompt(customName) Then
SyncSpecialControls frm, SelectionSession.GetSelectionSpecial()
Exit Function
End If
SelectionSession.AcceptCustomSelection customName, SelectionSession.GetSelectionSpecial()
HandleCustomClick = True
End Function
Public Function HandleDeleteClick(ByVal frm As Object) As Boolean
If frm Is Nothing Then Exit Function
If Not SelectionSession.CanDeleteSelectedRow() Then Exit Function
SelectionSession.AcceptDeleteSelection CBool(frm.chkSpecial.value)
HandleDeleteClick = True
End Function
Public Sub HandleQueryClose(ByVal CloseMode As Integer)
If CloseMode = vbFormControlMenu Then
SelectionSession.CancelSelection
End If
End Sub
Private Function FinalizeCurrentSelection(ByVal frm As Object) As Boolean
Dim rowNorms As Long
Dim codeText As String
Dim customName As String
Dim promptResult As Long
If frm Is Nothing Then Exit Function
rowNorms = GetSelectedNormRow(frm)
If rowNorms <= 0 Then Exit Function
codeText = NormsCatalog.GetNormCode(rowNorms)
If Right$(codeText, 1) = "." And NormsCatalog.HasChildNorms(codeText) Then
SelectionSession.SetSelectionLevelCode codeText
LoadLevel2 frm, codeText
UpdateOkButtonState frm
Exit Function
End If
If NormsCatalog.IsNormDefaultSpecial(rowNorms) And (Not CBool(frm.chkSpecial.Value)) Then
SyncSpecialControls frm, False
ElseIf NormsCatalog.IsNormDefaultSpecial(rowNorms) Then
SyncSpecialControls frm, True
Else
SyncSpecialControls frm, mUserSpecialChoice
End If
promptResult = CustomNamePromptPresenter.ShowCustomNamePrompt()
If promptResult < 0 Then
SyncSpecialControls frm, SelectionSession.GetSelectionSpecial()
Exit Function
End If
If promptResult > 0 Then
customName = InputBox(PromptCustomNameText(), PromptCustomNameCaption())
If StrPtr(customName) = 0 Then Exit Function
End If
SelectionSession.AcceptNormSelection rowNorms, Trim$(customName), SelectionSession.GetSelectionSpecial()
FinalizeCurrentSelection = True
End Function
Private Sub LoadLevel1(ByVal frm As Object)
Dim count As Long
count = NormsCatalog.PopulateConsumerList(frm.ListBox1)
frm.cmdBack.Visible = False
frm.caption = Level1Caption(count)
ClearCurrentSelection frm
End Sub
Private Sub LoadLevel2(ByVal frm As Object, ByVal levelCode As String)
Dim count As Long
count = NormsCatalog.PopulateConsumerList(frm.ListBox1, levelCode)
frm.cmdBack.Visible = True
frm.caption = Level2Caption(levelCode, count)
ClearCurrentSelection frm
End Sub
Private Sub ClearCurrentSelection(ByVal frm As Object)
On Error Resume Next
frm.ListBox1.ListIndex = -1
On Error GoTo 0
End Sub
Private Sub UpdateOkButtonState(ByVal frm As Object)
SetControlEnabled frm, "cmdOK", (GetSelectedNormRow(frm) > 0)
End Sub
Private Function GetSelectedNormRow(ByVal frm As Object) As Long
On Error Resume Next
If frm.ListBox1.ListIndex < 0 Then Exit Function
GetSelectedNormRow = CLng(Val(CStr(frm.ListBox1.List(frm.ListBox1.ListIndex, 1))))
On Error GoTo 0
End Function
Private Sub SyncSpecialControls(ByVal frm As Object, ByVal newValue As Boolean)
mSyncingSpecial = True
SelectionSession.SetSelectionSpecial newValue
On Error Resume Next
frm.chkSpecial.value = newValue
frm.chkSpecial.ForeColor = IIf(newValue, vbRed, vbBlack)
frm.Label1.ForeColor = IIf(newValue, vbRed, vbBlack)
On Error GoTo 0
mSyncingSpecial = False
End Sub
Private Sub SetControlEnabled(ByVal frm As Object, ByVal controlName As String, ByVal isEnabled As Boolean)
On Error Resume Next
CallByName frm.Controls(controlName), "Enabled", VbLet, isEnabled
On Error GoTo 0
End Sub
Private Function Level1Caption(ByVal count As Long) As String
Level1Caption = PromptSelectConsumerText() & ". " & PromptLevel1Text() & " (" & PromptFoundText() & ": " & count & ")"
End Function
Private Function Level2Caption(ByVal levelCode As String, ByVal count As Long) As String
Level2Caption = PromptLevel2Text() & ": " & levelCode & " (" & PromptFoundText() & ": " & count & ")"
End Function
Private Function PromptSelectConsumerText() As String
PromptSelectConsumerText = ChrW$(1042) & ChrW$(1099) & ChrW$(1073) & ChrW$(1086) & ChrW$(1088) & " " & ChrW$(1087) & ChrW$(1086) & ChrW$(1090) & ChrW$(1088) & ChrW$(1077) & ChrW$(1073) & ChrW$(1080) & ChrW$(1090) & ChrW$(1077) & ChrW$(1083) & ChrW$(1103)
End Function
Private Function PromptLevel1Text() As String
PromptLevel1Text = ChrW$(1059) & ChrW$(1088) & ChrW$(1086) & ChrW$(1074) & ChrW$(1077) & ChrW$(1085) & ChrW$(1100) & " 1"
End Function
Private Function PromptLevel2Text() As String
PromptLevel2Text = ChrW$(1059) & ChrW$(1088) & ChrW$(1086) & ChrW$(1074) & ChrW$(1077) & ChrW$(1085) & ChrW$(1100) & " 2"
End Function
Private Function PromptFoundText() As String
PromptFoundText = ChrW$(1085) & ChrW$(1072) & ChrW$(1081) & ChrW$(1076) & ChrW$(1077) & ChrW$(1085) & ChrW$(1086)
End Function
Private Function PromptCustomNameText() As String
PromptCustomNameText = ChrW$(1042) & ChrW$(1074) & ChrW$(1077) & ChrW$(1076) & ChrW$(1080) & ChrW$(1090) & ChrW$(1077) & " " & ChrW$(1085) & ChrW$(1072) & ChrW$(1079) & ChrW$(1074) & ChrW$(1072) & ChrW$(1085) & ChrW$(1080) & ":"
End Function
Private Function PromptCustomNameCaption() As String
PromptCustomNameCaption = ChrW$(1050) & ChrW$(1072) & ChrW$(1089) & ChrW$(1090) & ChrW$(1086) & ChrW$(1084) & ChrW$(1085) & ChrW$(1086) & ChrW$(1077) & " " & ChrW$(1085) & ChrW$(1072) & ChrW$(1079) & ChrW$(1074) & ChrW$(1072) & ChrW$(1085) & ChrW$(1080) & ChrW$(1077)
End Function
Private Function PromptCustomConsumerText() As String
PromptCustomConsumerText = ChrW$(1042) & ChrW$(1074) & ChrW$(1077) & ChrW$(1076) & ChrW$(1080) & ChrW$(1090) & ChrW$(1077) & " " & ChrW$(1085) & ChrW$(1072) & ChrW$(1079) & ChrW$(1074) & ChrW$(1072) & ChrW$(1085) & ChrW$(1080) & ChrW$(1077) & " " & ChrW$(1087) & ChrW$(1086) & ChrW$(1090) & ChrW$(1088) & ChrW$(1077) & ChrW$(1073) & ChrW$(1080) & ChrW$(1090) & ChrW$(1077) & ChrW$(1083) & ChrW$(1103) & ":"
End Function
Private Function PromptCustomConsumerCaption() As String
PromptCustomConsumerCaption = ChrW$(1057) & ChrW$(1074) & ChrW$(1086) & ChrW$(1080) & " " & ChrW$(1076) & ChrW$(1072) & ChrW$(1085) & ChrW$(1085) & ChrW$(1099) & ChrW$(1077)
End Function
```
222222
## CustomConsumerPresenter.bas
```vb
Attribute VB_Name = "CustomConsumerPresenter"
Option Explicit
' Presenter for the dedicated fully custom consumer form.
' This path does not use the regular yes/no name prompt.
Private mSyncing As Boolean
Private mAccepted As Boolean
Private mCustomName As String
Private Const CUSTOM_NAME_LABEL_NAME As String = "lblDynamicCustomName"
Private Const CUSTOM_NAME_TEXTBOX_NAME As String = "txtDynamicCustomName"
Public Function ShowCustomConsumerPrompt(ByRef customName As String) As Boolean
Dim frm As Object
mAccepted = False
mCustomName = vbNullString
Set frm = New CustomConsumerForm
frm.Show vbModal
If Not mAccepted Then Exit Function
customName = mCustomName
ShowCustomConsumerPrompt = (Len(Trim$(customName)) > 0)
End Function
Public Sub InitializeForm(ByVal frm As Object)
If frm Is Nothing Then Exit Sub
ConfigureDynamicControls frm
On Error Resume Next
frm.caption = ChrW$(1057) & ChrW$(1074) & ChrW$(1086) & ChrW$(1080) & " " & ChrW$(1076) & ChrW$(1072) & ChrW$(1085) & ChrW$(1085) & ChrW$(1099) & ChrW$(1077)
frm.cmdYes.caption = ChrW$(1054) & ChrW$(1050)
frm.cmdNo.caption = ChrW$(1054) & ChrW$(1090) & ChrW$(1084) & ChrW$(1077) & ChrW$(1085) & ChrW$(1072)
frm.cmdYes.Default = True
frm.cmdNo.Cancel = True
frm.Controls(CUSTOM_NAME_TEXTBOX_NAME).Text = vbNullString
frm.Controls(CUSTOM_NAME_TEXTBOX_NAME).SetFocus
On Error GoTo 0
SyncSpecialControls frm, SelectionSession.GetSelectionSpecial()
End Sub
Public Sub HandleSpecialToggle(ByVal frm As Object)
If frm Is Nothing Then Exit Sub
If mSyncing Then Exit Sub
SyncSpecialControls frm, CBool(frm.chkSpecialMirror.value)
End Sub
Public Function HandleOkClick(ByVal frm As Object) As Boolean
If frm Is Nothing Then Exit Function
mCustomName = Trim$(ReadNameValue(frm))
If Len(mCustomName) = 0 Then Exit Function
SelectionSession.SetSelectionSpecial CBool(frm.chkSpecialMirror.value)
mAccepted = True
HandleOkClick = True
End Function
Public Function HandleCancelClick(ByVal frm As Object) As Boolean
mAccepted = False
HandleCancelClick = True
End Function
Public Function HandleQueryClose(ByVal frm As Object) As Boolean
mAccepted = False
HandleQueryClose = True
End Function
Private Sub SyncSpecialControls(ByVal frm As Object, ByVal newValue As Boolean)
mSyncing = True
SelectionSession.SetSelectionSpecial newValue
On Error Resume Next
frm.chkSpecialMirror.value = newValue
frm.chkSpecialMirror.ForeColor = IIf(newValue, vbRed, vbBlack)
frm.lblSpecialMirror.ForeColor = IIf(newValue, vbRed, vbBlack)
On Error GoTo 0
mSyncing = False
End Sub
Private Function ReadNameValue(ByVal frm As Object) As String
Dim ctrl As Object
On Error Resume Next
Set ctrl = frm.Controls(CUSTOM_NAME_TEXTBOX_NAME)
If Not ctrl Is Nothing Then
ReadNameValue = Trim$(CStr(ctrl.Value))
If Len(ReadNameValue) = 0 Then ReadNameValue = Trim$(CStr(ctrl.Text))
End If
On Error GoTo 0
End Function
Private Sub ConfigureDynamicControls(ByVal frm As Object)
Dim lbl As Object
Dim txt As Object
On Error Resume Next
frm.Controls.Remove CUSTOM_NAME_LABEL_NAME
frm.Controls.Remove CUSTOM_NAME_TEXTBOX_NAME
On Error GoTo 0
On Error Resume Next
Set lbl = frm.Controls.Add("Forms.Label.1", CUSTOM_NAME_LABEL_NAME, True)
With lbl
.caption = ChrW$(1042) & ChrW$(1074) & ChrW$(1077) & ChrW$(1076) & ChrW$(1080) & ChrW$(1090) & ChrW$(1077) & " " & ChrW$(1085) & ChrW$(1072) & ChrW$(1079) & ChrW$(1074) & ChrW$(1072) & ChrW$(1085) & ChrW$(1080) & ChrW$(1077) & " " & ChrW$(1087) & ChrW$(1086) & ChrW$(1090) & ChrW$(1088) & ChrW$(1077) & ChrW$(1073) & ChrW$(1080) & ChrW$(1090) & ChrW$(1077) & ChrW$(1083) & ChrW$(1103) & ":"
.Left = 300
.Top = 360
.Width = 5000
.Height = 240
.Font.Name = "Arial"
.Font.Size = 8
.ForeColor = vbBlack
.BackStyle = fmBackStyleTransparent
End With
Set txt = frm.Controls.Add("Forms.TextBox.1", CUSTOM_NAME_TEXTBOX_NAME, True)
With txt
.Left = 300
.Top = 630
.Width = 7600
.Height = 300
.Font.Name = "Arial"
.Font.Size = 8
.Text = vbNullString
End With
On Error GoTo 0
End Sub
```
33333
## CustomConsumerPresenter.bas
```vb
Attribute VB_Name = "CustomConsumerPresenter"
Option Explicit
' Presenter for the dedicated fully custom consumer form.
' This path does not use the regular yes/no name prompt.
Private mSyncing As Boolean
Private mAccepted As Boolean
Private mCustomName As String
Private Const CUSTOM_NAME_LABEL_NAME As String = "lblDynamicCustomName"
Private Const CUSTOM_NAME_TEXTBOX_NAME As String = "txtDynamicCustomName"
Public Function ShowCustomConsumerPrompt(ByRef customName As String) As Boolean
Dim frm As Object
mAccepted = False
mCustomName = vbNullString
Set frm = New CustomConsumerForm
frm.Show vbModal
If Not mAccepted Then Exit Function
customName = mCustomName
ShowCustomConsumerPrompt = (Len(Trim$(customName)) > 0)
End Function
Public Sub InitializeForm(ByVal frm As Object)
If frm Is Nothing Then Exit Sub
ConfigureDynamicControls frm
On Error Resume Next
frm.caption = ChrW$(1057) & ChrW$(1074) & ChrW$(1086) & ChrW$(1080) & " " & ChrW$(1076) & ChrW$(1072) & ChrW$(1085) & ChrW$(1085) & ChrW$(1099) & ChrW$(1077)
frm.cmdYes.caption = ChrW$(1054) & ChrW$(1050)
frm.cmdNo.caption = ChrW$(1054) & ChrW$(1090) & ChrW$(1084) & ChrW$(1077) & ChrW$(1085) & ChrW$(1072)
frm.cmdYes.Default = True
frm.cmdNo.Cancel = True
frm.Controls(CUSTOM_NAME_TEXTBOX_NAME).Text = vbNullString
frm.Controls(CUSTOM_NAME_TEXTBOX_NAME).SetFocus
On Error GoTo 0
SyncSpecialControls frm, SelectionSession.GetSelectionSpecial()
End Sub
Public Sub HandleSpecialToggle(ByVal frm As Object)
If frm Is Nothing Then Exit Sub
If mSyncing Then Exit Sub
SyncSpecialControls frm, CBool(frm.chkSpecialMirror.value)
End Sub
Public Function HandleOkClick(ByVal frm As Object) As Boolean
If frm Is Nothing Then Exit Function
mCustomName = Trim$(ReadNameValue(frm))
If Len(mCustomName) = 0 Then Exit Function
SelectionSession.SetSelectionSpecial CBool(frm.chkSpecialMirror.value)
mAccepted = True
HandleOkClick = True
End Function
Public Function HandleCancelClick(ByVal frm As Object) As Boolean
mAccepted = False
HandleCancelClick = True
End Function
Public Function HandleQueryClose(ByVal frm As Object) As Boolean
mAccepted = False
HandleQueryClose = True
End Function
Private Sub SyncSpecialControls(ByVal frm As Object, ByVal newValue As Boolean)
mSyncing = True
SelectionSession.SetSelectionSpecial newValue
On Error Resume Next
frm.chkSpecialMirror.value = newValue
frm.chkSpecialMirror.ForeColor = IIf(newValue, vbRed, vbBlack)
frm.lblSpecialMirror.ForeColor = IIf(newValue, vbRed, vbBlack)
On Error GoTo 0
mSyncing = False
End Sub
Private Function ReadNameValue(ByVal frm As Object) As String
Dim ctrl As Object
On Error Resume Next
Set ctrl = frm.Controls(CUSTOM_NAME_TEXTBOX_NAME)
If Not ctrl Is Nothing Then
ReadNameValue = Trim$(CStr(ctrl.Value))
If Len(ReadNameValue) = 0 Then ReadNameValue = Trim$(CStr(ctrl.Text))
End If
On Error GoTo 0
End Function
Private Sub ConfigureDynamicControls(ByVal frm As Object)
Dim lbl As Object
Dim txt As Object
On Error Resume Next
frm.Controls.Remove CUSTOM_NAME_LABEL_NAME
frm.Controls.Remove CUSTOM_NAME_TEXTBOX_NAME
On Error GoTo 0
On Error Resume Next
Set lbl = frm.Controls.Add("Forms.Label.1", CUSTOM_NAME_LABEL_NAME, True)
With lbl
.caption = ChrW$(1042) & ChrW$(1074) & ChrW$(1077) & ChrW$(1076) & ChrW$(1080) & ChrW$(1090) & ChrW$(1077) & " " & ChrW$(1085) & ChrW$(1072) & ChrW$(1079) & ChrW$(1074) & ChrW$(1072) & ChrW$(1085) & ChrW$(1080) & ChrW$(1077) & " " & ChrW$(1087) & ChrW$(1086) & ChrW$(1090) & ChrW$(1088) & ChrW$(1077) & ChrW$(1073) & ChrW$(1080) & ChrW$(1090) & ChrW$(1077) & ChrW$(1083) & ChrW$(1103) & ":"
.Left = 300
.Top = 360
.Width = 5000
.Height = 240
.Font.Name = "Arial"
.Font.Size = 8
.ForeColor = vbBlack
.BackStyle = fmBackStyleTransparent
End With
Set txt = frm.Controls.Add("Forms.TextBox.1", CUSTOM_NAME_TEXTBOX_NAME, True)
With txt
.Left = 300
.Top = 630
.Width = 7600
.Height = 300
.Font.Name = "Arial"
.Font.Size = 8
.Text = vbNullString
End With
On Error GoTo 0
End Sub
```
44444
## Diagnostics.bas
```vb
Attribute VB_Name = "Diagnostics"
Option Explicit
' Lightweight diagnostics for runtime and layout invariants.
' Output goes to the VBA Immediate window via Debug.Print.
Private CurrentOperationName As String
Private CurrentOperationStartedAt As Date
Private CurrentOperationSteps As Collection
Private CurrentOperationHasError As Boolean
Public Sub BeginOperation(ByVal operationName As String)
CurrentOperationName = Trim$(operationName)
CurrentOperationStartedAt = Now
CurrentOperationHasError = False
Set CurrentOperationSteps = New Collection
Debug.Print TimestampPrefix() & "BEGIN " & CurrentOperationName
End Sub
Public Sub MarkStepOk(ByVal stepName As String, Optional ByVal details As String = "")
AppendStep "OK", stepName, details
End Sub
Public Sub MarkStepError(ByVal stepName As String, Optional ByVal details As String = "")
CurrentOperationHasError = True
AppendStep "ERROR", stepName, details
End Sub
Public Sub FinishOperation(Optional ByVal finalStatus As String = "OK")
Dim statusText As String
Dim item As Variant
If Len(CurrentOperationName) = 0 Then Exit Sub
statusText = UCase$(Trim$(finalStatus))
If CurrentOperationHasError And statusText = "OK" Then statusText = "ERROR"
Debug.Print TimestampPrefix() & "END " & CurrentOperationName & " [" & statusText & "]"
If Not CurrentOperationSteps Is Nothing Then
For Each item In CurrentOperationSteps
Debug.Print " " & CStr(item)
Next item
End If
CurrentOperationName = vbNullString
CurrentOperationStartedAt = 0
CurrentOperationHasError = False
Set CurrentOperationSteps = Nothing
End Sub
Public Function IsOperationActive() As Boolean
IsOperationActive = (Len(CurrentOperationName) > 0)
End Function
Public Function AssertCoreState(Optional ByVal stageName As String = "") As Boolean
Dim runtimeIssues As String
Dim layoutIssues As String
Dim issueText As String
runtimeIssues = ValidateRuntimeState()
layoutIssues = ValidateLayoutState()
If Len(runtimeIssues) > 0 Then issueText = runtimeIssues
If Len(layoutIssues) > 0 Then
If Len(issueText) > 0 Then issueText = issueText & " | "
issueText = issueText & layoutIssues
End If
AssertCoreState = (Len(issueText) = 0)
If AssertCoreState Then Exit Function
If Len(stageName) > 0 Then
Debug.Print TimestampPrefix() & "CORE CHECK FAILED [" & stageName & "] " & issueText
Else
Debug.Print TimestampPrefix() & "CORE CHECK FAILED " & issueText
End If
End Function
Public Function ValidateRuntimeState() As String
Dim rowIndex As Long
Dim rowText As String
If StateRuntime.RuntimeRowsCount < 1 Then
AddIssue ValidateRuntimeState, "RuntimeRowsCount < 1"
Exit Function
End If
If StateRuntime.RuntimeEFCount < StateRuntime.RuntimeRowsCount Then
AddIssue ValidateRuntimeState, "RuntimeEFCount < RuntimeRowsCount"
End If
For rowIndex = 1 To StateRuntime.RuntimeRowsCount
If Not StateRuntime.RuntimeRowExists(rowIndex) Then
AddIssue ValidateRuntimeState, "Missing runtime slot " & rowIndex
GoTo NextRow
End If
If StateRuntime.RuntimeRowHasData(rowIndex) And StateRuntime.RuntimeRows(rowIndex).rowID <= 0 Then
AddIssue ValidateRuntimeState, "Row " & rowIndex & " has data but no RowID"
End If
If StateRuntime.RuntimeRows(rowIndex).IsCustom Then
rowText = Trim$(StateRuntime.RuntimeRows(rowIndex).consumerName)
If Len(rowText) = 0 Then AddIssue ValidateRuntimeState, "Custom row " & rowIndex & " has blank ConsumerName"
End If
NextRow:
Next rowIndex
End Function
Public Function ValidateLayoutState() As String
Dim layout As CoreBlockLayout
Dim rowIndex As Long
Dim previousPhysicalRow As Long
Dim currentPhysicalRow As Long
layout = LayoutEngine.BuildBlockLayout()
If layout.LogicalRowCount <> StateRuntime.GetRuntimeLogicalRowCount() Then
AddIssue ValidateLayoutState, "LogicalRowCount mismatch"
End If
If layout.filledNormalCount <> LayoutEngine.CountNormalRows() Then
AddIssue ValidateLayoutState, "FilledNormalCount mismatch"
End If
If layout.filledSpecialCount <> LayoutEngine.CountSpecialRows() Then
AddIssue ValidateLayoutState, "FilledSpecialCount mismatch"
End If
If layout.blockSize < 2 Then
AddIssue ValidateLayoutState, "BlockSize < 2"
End If
For rowIndex = 1 To layout.LogicalRowCount
currentPhysicalRow = LayoutEngine.GetPhysicalRow(1, rowIndex, layout)
If currentPhysicalRow <= 0 Then
AddIssue ValidateLayoutState, "Missing physical row for logical row " & rowIndex
GoTo NextRow
End If
If previousPhysicalRow > 0 And currentPhysicalRow < previousPhysicalRow Then
AddIssue ValidateLayoutState, "Physical rows are not monotonic"
Exit For
End If
previousPhysicalRow = currentPhysicalRow
NextRow:
Next rowIndex
If layout.HasMixedGroups Then
If layout.upperTotalRow <= layout.UpperPlaceholderRow Then AddIssue ValidateLayoutState, "Upper total row order is invalid"
If layout.LowerFirstRow <= layout.upperTotalRow Then AddIssue ValidateLayoutState, "Lower section starts before upper total"
If layout.lowerTotalRow <= layout.LowerPlaceholderRow Then AddIssue ValidateLayoutState, "Lower total row order is invalid"
If layout.GrandTotalRow <= layout.lowerTotalRow Then AddIssue ValidateLayoutState, "Grand total row order is invalid"
End If
End Function
Public Function SnapshotState() As String
Dim layout As CoreBlockLayout
Dim rowIndex As Long
Dim lineText As String
layout = LayoutEngine.BuildBlockLayout()
lineText = "rows=" & StateRuntime.RuntimeRowsCount & ", normals=" & layout.filledNormalCount & ", specials=" & layout.filledSpecialCount & ", blockSize=" & layout.blockSize
For rowIndex = 1 To StateRuntime.RuntimeRowsCount
lineText = lineText & " | #" & rowIndex & ":" & RowSnapshot(rowIndex)
Next rowIndex
SnapshotState = lineText
End Function
Private Sub AppendStep(ByVal statusText As String, ByVal stepName As String, ByVal details As String)
Dim lineText As String
lineText = "[" & UCase$(Trim$(statusText)) & "] " & Trim$(stepName)
If Len(Trim$(details)) > 0 Then lineText = lineText & " - " & Trim$(details)
If CurrentOperationSteps Is Nothing Then Set CurrentOperationSteps = New Collection
CurrentOperationSteps.Add lineText
Debug.Print TimestampPrefix() & lineText
End Sub
Private Sub AddIssue(ByRef issueText As String, ByVal newIssue As String)
If Len(issueText) > 0 Then issueText = issueText & "; "
issueText = issueText & newIssue
End Sub
Private Function RowSnapshot(ByVal rowIndex As Long) As String
Dim stateText As String
If Not StateRuntime.RuntimeRowExists(rowIndex) Then
RowSnapshot = "missing"
Exit Function
End If
If StateRuntime.RuntimeRowHasData(rowIndex) Then
stateText = "filled"
Else
stateText = "empty"
End If
RowSnapshot = StateRuntime.RuntimeRows(rowIndex).rowID & _
":" & IIf(StateRuntime.RuntimeRows(rowIndex).IsSpecial, "S", "N") & _
":" & stateText
End Function
Private Function TimestampPrefix() As String
TimestampPrefix = Format$(Now, "hh:nn:ss") & " "
End Function
```
55555
## NormsCatalog.bas
```vb
Attribute VB_Name = "NormsCatalog"
Option Explicit
' Read-only access to the Norms sheet.
' This module centralizes row lookup and editable-mask rules.
Private CachedNormRows() As Variant
Private CachedNormRowLoaded() As Boolean
Private CachedNormRowUpperBound As Long
Private CachedNormLookupLoaded As Boolean
Private CachedNormLookupLastRow As Long
Private CachedNormCodes() As String
Private CachedNormNames() As String
Private CachedNormDefaultSpecial() As Boolean
Private CachedNormByConsumer As Object
Private CachedNormByCode As Object
Public Function LoadNormsValues(ByVal rowNorms As Long) As Variant
Dim wsN As Worksheet
If rowNorms <= 0 Then Exit Function
EnsureNormRowCacheCapacity rowNorms
If CachedNormRowLoaded(rowNorms) Then
LoadNormsValues = CachedNormRows(rowNorms)
Exit Function
End If
Set wsN = GetNormsSheet()
If wsN Is Nothing Then Exit Function
CachedNormRows(rowNorms) = wsN.Range(wsN.Cells(rowNorms, 2), wsN.Cells(rowNorms, 14)).value
CachedNormRowLoaded(rowNorms) = True
LoadNormsValues = CachedNormRows(rowNorms)
End Function
Public Function ResolveNormsRow(ByVal consumerName As String, ByVal codeB As String) As Long
ResolveNormsRow = ResolveNormsRowByConsumer(consumerName)
If ResolveNormsRow > 0 Then Exit Function
If Len(Trim$(codeB)) > 0 Then
ResolveNormsRow = ResolveNormsRowByCode(codeB)
End If
End Function
Public Function ResolveNormsRowByConsumer(ByVal consumerName As String) As Long
Dim searchName As String
searchName = NormalizeNormsText(consumerName)
If Len(searchName) = 0 Then Exit Function
EnsureNormLookupCache
If CachedNormByConsumer Is Nothing Then Exit Function
If CachedNormByConsumer.Exists(searchName) Then ResolveNormsRowByConsumer = CLng(CachedNormByConsumer(searchName))
End Function
Public Function ResolveNormsRowByCode(ByVal codeB As String) As Long
Dim searchCode As String
searchCode = Trim$(Replace(CStr(codeB), " ", vbNullString))
If Len(searchCode) = 0 Then Exit Function
EnsureNormLookupCache
If CachedNormByCode Is Nothing Then Exit Function
If CachedNormByCode.Exists(searchCode) Then ResolveNormsRowByCode = CLng(CachedNormByCode(searchCode))
End Function
Public Function GetNormCode(ByVal rowNorms As Long) As String
If rowNorms <= 0 Then Exit Function
EnsureNormLookupCache
If rowNorms > CachedNormLookupLastRow Then Exit Function
GetNormCode = CachedNormCodes(rowNorms)
End Function
Public Function PopulateConsumerList(ByVal listBox As Object, Optional ByVal levelCode As String = "") As Long
Dim rowNum As Long
Dim codeText As String
Dim nameText As String
If listBox Is Nothing Then Exit Function
EnsureNormLookupCache
If CachedNormLookupLastRow < 7 Then Exit Function
listBox.Clear
For rowNum = 7 To CachedNormLookupLastRow
codeText = CachedNormCodes(rowNum)
nameText = CachedNormNames(rowNum)
If Len(nameText) = 0 Then GoTo NextRow
If Len(levelCode) = 0 Then
If IsTopLevelNorm(codeText) Then
listBox.AddItem nameText
listBox.List(listBox.ListCount - 1, 1) = rowNum
PopulateConsumerList = PopulateConsumerList + 1
End If
ElseIf Left$(codeText, Len(levelCode)) = levelCode And Len(codeText) > Len(levelCode) Then
listBox.AddItem nameText
listBox.List(listBox.ListCount - 1, 1) = rowNum
PopulateConsumerList = PopulateConsumerList + 1
End If
NextRow:
Next rowNum
End Function
Public Function HasChildNorms(ByVal levelCode As String) As Boolean
Dim rowNum As Long
Dim codeText As String
If Len(levelCode) = 0 Then Exit Function
EnsureNormLookupCache
If CachedNormLookupLastRow < 7 Then Exit Function
For rowNum = 7 To CachedNormLookupLastRow
codeText = CachedNormCodes(rowNum)
If Left$(codeText, Len(levelCode)) = levelCode And Len(codeText) > Len(levelCode) Then
HasChildNorms = True
Exit Function
End If
Next rowNum
End Function
Public Function GetNormEditableMask(ByVal rowNorms As Long, ByVal blockNum As Long) As Variant
Dim mask(1 To 4) As Boolean
Dim valueIndex As Long
If rowNorms <= 0 Then
GetNormEditableMask = mask
Exit Function
End If
For valueIndex = 1 To 4
mask(valueIndex) = NeedsManualReplacement(GetNormDefaultValue(rowNorms, blockNum, valueIndex))
Next valueIndex
GetNormEditableMask = mask
End Function
Public Function GetNormDefaultValue(ByVal rowNorms As Long, ByVal blockNum As Long, ByVal valueIndex As Long) As Variant
Dim normsValues As Variant
If rowNorms <= 0 Then Exit Function
If valueIndex < 1 Or valueIndex > 4 Then Exit Function
normsValues = LoadNormsValues(rowNorms)
If IsEmpty(normsValues) Then Exit Function
Select Case blockNum
Case 1
Select Case valueIndex
Case 1: GetNormDefaultValue = normsValues(1, 4)
Case 2: GetNormDefaultValue = normsValues(1, 6)
Case 3: GetNormDefaultValue = normsValues(1, 9)
Case 4: GetNormDefaultValue = normsValues(1, 10)
End Select
Case 2
Select Case valueIndex
Case 1: GetNormDefaultValue = ResolveBlock2GValue(normsValues)
Case 2: GetNormDefaultValue = normsValues(1, 8)
Case 3: GetNormDefaultValue = normsValues(1, 11)
Case 4: GetNormDefaultValue = normsValues(1, 12)
End Select
Case 3
Select Case valueIndex
Case 1: GetNormDefaultValue = normsValues(1, 5)
Case 2: GetNormDefaultValue = normsValues(1, 7)
Case 3: GetNormDefaultValue = normsValues(1, 11)
Case 4: GetNormDefaultValue = normsValues(1, 12)
End Select
End Select
End Function
Public Function IsNormValueManual(ByVal rowNorms As Long, ByVal blockNum As Long, ByVal valueIndex As Long) As Boolean
IsNormValueManual = NeedsManualReplacement(GetNormDefaultValue(rowNorms, blockNum, valueIndex))
End Function
Public Function IsNormDefaultSpecial(ByVal rowNorms As Long) As Boolean
If rowNorms <= 0 Then Exit Function
EnsureNormLookupCache
If rowNorms > CachedNormLookupLastRow Then Exit Function
IsNormDefaultSpecial = CachedNormDefaultSpecial(rowNorms)
End Function
Public Function GetNormWorkTime(ByVal rowNorms As Long) As Variant
Dim normsValues As Variant
If rowNorms <= 0 Then Exit Function
normsValues = LoadNormsValues(rowNorms)
If IsEmpty(normsValues) Then Exit Function
GetNormWorkTime = normsValues(1, 13)
End Function
Public Sub ResetNormsRowCache()
Erase CachedNormRows
Erase CachedNormRowLoaded
CachedNormRowUpperBound = 0
CachedNormLookupLoaded = False
CachedNormLookupLastRow = 0
Erase CachedNormCodes
Erase CachedNormNames
Erase CachedNormDefaultSpecial
Set CachedNormByConsumer = Nothing
Set CachedNormByCode = Nothing
End Sub
Private Sub EnsureNormLookupCache()
Dim wsN As Worksheet
Dim lastRow As Long
Dim rawData As Variant
Dim rowNum As Long
Dim codeText As String
Dim nameText As String
Dim markerText As String
If CachedNormLookupLoaded Then Exit Sub
Set wsN = GetNormsSheet()
If wsN Is Nothing Then Exit Sub
lastRow = wsN.Cells(wsN.Rows.count, 3).End(xlUp).Row
CachedNormLookupLastRow = lastRow
If lastRow < 7 Then
CachedNormLookupLoaded = True
Exit Sub
End If
rawData = wsN.Range(wsN.Cells(7, 2), wsN.Cells(lastRow, 15)).value
ReDim CachedNormCodes(1 To lastRow)
ReDim CachedNormNames(1 To lastRow)
ReDim CachedNormDefaultSpecial(1 To lastRow)
Set CachedNormByConsumer = CreateObject("Scripting.Dictionary")
Set CachedNormByCode = CreateObject("Scripting.Dictionary")
For rowNum = 7 To lastRow
codeText = Trim$(CStr(rawData(rowNum - 6, 1)))
nameText = Trim$(CStr(rawData(rowNum - 6, 2)))
markerText = Trim$(CStr(rawData(rowNum - 6, 14)))
CachedNormCodes(rowNum) = codeText
CachedNormNames(rowNum) = nameText
CachedNormDefaultSpecial(rowNum) = (markerText = "!")
If Len(nameText) > 0 Then
nameText = NormalizeNormsText(nameText)
If Len(nameText) > 0 Then
If Not CachedNormByConsumer.Exists(nameText) Then CachedNormByConsumer.Add nameText, rowNum
End If
End If
If Len(codeText) > 0 Then
codeText = Trim$(Replace(codeText, " ", vbNullString))
If Not CachedNormByCode.Exists(codeText) Then CachedNormByCode.Add codeText, rowNum
End If
Next rowNum
CachedNormLookupLoaded = True
End Sub
Private Function GetNormsSheet() As Worksheet
On Error Resume Next
Set GetNormsSheet = ThisWorkbook.Worksheets(NormsSheetName())
On Error GoTo 0
End Function
Private Function NormalizeNormsText(ByVal rawValue As Variant) As String
NormalizeNormsText = Trim$(Replace(CStr(rawValue), " ", vbNullString))
End Function
Private Function IsManualNormToken(ByVal rawValue As Variant) As Boolean
Dim textValue As String
textValue = Trim$(CStr(rawValue))
If Len(textValue) = 0 Then Exit Function
If IsNumeric(rawValue) Then Exit Function
IsManualNormToken = True
End Function
Private Function NeedsManualReplacement(ByVal rawValue As Variant) As Boolean
If IsEmpty(rawValue) Or IsNull(rawValue) Then Exit Function
If Len(Trim$(CStr(rawValue))) = 0 Then Exit Function
If IsNumeric(rawValue) Then Exit Function
NeedsManualReplacement = True
End Function
Private Function ResolveBlock2GValue(ByVal normsValues As Variant) As Variant
If IsNumeric(normsValues(1, 4)) And IsNumeric(normsValues(1, 5)) Then
ResolveBlock2GValue = CDbl(normsValues(1, 4)) - CDbl(normsValues(1, 5))
Exit Function
End If
If IsManualNormToken(normsValues(1, 4)) Then
ResolveBlock2GValue = CStr(normsValues(1, 4))
ElseIf IsManualNormToken(normsValues(1, 5)) Then
ResolveBlock2GValue = CStr(normsValues(1, 5))
End If
End Function
Private Function IsTopLevelNorm(ByVal codeText As String) As Boolean
If Len(codeText) < 2 Then Exit Function
If Right$(codeText, 1) <> "." Then Exit Function
If Not IsNumeric(Left$(codeText, 1)) Then Exit Function
IsTopLevelNorm = True
End Function
Private Sub EnsureNormRowCacheCapacity(ByVal rowNorms As Long)
Dim newUpperBound As Long
If rowNorms <= CachedNormRowUpperBound Then Exit Sub
newUpperBound = rowNorms + 64
If newUpperBound < 128 Then newUpperBound = 128
If CachedNormRowUpperBound = 0 Then
ReDim CachedNormRows(1 To newUpperBound)
ReDim CachedNormRowLoaded(1 To newUpperBound)
Else
ReDim Preserve CachedNormRows(1 To newUpperBound)
ReDim Preserve CachedNormRowLoaded(1 To newUpperBound)
End If
CachedNormRowUpperBound = newUpperBound
End Sub
```