' ============================================================ ' Module Name: Tukin_C1 ' Module Desc: Commuter allowance editing sheet (no CSV import) ' Module Methods: ' - Tukin_ValidateRow ' - FillTransportFromM1KukanD ' - FillDepartureFromM1KukanD ' - FillArrivalFromM1KukanD ' - FillKukanFromM1 ' - FillKanshuFromM2 ' - FillCodeFromM2 ' - CreateAddress1Dropdown ' - FillZ1Dropdown ' ============================================================ ' ====== (Tukin_C1) ======= ' Commuter allowance editing sheet ' No CSV import - direct editing only ' ============================================================ ' Column arrays for 4 kukan sections ' ============================================================ Const CSHAINNO_COL As String = "C" Const ADDRESS1_COL As String = "I" Const ADDRESS2_COL As String = "J" Private Function KUKAN_CODE_COLS() As Variant KUKAN_CODE_COLS = Array(19, 26, 33, 40) ' S, Z, AG, AN End Function Private Function KUKAN_TRANSPORT_COLS() As Variant KUKAN_TRANSPORT_COLS = Array(20, 27, 34, 41) ' T, AA, AH, AO End Function Private Function KUKAN_STATION_COLS() As Variant KUKAN_STATION_COLS = Array(21, 28, 35, 42) ' U, AB, AI, AP End Function Private Function KUKAN_ARRIVAL_COLS() As Variant KUKAN_ARRIVAL_COLS = Array(22, 29, 36, 43) ' V, AC, AJ, AQ End Function Private Function KUKAN_TICKET_COLS() As Variant KUKAN_TICKET_COLS = Array(23, 30, 37, 44) ' W, AD, AK, AR End Function Private Function KUKAN_CODE2_COLS() As Variant KUKAN_CODE2_COLS = Array(24, 31, 38, 45) ' X, AE, AL, AS End Function Private Function KUKAN_START_DAY_COLS() As Variant KUKAN_START_DAY_COLS = Array(25, 32, 39, 46) ' Y, AF, AM, AT End Function Private Function DATE_COLS() As Variant DATE_COLS = Array(4, 5, 6, 25, 32, 39, 46, 51, 54) ' D, E, F, Y, AF, AM, AT, AY, BB End Function Private Function NUMBER_COLS() As Variant NUMBER_COLS = Array("L", "P", "Q", "R") End Function ' ============================================================ ' Helper: Get index by value, return -1 if not found ' ============================================================ Private Function GetIdx(val As Long, arr As Variant) As Long Dim i As Long For i = LBound(arr) To UBound(arr) If arr(i) = val Then GetIdx = i Exit Function End If Next i GetIdx = -1 End Function ' ============================================================ ' Event Handlers ' ============================================================ Private Sub Worksheet_Change(ByVal Target As Range) Dim HasHeaderEdit As Boolean: HasHeaderEdit = CheckHeaderEdit(Me, Target) If HasHeaderEdit = True Then Exit Sub Dim watchArea As Range With Me Set watchArea = Union( _ .Columns("C"), _ .Columns("D"), _ .Columns("E"), _ .Columns("F"), _ .Columns("G"), _ .Columns("I"), _ .Columns("S:W"), _ .Columns("Z:AD"), _ .Columns("AG:AK"), _ .Columns("AN:AR"), _ .Columns("BB") _ ) End With Dim intersectRng As Range: Set intersectRng = Application.Intersect(Target, watchArea) If intersectRng Is Nothing Then Exit Sub If Target.Row < 8 Then Exit Sub Dim idx As Long Application.EnableEvents = False On Error GoTo Finally ' === 3. rebuild dropdown list === Call RebuildDropdownsForTarget(Target) ' === Column C changes === If Target.Column = 3 Then Dim cell As Range For Each cell In Target Dim cshainno As String: cshainno = Trim(cell.Value) If cshainno = "" Then Call ClearRowData(cell.Row) Else Call CreateAddress1Dropdown(cell.Row, cshainno) End If Next End If ' auto fill G column [todoke biko] If Target.Column = 7 Then Dim cellG As Range For Each cellG In Target Dim todoke As String: todoke = Trim(cellG.Value) If todoke <> "" Then Dim z4Cache As Object: Set z4Cache = GetCache("Z4") Dim todokeCde As String: todokeCde = GetCode(todoke) If z4Cache.Exists(todokeCde) Then Dim cellH As Range: Set cellH = Me.Cells(cellG.Row, 8) cellH.Value = z4Cache(todokeCde)(0) End If End If Next End If ' === Column I changes === If Target.Column = 9 Then Dim cellI As Range For Each cellI In Target Call CreateAddress2Dropdown(cellI.Row) Next End If ' === Date columns changes === idx = GetIdx(Target.Column, DATE_COLS) If idx >= 0 Then Dim cellDate As Range For Each cellDate In Target If Trim(cellDate.Value) <> "" Then Dim formattedDate As String: formattedDate = FormatDateInput(cellDate.Value) cellDate.Value = FormatDateInput(formattedDate) If cellDate.Column = 5 Then Dim fCell As Range: Set fCell = Me.Cells(cellDate.Row, 6) If Trim(fCell.Value) = "" Then fCell.Value = formattedDate End If End If End If Next End If ' === Transport column changes (T, AA, AH, AO) === idx = GetIdx(Target.Column, KUKAN_TRANSPORT_COLS) If idx >= 0 Then Dim cellT As Range For Each cellT In Target Me.Cells(cellT.Row, KUKAN_STATION_COLS(idx)).ClearContents Me.Cells(cellT.Row, KUKAN_ARRIVAL_COLS(idx)).ClearContents If Trim(cellT.Value) <> "" Then Call CreateFromStationDropdown(cellT.Row, KUKAN_TRANSPORT_COLS(idx), KUKAN_STATION_COLS(idx)) End If Next End If ' === Station column changes (U, AB, AI, AP) === idx = GetIdx(Target.Column, KUKAN_STATION_COLS) If idx >= 0 Then Dim cellU As Range For Each cellU In Target ' Clear arrival value first Me.Cells(cellU.Row, KUKAN_ARRIVAL_COLS(idx)).ClearContents If Trim(cellU.Value) <> "" Then Call CreateToStationDropdown(cellU.Row, KUKAN_TRANSPORT_COLS(idx), KUKAN_STATION_COLS(idx), KUKAN_ARRIVAL_COLS(idx)) End If Next End If ' === Arrival column changes (V, AC, AJ, AQ) === idx = GetIdx(Target.Column, KUKAN_ARRIVAL_COLS) If idx >= 0 Then Dim cellV As Range For Each cellV In Target If Trim(cellV.Value) <> "" Then ' Reverse lookup: find kukan code by transport + from + to Dim foundCode As String foundCode = FindKukanCodeByStation(cellV.Row, KUKAN_TRANSPORT_COLS(idx), KUKAN_STATION_COLS(idx), KUKAN_ARRIVAL_COLS(idx)) If foundCode <> "" Then Me.Cells(cellV.Row, KUKAN_CODE_COLS(idx)).Value = foundCode Call CreateKenshuDropdown(cellV.Row, idx, foundCode) End If End If Next End If ' === Kukan code column changes (S, Z, AG, AN) === idx = GetIdx(Target.Column, KUKAN_CODE_COLS) If idx >= 0 Then Dim cellK As Range For Each cellK In Target Call FillKukanFromM1(cellK.Row, idx) Next End If ' === Ticket column changes (W, AD, AK, AR) === idx = GetIdx(Target.Column, KUKAN_TICKET_COLS) If idx >= 0 Then Dim cellTi As Range For Each cellTi In Target ' Clear old code first Dim code2Col As Long: code2Col = KUKAN_CODE2_COLS(idx) Me.Cells(cellTi.Row, code2Col).ClearContents Me.Cells(cellTi.Row, code2Col).Validation.Delete Call CreateM2CodeDropdown(cellTi.Row, KUKAN_CODE_COLS(idx), KUKAN_TICKET_COLS(idx), code2Col) Next End If Finally: Application.EnableEvents = True ' End Sub ' Prevent insert/delete row in header area Private Sub Worksheet_BeforeRightClick(ByVal Target As Range, Cancel As Boolean) Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig() Dim sheetConf As Object: Set sheetConf = sheetConfDict(Me.CodeName) Dim filterRow As Long: filterRow = sheetConf("FilterRow") If Target.Row < filterRow + 1 Then Cancel = True MsgBox "Cannot insert or delete row in header area.", vbExclamation End If End Sub Private Sub RebuildDropdownsForTarget(ByVal Target As Range) If Target Is Nothing Then Exit Sub Dim cell As Range Dim processedRows As Object Set processedRows = CreateObject("Scripting.Dictionary") For Each cell In Target Dim r As Long r = cell.Row If Not processedRows.Exists(r) Then processedRows(r) = True Dim colLetter As String colLetter = Split(Me.Cells(1, cell.Column).Address(True, False), "$")(0) Dim dropdowns As Variant dropdowns = Array( _ Array("T", "BuildTransportList"), _ Array("AA", "BuildTransportList"), _ Array("AH", "BuildTransportList"), _ Array("AO", "BuildTransportList"), _ Array("G", "BuildTodokeList"), _ Array("M", "BuildOufukuList"), _ Array("N", "BuildKoutaiList"), _ Array("AU", "BuildKetteiList"), _ Array("AW", "BuildHigaitouList"), _ Array("AX", "BuildMonthAmountKbnList"), _ Array("BC", "BuildKanshokuList") _ ) Dim i As Long For i = LBound(dropdowns) To UBound(dropdowns) If colLetter <> dropdowns(i)(0) Then With Me.Cells(r, dropdowns(i)(0)).Validation .Delete .Add Type:=xlValidateList, Formula1:=Application.Run(dropdowns(i)(1)) .IgnoreBlank = True .InCellDropdown = True End With End If Next i End If NextCell: Next cell End Sub ' Fill kukan info from M1 cache (key: kukan code, value: 7 elements) Private Sub FillKukanFromM1(ByVal rowNum As Long, ByVal idx As Long) Dim m1Cache As Object: Set m1Cache = GetCache("M1") Dim codeCol As Long: codeCol = KUKAN_CODE_COLS(idx) Dim transportCol As Long: transportCol = KUKAN_TRANSPORT_COLS(idx) Dim stationCol As Long: stationCol = KUKAN_STATION_COLS(idx) Dim arrivalCol As Long: arrivalCol = KUKAN_ARRIVAL_COLS(idx) Dim ticketCol As Long: ticketCol = KUKAN_TICKET_COLS(idx) Dim code2Col As Long: code2Col = KUKAN_CODE2_COLS(idx) Dim startDayCol As Long: startDayCol = KUKAN_START_DAY_COLS(idx) Dim code As String: code = Trim(Me.Cells(rowNum, codeCol).Value) If code <> "" And m1Cache.Exists(code) Then Dim vals As Variant: vals = m1Cache(code) Me.Cells(rowNum, transportCol).Value = MakeSelect(vals(1), vals(2)) Me.Cells(rowNum, stationCol).Value = Trim(vals(3)) Me.Cells(rowNum, arrivalCol).Value = Trim(vals(4)) Call CreateKenshuDropdown(rowNum, idx, code) Else Me.Cells(rowNum, transportCol).ClearContents Me.Cells(rowNum, stationCol).ClearContents Me.Cells(rowNum, arrivalCol).ClearContents Me.Cells(rowNum, startDayCol).ClearContents Call ClearKukanValidation(rowNum, stationCol) Call ClearKukanValidation(rowNum, arrivalCol) Call ClearKukanValidation(rowNum, code2Col) End If Me.Cells(rowNum, ticketCol).ClearContents Me.Cells(rowNum, code2Col).ClearContents End Sub ' triggered by c clomun cshainno input ' when cshainno does not exist in o1, clear dropdownList and value ' when cshainno exist in o1, create dropdownList and value Private Sub CreateAddress1Dropdown(ByVal rowNum As Long, ByVal cshainno As String) Dim o1Cache As Object: Set o1Cache = GetCache("O1") Me.Range("I" & rowNum).Validation.Delete Me.Range("I" & rowNum).Value = "" Me.Range("J" & rowNum).Validation.Delete Me.Range("J" & rowNum).Value = "" ' Build dropdown list from O1 cache: get all E values for the C Dim dropdownList As String If o1Cache.Exists(cshainno) Then Dim innerDict As Object Set innerDict = o1Cache(cshainno) Dim eKey As Variant For Each eKey In innerDict.Keys If dropdownList = "" Then dropdownList = eKey Else dropdownList = dropdownList & "," & eKey End If Next eKey End If ' Create dropdown for I column address1 If dropdownList <> "" Then With Me.Range("I" & rowNum).Validation .Delete .Add Type:=xlValidateList, Formula1:=dropdownList .IgnoreBlank = True .InCellDropdown = True .InputTitle = "" .InputMessage = "" End With End If End Sub ' triggered by address1 select O1 cache Private Sub CreateAddress2Dropdown(ByVal rowNum As Long) ' Clear address2 contents Me.Range(ADDRESS2_COL & rowNum).Validation.Delete Me.Range(ADDRESS2_COL & rowNum).Value = "" ' obtain cshainno, address1, o1Cache Dim o1Cache As Object: Set o1Cache = GetCache("O1") Dim cshainno As String: cshainno = Trim(Me.Cells(rowNum, CSHAINNO_COL).Value) Dim address1 As String: address1 = Trim(Me.Cells(rowNum, ADDRESS1_COL).Value) If cshainno = "" OR address1 = "" Then Exit Sub End If ' Build dropdown list from O1 cache Dim dropdownList As String If o1Cache.Exists(cshainno) Then Dim innerDict As Object Set innerDict = o1Cache(cshainno) If innerDict.Exists(address1) Then Dim addr2Dict As Object Set addr2Dict = innerDict(address1) Dim addr2Key As Variant For Each addr2Key In addr2Dict.Keys If dropdownList = "" Then dropdownList = addr2Key Else dropdownList = dropdownList & "," & addr2Key End If Next addr2Key End If End If ' Create dropdown for J column If dropdownList <> "" Then With Me.Range("J" & rowNum).Validation .Delete .Add Type:=xlValidateList, Formula1:=dropdownList .IgnoreBlank = True .InCellDropdown = True .InputTitle = "" .InputMessage = "" End With End If End Sub ' Create station from dropdown from M1_KukanD cache Private Sub CreateFromStationDropdown(ByVal rowNum As Long, ByVal transportCol As Long, ByVal stationCol As Long) Dim m1KukanDCache As Object: Set m1KukanDCache = GetCache("M1KukanDCache") Dim transport As String: transport = GetCode(Me.Cells(rowNum, transportCol).Value) If transport = "" Then Exit Sub ' Build dropdown list from M1_KukanD cache: get all F values for the transport (D) Dim dropdownList As String If m1KukanDCache.Exists(transport) Then Dim innerDict As Object: Set innerDict = m1KukanDCache(transport) Dim fValue As Variant For Each fValue In innerDict.Keys If dropdownList = "" Then dropdownList = fValue Else dropdownList = dropdownList & "," & fValue End If Next fValue End If If dropdownList <> "" Then With Me.Cells(rowNum, stationCol).Validation .Delete .Add Type:=xlValidateList, Formula1:=dropdownList .IgnoreBlank = True .InCellDropdown = True End With End If End Sub ' Create Kenshu dropdown from ' Structure: { D: { F: [G] } } Private Sub CreateKenshuDropdown(ByVal rowNum As Long, ByVal idx As Long, ByVal kukanCode As String) Dim kenshuList As Object: Set kenshuList = GetCache("kenshuList") Dim m2Cache As Object: Set m2Cache = GetCache("M2") Dim ticketCol As Long: ticketCol = KUKAN_TICKET_COLS(idx) Me.Cells(rowNum, ticketCol).ClearContents Call ClearKukanValidation(rowNum, ticketCol) Dim kanshuDict As Object if m2Cache.Exists(kukanCode) Then Set kanshuDict = m2Cache(kukanCode) End If Dim dropdownList As String: dropdownList = MakeSelect("0", kenshuList("0")(0)) If Not kanshuDict Is Nothing Then Dim key As Variant For Each key In kenshuList.Keys If kanshuDict.Exists(key) Then dropdownList = dropdownList & "," & MakeSelect(key, kenshuList(key)(0)) End If Next key End If With Me.Cells(rowNum, ticketCol).Validation .Delete .Add Type:=xlValidateList, Formula1:=dropdownList .IgnoreBlank = True .InCellDropdown = True End With End Sub ' Create destination dropdown from M1_KukanD cache ' Structure: { D: { F: [G] } } Private Sub CreateToStationDropdown(ByVal rowNum As Long, ByVal transportCol As Long, ByVal stationFromCol As Long, ByVal stationToCol As Long) Dim m1KukanDCache As Object: Set m1KukanDCache = GetCache("M1KukanDCache") Dim transport As String: transport = GetCode(Me.Cells(rowNum, transportCol).Value) Dim stationFrom As String: stationFrom = GetCode(Me.Cells(rowNum, stationFromCol).Value) If transport = "" Or stationFrom = "" Then Exit Sub ' Build dropdown list from M1_KukanD cache Dim dropdownList As String If m1KukanDCache.Exists(transport) Then Dim innerDict As Object: Set innerDict = m1KukanDCache(transport) If innerDict.Exists(stationFrom) Then Dim arr As Object: Set arr = innerDict(stationFrom) Dim gValue As Variant For Each gValue In arr.Keys If dropdownList = "" Then dropdownList = gValue Else dropdownList = dropdownList & "," & gValue End If Next gValue End If End If If dropdownList <> "" Then With Me.Cells(rowNum, stationToCol).Validation .Delete .Add Type:=xlValidateList, Formula1:=dropdownList .IgnoreBlank = True .InCellDropdown = True End With End If End Sub ' Find kukan code by transport + station_from + station_to (reverse lookup) Private Function FindKukanCodeByStation(ByVal rowNum As Long, ByVal transportCol As Long, ByVal stationFromCol As Long, ByVal stationToCol As Long) As String Dim m1Cache As Object: Set m1Cache = GetCache("M1") Dim transportKbn As String: transportKbn = GetCode(Trim(Me.Cells(rowNum, transportCol).Value)) Dim stationFrom As String: stationFrom = Trim(Me.Cells(rowNum, stationFromCol).Value) Dim stationTo As String: stationTo = Trim(Me.Cells(rowNum, stationToCol).Value) If transportKbn = "" Or stationFrom = "" Or stationTo = "" Then FindKukanCodeByStation = "" Exit Function End If Dim code As Variant For Each code In m1Cache.Keys Dim vals As Variant: vals = m1Cache(code) ' vals(1) = D列, vals(3) = F列, vals(4) = G列 If vals(1) = transportKbn And vals(3) = stationFrom And vals(4) = stationTo Then FindKukanCodeByStation = code Exit Function End If Next code FindKukanCodeByStation = "" End Function ' Clear validation for kukan columns Private Sub ClearKukanValidation(ByVal rowNum As Long, ByVal col As Long) Me.Cells(rowNum, col).Validation.Delete End Sub ' Create dropdown from M2 cache: get code (J) list for kukanCode + kanshu Private Sub CreateM2CodeDropdown(ByVal rowNum As Long, ByVal kukanCodeCol As Long, ByVal kanshuCol As Long, ByVal codeCol As Long) Dim m2Cache As Object: Set m2Cache = GetCache("M2") Dim kukanCode As String: kukanCode = Trim(Me.Cells(rowNum, kukanCodeCol).Value) Dim kanshuStr As String: kanshuStr = Trim(Me.Cells(rowNum, kanshuCol).Value) If kukanCode = "" Or kanshuStr = "" Then Exit Sub ' Build dropdown list: get all code for kukanCode + kanshuStr Dim dropdownList As String If m2Cache.Exists(kukanCode) Then Dim innerDict As Object: Set innerDict = m2Cache(kukanCode) Dim kanshu As String: kanshu = GetCode(kanshuStr) If innerDict.Exists(kanshu) Then Dim innermostDict As Object: Set innermostDict = innerDict(kanshu) Dim code As Variant For Each code In innermostDict.Keys If dropdownList = "" Then dropdownList = MakeSelect(code, innermostDict(code)) Else dropdownList = dropdownList & "," & code End If Next code End If End If If dropdownList <> "" Then With Me.Cells(rowNum, codeCol).Validation .Delete .Add Type:=xlValidateList, Formula1:=dropdownList .IgnoreBlank = True .InCellDropdown = True End With End If End Sub ' Clear row data and validation Private Sub ClearRowData(ByVal rowNum As Long) Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig() Dim sheetConf As Object: Set sheetConf = sheetConfDict(Me.CodeName) Dim startCol As String: startCol = sheetConf("StartCol") Dim endCol As String: endCol = sheetConf("EndCol") Dim errorCol As String: errorCol = sheetConf("ErrorCol") Me.Range(Me.Cells(rowNum, startCol), Me.Cells(rowNum, endCol)).ClearContents Me.Range(Me.Cells(rowNum, startCol), Me.Cells(rowNum, endCol)).Interior.Color = vbWhite Me.Cells(rowNum, errorCol).ClearContents Dim clearValidationCols As Variant clearValidationCols = Array("I", "J", "U", "V", "X", "AB", "AC", "AE", "AI", "AJ", "AL", "AP", "AQ", "AS") Dim col As Variant For Each col In clearValidationCols Me.Range(col & rowNum).Validation.Delete Next col End Sub ' Validation logic Public Sub Validate(ws As Worksheet, ByVal rowNum As Long, ByVal lastDataRow As Long) On Error GoTo ErrHandler Dim sheetConfDict As Object: Set sheetConfDict = GetSheetConfig() Dim sheetConf As Object: Set sheetConf = sheetConfDict(ws.CodeName) Dim startCol As String: startCol = sheetConf("StartCol") Dim endCol As String: endCol = sheetConf("EndCol") Dim errorCol As String: errorCol = sheetConf("ErrorCol") Dim clearRange As Range: Set clearRange = ws.Range(ws.Cells(rowNum, startCol), ws.Cells(rowNum, endCol)) clearRange.Interior.Color = vbWhite ' Required columns: C-G, K-N, AW Dim requiredCols As Variant requiredCols = Array("C", "D", "E", "F", "G", "L", "M", "N", "AW") Dim col As Variant For Each col In requiredCols If Trim(Me.Range(col & rowNum).Value & "") = "" Then Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E002", col & rowNum) Me.Range(col & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If Next col ' validate date Dim colIndex As Variant For Each colIndex In DATE_COLS() Dim cellDate As String: cellDate = Trim(Me.Cells(rowNum, colIndex).Value) If cellDate <> "" And Not IsDate(cellDate) Then Dim letter As String: letter = Split(Me.Cells(1, colIndex).Address, "$")(1) Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E001", letter & rowNum) Me.Range(letter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If Next colIndex ' validate number For Each col In NUMBER_COLS() Dim cellNumber As String: cellNumber = Trim(Me.Cells(rowNum, col).Value) If cellNumber <> "" And Not IsNumeric(cellNumber) Then Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E001", col & rowNum) Me.Range(col & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If Next col ' validate CodeSelect ' G column [todoke Cde] Dim ColG As String: ColG = "G" Dim z4Cache As Object: Set z4Cache = GetCache("Z4") Dim todokeCde As String: todokeCde = GetCode(Trim(Me.Cells(rowNum, ColG).Value)) If Not z4Cache.Exists(todokeCde) Then Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E001", ColG & rowNum) Me.Range(ColG & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If ' I column [address1 J column address2] Dim o1Cache As Object: Set o1Cache = GetCache("O1") Dim ColI As String: ColI = "I" Dim ColJ As String: ColJ = "J" Dim address1 As String: address1 = Trim(Me.Cells(rowNum, ColI).Value) Dim address2 As String: address2 = Trim(Me.Cells(rowNum, ColJ).Value) If address1 = "" Then If address2 <> "" Then Me.Cells(rowNum, errorCol).Value = ColJ & " column is invalid" Me.Range(ColJ & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If Else Dim empNo As String: empNo = Trim(Me.Cells(rowNum, 3).Value) If Not o1Cache.Exists(empNo) Then Me.Cells(rowNum, errorCol).Value = ColI & " column is invalid" Me.Range(ColI & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If Dim innerDict As Object: Set innerDict = o1Cache(empNo) If Not innerDict.Exists(address1) Then Me.Cells(rowNum, errorCol).Value = ColI & " column is invalid" Me.Range(ColI & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If Dim addr2Dict As Object: Set addr2Dict = innerDict(address1) If Not addr2Dict.Exists(address2) Then Me.Cells(rowNum, errorCol).Value = ColJ & " column is invalid" Me.Range(ColJ & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If End If ' K column Dim ColK As String: ColK = "K" If Trim(Me.Cells(rowNum, ColK).Value) <> "" Then Me.Cells(rowNum, errorCol).Value = ColK & " column can not be input" Me.Range(ColK & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If ' validate CodeSelect ' M column [oufuku] Dim ColM As String: ColM = "M" Dim oufukuList As Object: Set oufukuList = GetCache("oufukuList") Dim oufukuCde As String: oufukuCde = GetCode(Trim(Me.Cells(rowNum, ColM).Value)) If Not oufukuList.Exists(oufukuCde) Then Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E001", ColM & rowNum) Me.Range(ColM & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If ' validate CodeSelect ' N column [koutai] Dim ColN As String: ColN = "N" Dim koutaiList As Object: Set koutaiList = GetCache("koutaiList") Dim koutaiCde As String: koutaiCde = GetCode(Trim(Me.Cells(rowNum, ColN).Value)) If Not koutaiList.Exists(koutaiCde) Then Me.Cells(rowNum, errorCol).Value = ColN & " column is invalid" Me.Range(ColN & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If ' validate KUKAN_CODE_COLS (S, Z, AG, AN) and related columns Dim m1Cache As Object: Set m1Cache = GetCache("M1") Dim m2Cache As Object: Set m2Cache = GetCache("M2") Dim kukanCols As Variant kukanCols = Array(KUKAN_TRANSPORT_COLS, KUKAN_STATION_COLS, KUKAN_ARRIVAL_COLS, KUKAN_TICKET_COLS, KUKAN_CODE2_COLS, KUKAN_START_DAY_COLS) Dim kukanIdx As Long For kukanIdx = LBound(KUKAN_CODE_COLS) To UBound(KUKAN_CODE_COLS) Dim kukanCol As Long: kukanCol = KUKAN_CODE_COLS(kukanIdx) Dim kukanCode As String: kukanCode = Trim(Me.Cells(rowNum, kukanCol).Value) Dim kukanLetter As String: kukanLetter = Split(Me.Cells(1, kukanCol).Address, "$")(1) If kukanCode <> "" Then ' KUKAN_CODE has value, check if exists in m1Cache If Not m1Cache.Exists(kukanCode) Then Me.Cells(rowNum, errorCol).Value = kukanLetter & " column does not exist" Me.Range(kukanLetter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If ' Validate KUKAN_TICKET_COLS and KUKAN_CODE2_COLS Dim ticketCol As Long: ticketCol = KUKAN_TICKET_COLS(kukanIdx) Dim code2Col As Long: code2Col = KUKAN_CODE2_COLS(kukanIdx) Dim ticketVal As String: ticketVal = GetCode(Trim(Me.Cells(rowNum, ticketCol).Value)) Dim code2Val As String: code2Val = GetCode(Trim(Me.Cells(rowNum, code2Col).Value)) Dim ticketLetter As String: ticketLetter = Split(Me.Cells(1, ticketCol).Address, "$")(1) Dim code2Letter As String: code2Letter = Split(Me.Cells(1, code2Col).Address, "$")(1) If ticketVal = "" Then Me.Cells(rowNum, errorCol).Value = ticketLetter & " column must be input" Me.Range(ticketLetter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If If ticketVal = "0" Then If code2Val <> "" Then Me.Cells(rowNum, errorCol).Value = code2Letter & " column is invalid" Me.Range(code2Letter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If Else ' Check if ticket exists in m2Cache for this kukanCode Dim kanshuDict As Object If m2Cache.Exists(kukanCode) Then Set kanshuDict = m2Cache(kukanCode) If Not kanshuDict.Exists(ticketVal) Then Me.Cells(rowNum, errorCol).Value = ticketLetter & " column is invalid" Me.Range(ticketLetter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If ' If code2 also has value, verify it exists in m2Cache If code2Val = "" Then Me.Cells(rowNum, errorCol).Value = code2Letter & " column should be input" Me.Range(code2Letter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub Else Dim codeDict As Object: Set codeDict = kanshuDict(ticketVal) If Not codeDict.Exists(code2Val) Then Me.Cells(rowNum, errorCol).Value = code2Letter & " column is invalid" Me.Range(code2Letter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If End If End If End If Else ' KUKAN_CODE is empty, check that related columns are also empty Dim colGroup As Variant For Each colGroup In kukanCols Dim checkCol As Long: checkCol = colGroup(kukanIdx) Dim checkVal As String: checkVal = Trim(Me.Cells(rowNum, checkCol).Value) If checkVal <> "" Then Dim checkLetter As String: checkLetter = Split(Me.Cells(1, checkCol).Address, "$")(1) Me.Cells(rowNum, errorCol).Value = checkLetter & " column requires " & kukanLetter & " column" Me.Range(checkLetter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If Next colGroup End If Next kukanIdx ' Validate KUKAN_CODE_COLS for duplicates (non-empty only) Dim kukanCodes As Object: Set kukanCodes = CreateObject("Scripting.Dictionary") For kukanIdx = LBound(KUKAN_CODE_COLS) To UBound(KUKAN_CODE_COLS) kukanCol = KUKAN_CODE_COLS(kukanIdx) kukanCode = Trim(Me.Cells(rowNum, kukanCol).Value) If kukanCode <> "" Then If kukanCodes.Exists(kukanCode) Then kukanLetter = Split(Me.Cells(1, kukanCol).Address, "$")(1) Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E003", kukanLetter & rowNum) Me.Range(kukanLetter & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub Else kukanCodes.Add kukanCode, True End If End If Next kukanIdx ' Validate H, BB, BC columns Dim linkCellValue As String: linkCellValue = Me.Cells(3, "H").Value Dim ColBB As String: ColBB = "BB" Dim ColBC As String: ColBC = "BC" Dim valBB As String: valBB = Trim(Me.Cells(rowNum, ColBB).Value) Dim valBC As String: valBC = Trim(Me.Cells(rowNum, ColBC).Value) If linkCellValue = "1" Then ' If code = "1", BB and BC must be empty If valBB <> "" Then Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E005", ColBB & rowNum) Me.Range(ColBB & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If If valBC <> "" Then Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E005", ColBC & rowNum) Me.Range(ColBC & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If ElseIf linkCellValue = "2" Then ' If code = "2", BB and BC must have value If valBB = "" Then Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E002", ColBB & rowNum) Me.Range(ColBB & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If If valBC = "" Then Me.Cells(rowNum, errorCol).Value = GetErrorMsg("E002", ColBC & rowNum) Me.Range(ColBC & rowNum).Interior.Color = RGB(255, 0, 0) Exit Sub End If End If Me.Cells(rowNum, errorCol).ClearContents Exit Sub ErrHandler: lastErrorMsg = Err.Description End Sub