Public Sub getUBOTupdateByAC()
Dim sid, sessionId, acctNo, beginDate, endDate
Dim lastDateRow As Long, totalRow As Long
Dim dataLastRow As Long, nextDataRow As Long
Dim existingRow As Long
Dim checkingExisting As Boolean
Dim requestBody As String
Dim enteredEndDate As String
sid = "F160043296A"
acctNo = Trim$(ActiveSheet.Name)
'The sheet name must be a 12-digit account number.
If Len(acctNo) <> 12 Or acctNo Like "*[!0-9]*" Then
MsgBox "The sheet name must contain exactly 12 numbers.", vbExclamation
Exit Sub
End If
sessionId = getToken
'Use the last transaction date in column A. If there are no transaction
'rows yet, start from August 1, 2026.
lastDateRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 1).End(xlUp).Row
If lastDateRow < 2 Or Len(Trim$(CStr(ActiveSheet.Cells(lastDateRow, 1).Value))) = 0 Then
lastDateRow = 1
beginDate = DateSerial(2026, 8, 1)
ElseIf Not TryGetTransactionDate(ActiveSheet.Cells(lastDateRow, 1).Value, beginDate) Then
MsgBox "The last transaction date in column A is not a valid date.", vbExclamation
Exit Sub
End If
endDate = DateSerial(Year(beginDate), Month(beginDate) + 1, 0)
'If the last transaction is already on the month's final day,
'extend the query through the end of the following month.
If DateValue(beginDate) = endDate Then
endDate = DateSerial(Year(beginDate), Month(beginDate) + 2, 0)
End If
enteredEndDate = InputBox( _
Prompt:="Confirm or change the query end date (yyyy-mm-dd):", _
Title:="Query End Date", _
Default:=Format$(endDate, "yyyy-mm-dd"))
If Len(Trim$(enteredEndDate)) = 0 Then Exit Sub
If Not TryGetTransactionDate(enteredEndDate, endDate) Then
MsgBox "The query end date is not valid. Use yyyy-mm-dd.", vbExclamation
Exit Sub
End If
If endDate < beginDate Then
MsgBox "The query end date cannot be earlier than the start date.", vbExclamation
Exit Sub
End If
requestBody = "{ ""sid"": """ & sid & """, ""sessionId"": """ & sessionId & """, ""acctNo"": """ & acctNo & """, ""beginDate"": """ & Format$(beginDate, "yyyymmdd") & """, ""endDate"": """ & Format$(endDate, "yyyymmdd") & """ }"
Debug.Print requestBody
' Send request
Dim HTTPReq As New MSXML2.XMLHTTP60
HTTPReq.Open "POST", "https://www.ubot.com.tw/MyBank/IBKB010102", False
HTTPReq.setRequestHeader "Content-Type", "application/json"
HTTPReq.send requestBody
' Get response
Dim response As String
response = HTTPReq.responseText
Debug.Print response
Dim JSON As Object, i As Long
Dim NTDetailsList As Object
Dim Item As Variant
Set JSON = ParseJson(response)
' *** Headers ***'
Dim headers() As String, Header As String, index As Integer
headers = Split("Transaction Date,Transaction Time,Account Date,Summary,Payment,Deposit,Account Balance,PS,Memo,AutoNote,Note,Mahakala,Ajam,Aba,Ani,Prayer,Teacher,Translator,other,Center,Total", ",")
For i = LBound(headers) To UBound(headers)
Header = headers(i)
index = i + 1
Debug.Print index, Header
ActiveSheet.Cells(1, index).Value = Header
If Header = "Memo" Then ActiveSheet.Columns(index).NumberFormat = "@"
Next i
'*** check for data ***'
If IsEmpty(JSON("RespBody")("NTDetailList")) = True Then
MsgBox "No Data"
Exit Sub
End If
'***clear the old total row and append after the last dated row***
totalRow = lastDateRow + 1
For i = 5 To 21
ActiveSheet.Cells(totalRow, i).Value = ""
ActiveSheet.Cells(totalRow, i).Font.Bold = False
Next
dataLastRow = lastDateRow
nextDataRow = lastDateRow + 1
checkingExisting = True
'*** fill values 1-22 ***'
For Each Item In JSON("RespBody")("NTDetailList")
'Only check the overlapping records at the start of the response.
'After the first new record, append everything else without checking.
If checkingExisting Then
existingRow = FindTransactionRow(Item("TraDate"), _
Item("TraTime"), _
Item("Balance"), _
dataLastRow)
If existingRow > 0 Then GoTo SkipTransaction
checkingExisting = False
End If
i = nextDataRow
nextDataRow = nextDataRow + 1
dataLastRow = i
ActiveSheet.Cells(i, 1).Value = Item("TraDate")
ActiveSheet.Cells(i, 2).Value = Item("TraTime")
ActiveSheet.Cells(i, 3).Value = Item("AccountDate")
ActiveSheet.Cells(i, 4).Value = Item("Summary")
ActiveSheet.Cells(i, 5).Value = Item("Expenditure")
'*** Deposit 6 ***'
'fill value
ActiveSheet.Cells(i, 6).Value = Item("Income")
'if Deposit = Total
ActiveSheet.Cells(i, 6).FormatConditions.Delete
ActiveSheet.Cells(i, 6).FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:="=$U" & i
'then format
ActiveSheet.Cells(i, 6).FormatConditions(ActiveSheet.Cells(i, 6).FormatConditions.Count).SetFirstPriority
With ActiveSheet.Cells(i, 6).FormatConditions(1).Font
.Color = -16752384
.TintAndShade = 0
End With
With ActiveSheet.Cells(i, 6).FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 13561798
.TintAndShade = 0
End With
ActiveSheet.Cells(i, 6).FormatConditions(1).StopIfTrue = False
'end format
ActiveSheet.Cells(i, 7).Value = Item("Balance")
ActiveSheet.Cells(i, 8).Value = Item("PS")
ActiveSheet.Cells(i, 9).Value = Item("TraSum")
ActiveSheet.Cells(i, 10).Value = getNameOfAccountNo("Accounts", "A:B", Item("TraSum"))
'*** 11-20 *************************
ActiveSheet.Cells(i, 21).Value = "=SUM(INDIRECT(""L"" & ROW()):INDIRECT(""T"" & ROW()))"
'if Total = Deposit
ActiveSheet.Cells(i, 21).FormatConditions.Delete
ActiveSheet.Cells(i, 21).FormatConditions.Add Type:=xlCellValue, Operator:=xlEqual, Formula1:="=$F" & i
'then
ActiveSheet.Cells(i, 21).FormatConditions(ActiveSheet.Cells(i, 21).FormatConditions.Count).SetFirstPriority
With ActiveSheet.Cells(i, 21).FormatConditions(1).Font
.Color = -16752384
.TintAndShade = 0
End With
With ActiveSheet.Cells(i, 21).FormatConditions(1).Interior
.PatternColorIndex = xlAutomatic
.Color = 13561798
.TintAndShade = 0
End With
ActiveSheet.Cells(i, 21).FormatConditions(1).StopIfTrue = False
'end format
SkipTransaction:
Next
i = nextDataRow 'totals row
'**** add total ***'
ActiveSheet.Cells(i, 5).Value = "=SUM(E2:E" & (i - 1) & ")"
ActiveSheet.Cells(i, 5).Font.Bold = True
ActiveSheet.Cells(i, 6).Value = "=SUM(F2:F" & (i - 1) & ")"
ActiveSheet.Cells(i, 6).Font.Bold = True
ActiveSheet.Cells(i, 12).Value = "=SUM(L2:L" & (i - 1) & ")"
ActiveSheet.Cells(i, 12).Font.Bold = True
ActiveSheet.Cells(i, 13).Value = "=SUM(M2:M" & (i - 1) & ")"
ActiveSheet.Cells(i, 13).Font.Bold = True
ActiveSheet.Cells(i, 14).Value = "=SUM(N2:N" & (i - 1) & ")"
ActiveSheet.Cells(i, 14).Font.Bold = True
ActiveSheet.Cells(i, 15).Value = "=SUM(O2:O" & (i - 1) & ")"
ActiveSheet.Cells(i, 15).Font.Bold = True
ActiveSheet.Cells(i, 16).Value = "=SUM(P2:P" & (i - 1) & ")"
ActiveSheet.Cells(i, 16).Font.Bold = True
ActiveSheet.Cells(i, 17).Value = "=SUM(Q2:Q" & (i - 1) & ")"
ActiveSheet.Cells(i, 17).Font.Bold = True
ActiveSheet.Cells(i, 18).Value = "=SUM(R2:R" & (i - 1) & ")"
ActiveSheet.Cells(i, 18).Font.Bold = True
ActiveSheet.Cells(i, 19).Value = "=SUM(S2:S" & (i - 1) & ")"
ActiveSheet.Cells(i, 19).Font.Bold = True
ActiveSheet.Cells(i, 20).Value = "=SUM(T2:T" & (i - 1) & ")"
ActiveSheet.Cells(i, 20).Font.Bold = True
ActiveSheet.Cells(i, 21).Value = "=SUM(U2:U" & (i - 1) & ")"
ActiveSheet.Cells(i, 21).Font.Bold = True
ActiveWorkbook.Save
MsgBox "Complete"
End Sub
Private Function FindTransactionRow(ByVal transactionDate As Variant, _
ByVal transactionTime As Variant, _
ByVal transactionBalance As Variant, _
ByVal dataLastRow As Long) As Long
Dim rowNumber As Long
Dim wantedDate As String, wantedTime As String, wantedBalance As String
Dim storedDate As String, storedTime As String, storedBalance As String
Dim displayedDate As String, displayedTime As String, displayedBalance As String
Dim worksheetLastRow As Long
wantedDate = TransactionDateKey(transactionDate)
wantedTime = TransactionTimeKey(transactionTime)
wantedBalance = TransactionBalanceKey(transactionBalance)
'Always search every dated row currently on the sheet.
worksheetLastRow = ActiveSheet.Cells(ActiveSheet.Rows.Count, 1).End(xlUp).Row
If worksheetLastRow > dataLastRow Then dataLastRow = worksheetLastRow
For rowNumber = 2 To dataLastRow
storedDate = TransactionDateKey(ActiveSheet.Cells(rowNumber, 1).Value2)
storedTime = TransactionTimeKey(ActiveSheet.Cells(rowNumber, 2).Value2)
storedBalance = TransactionBalanceKey(ActiveSheet.Cells(rowNumber, 7).Value2)
'The displayed-text fallback handles cells whose underlying values
'were converted differently by Excel when they were first imported.
displayedDate = DigitsOnly(ActiveSheet.Cells(rowNumber, 1).Text)
displayedTime = DigitsOnly(ActiveSheet.Cells(rowNumber, 2).Text)
displayedBalance = TransactionBalanceKey(ActiveSheet.Cells(rowNumber, 7).Text)
If (storedDate = wantedDate Or displayedDate = wantedDate) _
And (storedTime = wantedTime Or displayedTime = wantedTime) _
And (storedBalance = wantedBalance Or displayedBalance = wantedBalance) Then
Debug.Print "Skipping existing transaction at row"; rowNumber; _
wantedDate; wantedTime; wantedBalance
FindTransactionRow = rowNumber
Exit Function
End If
Next rowNumber
Debug.Print "First new transaction:"; wantedDate; wantedTime; wantedBalance
End Function
Private Function TransactionDateKey(ByVal cellValue As Variant) As String
Dim parsedDate As Variant
Dim digits As String
If TryGetTransactionDate(cellValue, parsedDate) Then
TransactionDateKey = Format$(parsedDate, "yyyymmdd")
Else
digits = DigitsOnly(Trim$(CStr(cellValue)))
If Len(digits) >= 8 Then
TransactionDateKey = Left$(digits, 8)
Else
TransactionDateKey = digits
End If
End If
End Function
Private Function TransactionTimeKey(ByVal cellValue As Variant) As String
Dim timeText As String, digits As String
Dim fractionPosition As Long
If IsDate(cellValue) Then
TransactionTimeKey = Format$(CDate(cellValue), "hhmmss")
Else
timeText = Trim$(CStr(cellValue))
'Ignore fractional seconds, for example 11:15:24.000.
fractionPosition = InStrRev(timeText, ".")
If InStr(timeText, ":") > 0 And fractionPosition > InStrRev(timeText, ":") Then
timeText = Left$(timeText, fractionPosition - 1)
End If
digits = DigitsOnly(timeText)
If Len(digits) > 6 Then digits = Right$(digits, 6)
TransactionTimeKey = Right$("000000" & digits, 6)
End If
End Function
Private Function TransactionBalanceKey(ByVal cellValue As Variant) As String
Dim balanceText As String
balanceText = Replace(Trim$(CStr(cellValue)), ",", "")
If Len(balanceText) = 0 Then Exit Function
If IsNumeric(balanceText) Then
TransactionBalanceKey = CStr(CDec(balanceText))
Else
TransactionBalanceKey = balanceText
End If
End Function
Private Function DigitsOnly(ByVal textValue As String) As String
Dim characterIndex As Long, oneCharacter As String
For characterIndex = 1 To Len(textValue)
oneCharacter = Mid$(textValue, characterIndex, 1)
If oneCharacter Like "#" Then DigitsOnly = DigitsOnly & oneCharacter
Next characterIndex
End Function
Private Function TryGetTransactionDate(ByVal cellValue As Variant, ByRef transactionDate As Variant) As Boolean
Dim dateText As String
If IsDate(cellValue) Then
transactionDate = CDate(cellValue)
TryGetTransactionDate = True
Exit Function
End If
dateText = DigitsOnly(Trim$(CStr(cellValue)))
If Len(dateText) <> 8 Or Not dateText Like "########" Then Exit Function
On Error GoTo InvalidDate
transactionDate = DateSerial(CInt(Left$(dateText, 4)), _
CInt(Mid$(dateText, 5, 2)), _
CInt(Right$(dateText, 2)))
If Format$(transactionDate, "yyyymmdd") <> dateText Then Exit Function
TryGetTransactionDate = True
InvalidDate:
End Function