1008 lines
32 KiB
Markdown
1008 lines
32 KiB
Markdown
# VBA 模組原始碼
|
||
# 來源:全機型_日報表.xlsm
|
||
# 提取工具:olevba 0.60.2
|
||
# 提取時間:2026-04-07
|
||
|
||
---
|
||
|
||
## Module19.bas - NT()
|
||
|
||
```vba
|
||
Function NT(Number As Integer) As String
|
||
NT = Split(Cells(1, Number).Address, "$")(1)
|
||
End Function
|
||
```
|
||
|
||
---
|
||
|
||
## Module7.bas - ra()
|
||
|
||
```vba
|
||
Function ra(inputText As String) As String
|
||
Dim regEx As Object
|
||
Dim matches As Object
|
||
Set regEx = CreateObject("VBScript.RegExp")
|
||
|
||
With regEx
|
||
.pattern = "[A-Z0-9-]{6,25}"
|
||
.Global = True
|
||
End With
|
||
|
||
Set matches = regEx.Execute(inputText)
|
||
|
||
If matches.Count > 0 Then
|
||
ra = matches(0).Value
|
||
Else
|
||
ra = "NO"
|
||
End If
|
||
End Function
|
||
```
|
||
|
||
---
|
||
|
||
## Module5.bas - A()
|
||
|
||
```vba
|
||
Sub A()
|
||
Call B
|
||
Call Q
|
||
End Sub
|
||
```
|
||
|
||
---
|
||
|
||
## Module6.bas - B()
|
||
|
||
```vba
|
||
Sub B()
|
||
Application.ScreenUpdating = False
|
||
Application.Calculation = xlCalculationManual
|
||
Application.EnableEvents = False
|
||
|
||
Dim wsFocest As Worksheet, wsBOM As Worksheet, wsOutput As Worksheet, wsUnmatched As Worksheet
|
||
Dim lastRowF As Long, lastRowB As Long, lastRowO As Long, lastRowU As Long
|
||
Dim i As Long, j As Long, k As Long, col As Long
|
||
Dim keyPart As String, material As String, usage As Double
|
||
Dim lic As Double, focestCol1 As String, focestCol2 As String
|
||
Dim weekValues(1 To 56) As Double
|
||
Dim dictBOM As Object, dictUnmatched As Object
|
||
Dim materialData As Variant
|
||
Dim key As Variant
|
||
|
||
Set dictBOM = CreateObject("Scripting.Dictionary")
|
||
Set dictUnmatched = CreateObject("Scripting.Dictionary")
|
||
|
||
' Set worksheets
|
||
Set wsFocest = ThisWorkbook.Sheets("FCST")
|
||
Set wsBOM = ThisWorkbook.Sheets("BOM")
|
||
|
||
' Create new worksheets for output
|
||
On Error Resume Next
|
||
Application.DisplayAlerts = False
|
||
ThisWorkbook.Sheets("Output").Delete
|
||
ThisWorkbook.Sheets("Unmatched").Delete
|
||
Application.DisplayAlerts = True
|
||
On Error GoTo 0
|
||
|
||
Set wsOutput = ThisWorkbook.Sheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
|
||
wsOutput.Name = "Output"
|
||
Set wsUnmatched = ThisWorkbook.Sheets.Add(After:=wsOutput)
|
||
wsUnmatched.Name = "Unmatched"
|
||
|
||
' Phase 1: Read BOM data into dictionary
|
||
lastRowB = wsBOM.Cells(wsBOM.Rows.Count, "A").End(xlUp).Row
|
||
Dim bomData As Variant
|
||
bomData = wsBOM.Range("A2:C" & lastRowB).Value
|
||
|
||
For i = 1 To UBound(bomData, 1)
|
||
keyPart = Trim(bomData(i, 1) & "")
|
||
material = Trim(bomData(i, 2) & "")
|
||
|
||
' Safe handling of usage value
|
||
If IsNumeric(bomData(i, 3)) Then
|
||
usage = CDbl(bomData(i, 3))
|
||
Else
|
||
usage = 0
|
||
End If
|
||
|
||
If keyPart <> "" And material <> "" Then
|
||
If Not dictBOM.exists(keyPart) Then
|
||
dictBOM.Add keyPart, New Collection
|
||
End If
|
||
dictBOM(keyPart).Add Array(material, usage)
|
||
End If
|
||
Next i
|
||
|
||
' Phase 2: Process Focest data - only process rows with BOM matches
|
||
lastRowF = wsFocest.Cells(wsFocest.Rows.Count, "A").End(xlUp).Row
|
||
Dim focestData As Variant
|
||
focestData = wsFocest.Range("A2:BJ" & lastRowF).Value ' Columns A to BJ (A, B + 56 weeks)
|
||
|
||
' Pre-calculate output data size
|
||
Dim outputRowCount As Long
|
||
outputRowCount = 0
|
||
For i = 1 To UBound(focestData, 1)
|
||
keyPart = Trim(focestData(i, 1) & "")
|
||
If keyPart <> "" And dictBOM.exists(keyPart) Then
|
||
outputRowCount = outputRowCount + dictBOM(keyPart).Count
|
||
End If
|
||
Next i
|
||
|
||
' Prepare output array
|
||
Dim outputData() As Variant
|
||
ReDim outputData(1 To outputRowCount, 1 To 60) ' 4 fixed columns + 56 week columns
|
||
|
||
lastRowO = 0
|
||
|
||
For i = 1 To UBound(focestData, 1)
|
||
keyPart = Trim(focestData(i, 1) & "")
|
||
If keyPart = "" Then GoTo NextFocestRow
|
||
|
||
' Only process rows with BOM matches
|
||
If dictBOM.exists(keyPart) Then
|
||
focestCol1 = focestData(i, 1) & ""
|
||
focestCol2 = focestData(i, 2) & ""
|
||
|
||
' Safe handling of LIC value
|
||
If IsNumeric(focestData(i, 2)) Then
|
||
lic = CDbl(focestData(i, 2))
|
||
Else
|
||
lic = 0
|
||
End If
|
||
|
||
' Extract week values with error handling
|
||
For j = 1 To 56
|
||
If IsNumeric(focestData(i, j + 2)) Then
|
||
weekValues(j) = CDbl(focestData(i, j + 2))
|
||
Else
|
||
weekValues(j) = 0
|
||
End If
|
||
Next j
|
||
|
||
' Process matching BOM items
|
||
For k = 1 To dictBOM(keyPart).Count
|
||
materialData = dictBOM(keyPart)(k)
|
||
material = materialData(0)
|
||
usage = materialData(1)
|
||
lastRowO = lastRowO + 1
|
||
|
||
outputData(lastRowO, 1) = focestCol1
|
||
outputData(lastRowO, 2) = focestCol2
|
||
outputData(lastRowO, 3) = material
|
||
outputData(lastRowO, 4) = usage
|
||
|
||
For col = 1 To 56
|
||
outputData(lastRowO, col + 4) = weekValues(col) * lic * usage
|
||
Next col
|
||
Next k
|
||
End If
|
||
|
||
NextFocestRow:
|
||
Next i
|
||
|
||
' Phase 3: Separately process Focest rows without BOM matches
|
||
For i = 1 To UBound(focestData, 1)
|
||
keyPart = Trim(focestData(i, 1) & "")
|
||
If keyPart <> "" And Not dictBOM.exists(keyPart) Then
|
||
If Not dictUnmatched.exists(keyPart) Then
|
||
dictUnmatched.Add keyPart, True
|
||
End If
|
||
End If
|
||
Next i
|
||
|
||
' Batch write output data
|
||
If outputRowCount > 0 Then
|
||
wsOutput.Range("A2").Resize(outputRowCount, 60).Value = outputData
|
||
End If
|
||
|
||
' Generate unmatched sheet
|
||
wsUnmatched.Cells(1, 1).Value = "Unmatched Key Part Numbers"
|
||
|
||
If dictUnmatched.Count > 0 Then
|
||
Dim unmatchedData() As Variant
|
||
ReDim unmatchedData(1 To dictUnmatched.Count, 1 To 1)
|
||
i = 0
|
||
For Each key In dictUnmatched.Keys
|
||
i = i + 1
|
||
unmatchedData(i, 1) = key
|
||
Next key
|
||
wsUnmatched.Range("A2").Resize(dictUnmatched.Count, 1).Value = unmatchedData
|
||
End If
|
||
|
||
' Set headers
|
||
wsOutput.Cells(1, 1).Value = "Focest Col1"
|
||
wsOutput.Cells(1, 2).Value = "Focest Col2"
|
||
wsOutput.Cells(1, 3).Value = "Material Number"
|
||
wsOutput.Cells(1, 4).Value = "BOM Usage"
|
||
For col = 1 To 56
|
||
wsOutput.Cells(1, col + 4).Value = "Week" & col
|
||
Next col
|
||
|
||
' Auto-fit columns
|
||
wsOutput.Columns.AutoFit
|
||
wsUnmatched.Columns.AutoFit
|
||
|
||
Application.ScreenUpdating = True
|
||
Application.Calculation = xlCalculationAutomatic
|
||
Application.EnableEvents = True
|
||
|
||
MsgBox "Processing completed! " & outputRowCount & " rows generated in Output sheet. " & _
|
||
dictUnmatched.Count & " unmatched items found."
|
||
End Sub
|
||
```
|
||
|
||
---
|
||
|
||
## Module3.bas - Q()
|
||
|
||
```vba
|
||
Sub Q()
|
||
' Define variables
|
||
Dim wsSource As Worksheet, wsDest As Worksheet
|
||
Dim pvtCache As PivotCache
|
||
Dim pvtTable As PivotTable
|
||
Dim lastRow As Long
|
||
Dim SourceDataRange As Range
|
||
Dim i As Long
|
||
Dim fieldName As String
|
||
Dim startTime As Double
|
||
Dim dataField As PivotField
|
||
|
||
' Start timing execution
|
||
startTime = Timer
|
||
|
||
' Disable Excel features for performance optimization
|
||
OptimizeVBA True
|
||
|
||
On Error GoTo ErrorHandler
|
||
|
||
' Check if source worksheet exists
|
||
If Not WorksheetExists("Output") Then
|
||
MsgBox "Source worksheet 'Output' not found!", vbCritical
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
' Set reference to source worksheet
|
||
Set wsSource = ThisWorkbook.Worksheets("Output")
|
||
|
||
' Delete destination worksheet if it already exists
|
||
If WorksheetExists("Cutout") Then
|
||
Application.DisplayAlerts = False
|
||
ThisWorkbook.Worksheets("Cutout").Delete
|
||
Application.DisplayAlerts = True
|
||
End If
|
||
|
||
' Remove any existing pivot table with the same name
|
||
RemovePivotTable "WeeklySummaryPivot"
|
||
|
||
' Create new worksheet for the pivot table
|
||
Set wsDest = ThisWorkbook.Worksheets.Add(After:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count))
|
||
wsDest.Name = "Cutout"
|
||
|
||
' Find the last row with data in source worksheet - MORE ROBUST METHOD
|
||
lastRow = wsSource.Cells(wsSource.Rows.Count, "A").End(xlUp).Row
|
||
If lastRow = 1 And wsSource.Cells(1, 1).Value = "" Then lastRow = 0
|
||
|
||
' Verify there is sufficient data
|
||
If lastRow < 2 Then
|
||
MsgBox "Insufficient data in source worksheet!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
' Define source data range
|
||
Set SourceDataRange = wsSource.Range("A1:BH" & lastRow)
|
||
|
||
' Create pivot cache from source data
|
||
Set pvtCache = ThisWorkbook.PivotCaches.Create( _
|
||
SourceType:=xlDatabase, _
|
||
SourceData:=SourceDataRange.Address(ReferenceStyle:=xlR1C1, External:=True))
|
||
|
||
Set pvtTable = pvtCache.CreatePivotTable( _
|
||
TableDestination:=wsDest.Range("A3"), _
|
||
tableName:="WeeklySummaryPivot")
|
||
|
||
With pvtTable
|
||
.ManualUpdate = True
|
||
.RowAxisLayout xlTabularRow
|
||
|
||
' Add row field - Material Number (Column C)
|
||
.PivotFields(wsSource.Cells(1, 3).Value).Orientation = xlRowField
|
||
|
||
' Add data fields (columns E to BH) - WITH PERFORMANCE CHECK
|
||
For i = 5 To 60
|
||
fieldName = wsSource.Cells(1, i).Value
|
||
|
||
' Only add field if it has a name and is likely numeric (avoid text fields for sum)
|
||
If fieldName <> "" Then
|
||
On Error Resume Next
|
||
Set dataField = .PivotFields(fieldName)
|
||
If Err.Number = 0 Then
|
||
With dataField
|
||
.Orientation = xlDataField
|
||
.Function = xlSum
|
||
.NumberFormat = "#,##0"
|
||
' Only rename if not already renamed
|
||
If InStr(1, .Caption, "Sum of", vbTextCompare) = 0 Then
|
||
.Caption = "Sum of " & fieldName
|
||
End If
|
||
End With
|
||
Else
|
||
Err.Clear
|
||
End If
|
||
On Error GoTo ErrorHandler
|
||
End If
|
||
Next i
|
||
|
||
' Apply formatting
|
||
.ShowTableStyleRowStripes = True
|
||
On Error Resume Next
|
||
.TableStyle2 = "PivotStyleMedium9"
|
||
If Err.Number <> 0 Then
|
||
.TableStyle1 = "PivotStyleMedium9"
|
||
Err.Clear
|
||
End If
|
||
On Error GoTo ErrorHandler
|
||
.ManualUpdate = False
|
||
End With
|
||
|
||
' Add title and timestamp
|
||
With wsDest
|
||
.Range("A1").Value = "Weekly Summary Report"
|
||
.Range("A1").Font.Bold = True
|
||
.Range("A1").Font.Size = 14
|
||
|
||
.Range("A2").Value = "Generated: " & Now()
|
||
.Range("A2").Font.Italic = True
|
||
End With
|
||
|
||
' Auto-fit columns carefully for large datasets
|
||
Application.ScreenUpdating = False
|
||
wsDest.UsedRange.Columns.AutoFit
|
||
Application.ScreenUpdating = True
|
||
|
||
' Success message
|
||
MsgBox "Pivot table created successfully in " & Format(Timer - startTime, "0.00") & _
|
||
" seconds! Location: Worksheet " & wsDest.Name, vbInformation
|
||
|
||
CleanUp:
|
||
OptimizeVBA False
|
||
Set pvtTable = Nothing
|
||
Set pvtCache = Nothing
|
||
Set SourceDataRange = Nothing
|
||
Set wsSource = Nothing
|
||
Set wsDest = Nothing
|
||
|
||
Exit Sub
|
||
|
||
ErrorHandler:
|
||
MsgBox "Error " & Err.Number & ": " & Err.Description & vbCrLf & _
|
||
"Please ensure your data in 'Output' sheet is correctly formatted.", vbCritical
|
||
Resume CleanUp
|
||
End Sub
|
||
|
||
' Helper function: Optimize VBA performance
|
||
Sub OptimizeVBA(Optimize As Boolean)
|
||
With Application
|
||
If Optimize Then
|
||
.ScreenUpdating = False
|
||
.Calculation = xlCalculationManual
|
||
.DisplayAlerts = False
|
||
.EnableEvents = False
|
||
.StatusBar = "Processing... Please wait"
|
||
Else
|
||
.ScreenUpdating = True
|
||
.Calculation = xlCalculationAutomatic
|
||
.DisplayAlerts = True
|
||
.EnableEvents = True
|
||
.StatusBar = False
|
||
End If
|
||
End With
|
||
End Sub
|
||
|
||
' Helper function: Check if worksheet exists
|
||
Function WorksheetExists(sheetName As String) As Boolean
|
||
On Error Resume Next
|
||
WorksheetExists = Not ThisWorkbook.Sheets(sheetName) Is Nothing
|
||
On Error GoTo 0
|
||
End Function
|
||
|
||
' Helper function: Remove pivot table by name (FIXED For Each issue)
|
||
Sub RemovePivotTable(tableName As String)
|
||
Dim ws As Worksheet
|
||
Dim pt As PivotTable
|
||
|
||
On Error Resume Next
|
||
|
||
For Each ws In ThisWorkbook.Worksheets
|
||
' CRITICAL FIX: Check if the worksheet has any pivot tables before trying to access one by name
|
||
If ws.PivotTables.Count > 0 Then
|
||
Set pt = ws.PivotTables(tableName)
|
||
If Not pt Is Nothing Then
|
||
pt.TableRange2.Clear
|
||
Exit For
|
||
End If
|
||
End If
|
||
Next ws
|
||
|
||
On Error GoTo 0
|
||
End Sub
|
||
```
|
||
|
||
---
|
||
|
||
## Module20.bas - W()
|
||
|
||
```vba
|
||
Sub W()
|
||
' =========================================================================
|
||
' USER CONFIGURATION AREA - Modify parameters below
|
||
' =========================================================================
|
||
|
||
' Data source settings
|
||
Const SOURCE_SHEET As String = "KCB" ' Source worksheet name
|
||
Const PIVOT_SHEET_NAME As String = "MaterialSummary" ' Output pivot table sheet name
|
||
Const HEADER_ROW As Long = 1 ' Header row number
|
||
|
||
' Custom column settings
|
||
Dim CUSTOM_COLUMNS As Variant
|
||
CUSTOM_COLUMNS = Array("B", "C", "D", "E", "F", "G", "H", "I", "J") ' Columns to include
|
||
|
||
' Pivot table field settings
|
||
Const ROW_FIELD_COLUMN As String = "B" ' Row field (row labels) column
|
||
Dim DATA_FIELDS As Variant
|
||
DATA_FIELDS = Array("C", "D", "E", "F", "G", "H") ' Data field columns to summarize
|
||
|
||
' Performance optimization settings
|
||
Const USE_ARRAY_METHOD As Boolean = False ' Disable array method to avoid 1004 errors
|
||
|
||
' Output settings
|
||
Const SHOW_PERFORMANCE_STATS As Boolean = True ' Show performance statistics
|
||
Const AUTO_ADJUST_COLUMNS As Boolean = True ' Auto-adjust column widths
|
||
|
||
' =========================================================================
|
||
' MAIN PROGRAM - Code below generally doesn't need modification
|
||
' =========================================================================
|
||
|
||
Dim startTime As Double
|
||
If SHOW_PERFORMANCE_STATS Then startTime = Timer
|
||
|
||
Dim wsData As Worksheet, wsPivot As Worksheet
|
||
Dim rngData As Range
|
||
Dim lastRow As Long, lastCol As Long
|
||
|
||
' Performance optimization settings
|
||
Application.ScreenUpdating = False
|
||
Application.Calculation = xlCalculationManual
|
||
Application.EnableEvents = False
|
||
Application.StatusBar = "Preparing data..."
|
||
|
||
On Error GoTo ErrorHandler
|
||
|
||
' Check if source sheet exists
|
||
If Not WorksheetExists(SOURCE_SHEET) Then
|
||
MsgBox "Source worksheet '" & SOURCE_SHEET & "' not found!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
' Set source worksheet
|
||
Set wsData = ThisWorkbook.Worksheets(SOURCE_SHEET)
|
||
|
||
' Get data range
|
||
With wsData
|
||
lastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
|
||
lastCol = .Cells(HEADER_ROW, .Columns.Count).End(xlToLeft).Column
|
||
|
||
If lastRow <= HEADER_ROW Then
|
||
MsgBox "No data found in worksheet!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
Application.StatusBar = "Reading data (" & lastRow & " rows)..."
|
||
|
||
' Build data range
|
||
Set rngData = BuildSafeRange(wsData, HEADER_ROW, lastRow, CUSTOM_COLUMNS)
|
||
|
||
If rngData Is Nothing Then
|
||
MsgBox "Failed to create data range. Please check column references.", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
If rngData.Rows.Count <= 1 Then
|
||
MsgBox "No data rows found after applying column filters.", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
End With
|
||
|
||
' Delete existing worksheet
|
||
Application.DisplayAlerts = False
|
||
On Error Resume Next
|
||
ThisWorkbook.Worksheets(PIVOT_SHEET_NAME).Delete
|
||
On Error GoTo ErrorHandler
|
||
Application.DisplayAlerts = True
|
||
|
||
' Create new worksheet
|
||
Application.StatusBar = "Creating pivot table..."
|
||
Set wsPivot = ThisWorkbook.Worksheets.Add
|
||
wsPivot.Name = PIVOT_SHEET_NAME
|
||
|
||
' Create pivot table (now uses DATA_FIELDS setting)
|
||
CreatePivotTableWithDataFields wsPivot, rngData, ROW_FIELD_COLUMN, DATA_FIELDS, wsData, HEADER_ROW
|
||
|
||
' Apply formatting
|
||
Application.StatusBar = "Applying formatting..."
|
||
With wsPivot
|
||
.Range("A1").Value = "Material Summary"
|
||
.Range("A1").Font.Bold = True
|
||
.Range("A1").Font.Size = 14
|
||
|
||
If AUTO_ADJUST_COLUMNS Then
|
||
.Columns.AutoFit
|
||
End If
|
||
|
||
.Range("A2").Value = "Created: " & Now()
|
||
.Range("A2").Font.Italic = True
|
||
.Range("A2").Font.Color = RGB(100, 100, 100)
|
||
End With
|
||
|
||
' Show results
|
||
Application.StatusBar = False
|
||
|
||
If SHOW_PERFORMANCE_STATS Then
|
||
Dim endTime As Double, elapsedTime As Double
|
||
endTime = Timer
|
||
elapsedTime = endTime - startTime
|
||
|
||
MsgBox "Pivot table created successfully!" & vbCrLf & _
|
||
"Data rows: " & (lastRow - HEADER_ROW) & vbCrLf & _
|
||
"Columns included: " & (UBound(CUSTOM_COLUMNS) - LBound(CUSTOM_COLUMNS) + 1) & vbCrLf & _
|
||
"Data fields: " & Join(DATA_FIELDS, ", ") & vbCrLf & _
|
||
"Processing time: " & Format(elapsedTime, "0.00") & " seconds", vbInformation
|
||
Else
|
||
MsgBox "Pivot table created successfully!", vbInformation
|
||
End If
|
||
|
||
CleanUp:
|
||
Application.ScreenUpdating = True
|
||
Application.Calculation = xlCalculationAutomatic
|
||
Application.EnableEvents = True
|
||
Application.StatusBar = False
|
||
Exit Sub
|
||
|
||
ErrorHandler:
|
||
MsgBox "Error " & Err.Number & ": " & Err.Description & vbCrLf & _
|
||
"Please check your configuration settings and data structure.", vbCritical
|
||
GoTo CleanUp
|
||
End Sub
|
||
|
||
' =========================================================================
|
||
' Fixed pivot table creation function - Now correctly uses DATA_FIELDS setting
|
||
' =========================================================================
|
||
|
||
Sub CreatePivotTableWithDataFields(wsPivot As Worksheet, rngData As Range, rowFieldCol As String, dataFields As Variant, wsData As Worksheet, headerRow As Long)
|
||
' Purpose: Create pivot table using configured data fields
|
||
|
||
On Error GoTo ErrorHandler
|
||
|
||
Dim pc As PivotCache, pt As PivotTable
|
||
Dim i As Long, fieldIndex As Long
|
||
Dim rowFieldTitle As String, dataFieldTitle As String
|
||
Dim colIndex As Long
|
||
|
||
' Validate data range
|
||
If rngData Is Nothing Then
|
||
MsgBox "Data range is empty. Cannot create pivot table.", vbExclamation
|
||
Exit Sub
|
||
End If
|
||
|
||
If rngData.Rows.Count <= 1 Then
|
||
MsgBox "Not enough data rows for pivot table.", vbExclamation
|
||
Exit Sub
|
||
End If
|
||
|
||
' Create pivot cache
|
||
Set pc = ThisWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:=rngData)
|
||
|
||
' Create pivot table
|
||
Set pt = pc.CreatePivotTable(TableDestination:=wsPivot.Range("A3"), tableName:="CustomPivot")
|
||
|
||
With pt
|
||
' Add row field (using configured row field column)
|
||
colIndex = GetColumnIndex(rowFieldCol)
|
||
If colIndex > 0 Then
|
||
rowFieldTitle = wsData.Cells(headerRow, colIndex).Value
|
||
.PivotFields(rowFieldTitle).Orientation = xlRowField
|
||
Else
|
||
' If row field is invalid, use first column as default row field
|
||
.PivotFields(1).Orientation = xlRowField
|
||
End If
|
||
|
||
' Add data fields (using configured data fields)
|
||
For i = LBound(dataFields) To UBound(dataFields)
|
||
colIndex = GetColumnIndex(dataFields(i))
|
||
If colIndex > 0 Then
|
||
dataFieldTitle = wsData.Cells(headerRow, colIndex).Value
|
||
On Error Resume Next ' Skip fields that cannot be added
|
||
.AddDataField .PivotFields(dataFieldTitle), "Sum of " & dataFieldTitle, xlSum
|
||
On Error GoTo ErrorHandler
|
||
End If
|
||
Next i
|
||
|
||
' If no data fields were successfully added, add all numeric fields as fallback
|
||
If .dataFields.Count = 0 Then
|
||
MsgBox "Configured data fields are invalid. Adding all numeric fields.", vbExclamation
|
||
For i = 2 To .PivotFields.Count
|
||
On Error Resume Next
|
||
.AddDataField .PivotFields(i), "Sum of " & .PivotFields(i).Name, xlSum
|
||
On Error GoTo ErrorHandler
|
||
Next i
|
||
End If
|
||
|
||
' Apply style
|
||
On Error Resume Next
|
||
.TableStyle2 = "PivotStyleLight16"
|
||
.RowAxisLayout xlTabularRow
|
||
On Error GoTo ErrorHandler
|
||
End With
|
||
|
||
Exit Sub
|
||
|
||
ErrorHandler:
|
||
MsgBox "Error creating pivot table: " & Err.Description, vbExclamation
|
||
End Sub
|
||
|
||
' =========================================================================
|
||
' Helper functions
|
||
' =========================================================================
|
||
|
||
Function BuildSafeRange(ws As Worksheet, headerRow As Long, lastRow As Long, customCols As Variant) As Range
|
||
' Purpose: Safely build data range
|
||
|
||
On Error GoTo ErrorHandler
|
||
|
||
Dim firstCol As Long, lastCol As Long
|
||
Dim colIndex As Long, i As Long
|
||
|
||
' Validate custom column references
|
||
For i = LBound(customCols) To UBound(customCols)
|
||
colIndex = GetColumnIndex(customCols(i))
|
||
If colIndex < 1 Or colIndex > ws.Columns.Count Then
|
||
MsgBox "Invalid column reference: " & customCols(i), vbExclamation
|
||
Set BuildSafeRange = Nothing
|
||
Exit Function
|
||
End If
|
||
Next i
|
||
|
||
firstCol = GetColumnIndex(customCols(LBound(customCols)))
|
||
lastCol = GetColumnIndex(customCols(UBound(customCols)))
|
||
|
||
If headerRow > lastRow Then
|
||
MsgBox "Header row is after last data row!", vbExclamation
|
||
Set BuildSafeRange = Nothing
|
||
Exit Function
|
||
End If
|
||
|
||
Set BuildSafeRange = ws.Range(ws.Cells(headerRow, firstCol), ws.Cells(lastRow, lastCol))
|
||
|
||
If BuildSafeRange Is Nothing Then
|
||
MsgBox "Failed to create data range.", vbExclamation
|
||
Exit Function
|
||
End If
|
||
|
||
Exit Function
|
||
|
||
ErrorHandler:
|
||
MsgBox "Error in BuildSafeRange: " & Err.Description, vbExclamation
|
||
Set BuildSafeRange = Nothing
|
||
End Function
|
||
|
||
Function GetColumnIndex(col As Variant) As Long
|
||
' Purpose: Convert column letter to column index
|
||
|
||
On Error GoTo ErrorHandler
|
||
|
||
If VarType(col) = vbString Then
|
||
GetColumnIndex = Range(col & "1").Column
|
||
Else
|
||
GetColumnIndex = col
|
||
End If
|
||
|
||
Exit Function
|
||
|
||
ErrorHandler:
|
||
GetColumnIndex = 0
|
||
End Function
|
||
|
||
Function WorksheetExists(sheetName As String) As Boolean
|
||
' Purpose: Check if worksheet exists
|
||
|
||
On Error Resume Next
|
||
WorksheetExists = Not ThisWorkbook.Worksheets(sheetName) Is Nothing
|
||
On Error GoTo 0
|
||
End Function
|
||
|
||
' =========================================================================
|
||
' Diagnostic tools
|
||
' =========================================================================
|
||
|
||
Sub CheckDataFields()
|
||
' Purpose: Check if data field configuration is correct
|
||
|
||
Dim wsData As Worksheet
|
||
Dim dataField As Variant
|
||
Dim colIndex As Long
|
||
Dim result As String
|
||
|
||
Set wsData = ThisWorkbook.Worksheets("KCB")
|
||
|
||
result = "Data Fields Check:" & vbCrLf & vbCrLf
|
||
|
||
For Each dataField In Array("C", "E") ' Using configured DATA_FIELDS
|
||
colIndex = GetColumnIndex(dataField)
|
||
If colIndex > 0 Then
|
||
result = result & "Column " & dataField & ": Valid" & vbCrLf & _
|
||
" Index: " & colIndex & vbCrLf & _
|
||
" Title: '" & wsData.Cells(1, colIndex).Value & "'" & vbCrLf & vbCrLf
|
||
Else
|
||
result = result & "Column " & dataField & ": Invalid" & vbCrLf & vbCrLf
|
||
End If
|
||
Next dataField
|
||
|
||
MsgBox result, vbInformation, "Data Fields Check"
|
||
End Sub
|
||
|
||
' =========================================================================
|
||
' Simple version - Use if above code still has issues
|
||
' =========================================================================
|
||
|
||
Sub SimplePivotTable()
|
||
' Very simple version to avoid 1004 errors
|
||
|
||
Application.ScreenUpdating = False
|
||
Application.Calculation = xlCalculationManual
|
||
Application.EnableEvents = False
|
||
|
||
On Error GoTo ErrorHandler
|
||
|
||
Dim wsData As Worksheet, wsPivot As Worksheet
|
||
Dim rngData As Range
|
||
Dim lastRow As Long
|
||
|
||
' Configuration - modify as needed
|
||
Const SOURCE_SHEET As String = "KCB"
|
||
Const PIVOT_SHEET_NAME As String = "SimpleSummary"
|
||
|
||
' Check if source exists
|
||
If Not WorksheetExists(SOURCE_SHEET) Then
|
||
MsgBox "Worksheet '" & SOURCE_SHEET & "' not found!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
Set wsData = ThisWorkbook.Worksheets(SOURCE_SHEET)
|
||
|
||
' Find last row in column B (material column)
|
||
lastRow = wsData.Cells(wsData.Rows.Count, "B").End(xlUp).Row
|
||
|
||
If lastRow <= 1 Then
|
||
MsgBox "No data found!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
' Use simple range (columns B to I)
|
||
Set rngData = wsData.Range("B1:I" & lastRow)
|
||
|
||
' Delete existing sheet
|
||
Application.DisplayAlerts = False
|
||
On Error Resume Next
|
||
ThisWorkbook.Worksheets(PIVOT_SHEET_NAME).Delete
|
||
On Error GoTo ErrorHandler
|
||
Application.DisplayAlerts = True
|
||
|
||
' Create pivot table using simple method
|
||
Set wsPivot = ThisWorkbook.Worksheets.Add
|
||
wsPivot.Name = PIVOT_SHEET_NAME
|
||
|
||
' This method is less likely to cause 1004 errors
|
||
wsPivot.Activate
|
||
Set rngData = wsData.Range("B1:I" & lastRow)
|
||
|
||
' Use PivotTableWizard to create pivot table
|
||
Set pt = wsPivot.PivotTableWizard(SourceType:=xlDatabase, _
|
||
SourceData:=rngData, _
|
||
TableDestination:=wsPivot.Range("A3"))
|
||
|
||
' Simple configuration
|
||
With pt
|
||
.PivotFields(wsData.Range("B1").Value).Orientation = xlRowField
|
||
.PivotFields(wsData.Range("E1").Value).Orientation = xlDataField
|
||
.PivotFields(wsData.Range("H1").Value).Orientation = xlDataField
|
||
.PivotFields(wsData.Range("I1").Value).Orientation = xlDataField
|
||
End With
|
||
|
||
' Simple formatting
|
||
wsPivot.Range("A1").Value = "Simple Material Summary"
|
||
wsPivot.Columns.AutoFit
|
||
|
||
MsgBox "Simple pivot table created successfully!", vbInformation
|
||
|
||
CleanUp:
|
||
Application.ScreenUpdating = True
|
||
Application.Calculation = xlCalculationAutomatic
|
||
Application.EnableEvents = True
|
||
Exit Sub
|
||
|
||
ErrorHandler:
|
||
MsgBox "Error " & Err.Number & ": " & Err.Description, vbCritical
|
||
GoTo CleanUp
|
||
End Sub
|
||
|
||
Sub CheckDataRange()
|
||
' Purpose: Check data range to help diagnose issues
|
||
|
||
Dim ws As Worksheet
|
||
Dim rng As Range
|
||
Dim lastRow As Long, lastCol As Long
|
||
|
||
Set ws = ThisWorkbook.Worksheets("KCB")
|
||
|
||
lastRow = ws.Cells(ws.Rows.Count, "B").End(xlUp).Row
|
||
lastCol = ws.Cells(1, ws.Columns.Count).End(xlToLeft).Column
|
||
|
||
MsgBox "Data Check:" & vbCrLf & _
|
||
"Last row: " & lastRow & vbCrLf & _
|
||
"Last column: " & lastCol & vbCrLf & _
|
||
"Header row data: " & ws.Range("A1").Value & "..." & ws.Cells(1, lastCol).Value, _
|
||
vbInformation, "Data Diagnostic"
|
||
|
||
' Show a sample of the data
|
||
If lastRow > 1 Then
|
||
Set rng = ws.Range("A1").Resize(2, lastCol)
|
||
rng.Select
|
||
End If
|
||
End Sub
|
||
```
|
||
|
||
---
|
||
|
||
## Module21.bas - MKey()
|
||
|
||
```vba
|
||
Sub MKey()
|
||
' Declare variables
|
||
Dim wsBOM As Worksheet
|
||
Dim wsTarget As Worksheet
|
||
Dim dict As Object
|
||
Dim lastRowBOM As Long
|
||
Dim lastRowTarget As Long
|
||
Dim i As Long
|
||
Dim primaryKey As String
|
||
Dim model As String
|
||
Dim modelKey As String
|
||
Dim dataArray As Variant
|
||
Dim resultArray() As String
|
||
Dim modelArray() As String
|
||
Dim j As Long
|
||
Dim isDuplicate As Boolean
|
||
Dim foundKeys As Object
|
||
Dim originalColumnWidth As Double
|
||
|
||
' Save original column B width
|
||
On Error Resume Next
|
||
originalColumnWidth = Worksheets("0000").Columns("B").Width
|
||
On Error GoTo 0
|
||
|
||
' Turn off screen updating and calculation for speed
|
||
Application.ScreenUpdating = False
|
||
Application.Calculation = xlCalculationManual
|
||
|
||
On Error GoTo ErrorHandler
|
||
|
||
' Set worksheets
|
||
On Error Resume Next
|
||
Set wsBOM = Worksheets("BOM_BUFFER")
|
||
Set wsTarget = Worksheets("0000")
|
||
On Error GoTo ErrorHandler
|
||
|
||
If wsBOM Is Nothing Then
|
||
MsgBox "Worksheet 'BOM' not found!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
If wsTarget Is Nothing Then
|
||
MsgBox "Worksheet '0000' not found!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
' Create dictionaries for faster lookup
|
||
Set dict = CreateObject("Scripting.Dictionary")
|
||
Set foundKeys = CreateObject("Scripting.Dictionary")
|
||
|
||
' Get data from BOM sheet (A=model, B=primary key) starting from row 3
|
||
lastRowBOM = wsBOM.Cells(wsBOM.Rows.Count, "A").End(xlUp).Row
|
||
If lastRowBOM < 3 Then
|
||
MsgBox "No data found in BOM sheet (data should start from row 3)!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
dataArray = wsBOM.Range("A3:B" & lastRowBOM).Value
|
||
|
||
' Build dictionary from BOM data (group models by primary key)
|
||
For i = 1 To UBound(dataArray, 1)
|
||
model = Trim(CStr(dataArray(i, 1))) ' Column A - model data
|
||
primaryKey = Trim(CStr(dataArray(i, 2))) ' Column B - primary key
|
||
|
||
' Validate data
|
||
If primaryKey <> "" And model <> "" Then
|
||
' MODIFIED: For models starting with "781" - keep first 9 characters
|
||
If Left(model, 3) = "781" Then
|
||
If Len(model) >= 9 Then
|
||
modelKey = Left(model, 9) ' Keep first 9 characters for 781 starting models
|
||
Else
|
||
modelKey = model ' If less than 9 chars, keep original
|
||
End If
|
||
Else
|
||
' Extract first 7 characters for other models
|
||
If Len(model) >= 7 Then
|
||
modelKey = Left(model, 7)
|
||
Else
|
||
modelKey = model
|
||
End If
|
||
End If
|
||
|
||
' Process by primary key
|
||
If dict.exists(primaryKey) Then
|
||
' Split existing models and check for duplicates
|
||
modelArray = Split(dict(primaryKey), ",")
|
||
isDuplicate = False
|
||
|
||
' Check if modelKey already exists for this primary key
|
||
For j = 0 To UBound(modelArray)
|
||
If Trim(modelArray(j)) = modelKey Then
|
||
isDuplicate = True
|
||
Exit For
|
||
End If
|
||
Next j
|
||
|
||
' Add only if not duplicate
|
||
If Not isDuplicate Then
|
||
dict(primaryKey) = dict(primaryKey) & "," & modelKey
|
||
End If
|
||
Else
|
||
' First entry for this primary key
|
||
dict(primaryKey) = modelKey
|
||
End If
|
||
End If
|
||
Next i
|
||
|
||
' Get target range from 0000 sheet (column A = primary keys) starting from row 3
|
||
lastRowTarget = wsTarget.Cells(wsTarget.Rows.Count, "A").End(xlUp).Row
|
||
If lastRowTarget < 3 Then
|
||
MsgBox "No primary keys found in 0000 sheet (data should start from row 3)!", vbExclamation
|
||
GoTo CleanUp
|
||
End If
|
||
|
||
' Prepare result array for column B starting from row 3
|
||
ReDim resultArray(1 To lastRowTarget - 2, 1 To 1)
|
||
|
||
' Match models to primary keys - using direct cell reference instead of range variable
|
||
For i = 3 To lastRowTarget
|
||
primaryKey = Trim(CStr(wsTarget.Cells(i, 1).Value))
|
||
|
||
If primaryKey <> "" Then
|
||
If dict.exists(primaryKey) Then
|
||
resultArray(i - 2, 1) = Replace(dict(primaryKey), ",", ", ")
|
||
foundKeys(primaryKey) = True
|
||
Else
|
||
resultArray(i - 2, 1) = "Not Found"
|
||
End If
|
||
Else
|
||
resultArray(i - 2, 1) = ""
|
||
End If
|
||
Next i
|
||
|
||
' Insert results into column B of 0000 sheet starting from row 3
|
||
wsTarget.Range("B3:B" & lastRowTarget).Value = resultArray
|
||
|
||
' Restore original column width instead of auto-fit
|
||
wsTarget.Columns("B").Width = originalColumnWidth
|
||
|
||
' Show |