From 25bbbdfd14b3b21563543773df0eec28a67065e6 Mon Sep 17 00:00:00 2001 From: ckyOL <1503001+ckyOL@users.noreply.github.com> Date: Sat, 3 May 2025 22:04:26 +0800 Subject: [PATCH 1/3] :sparkles: Add time deposit and unit trust categories, omit time deposit rows, and add investment balances to the total balance --- hsbcpdf/helpers/accountstatement.py | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/hsbcpdf/helpers/accountstatement.py b/hsbcpdf/helpers/accountstatement.py index d9e03af..a34da12 100644 --- a/hsbcpdf/helpers/accountstatement.py +++ b/hsbcpdf/helpers/accountstatement.py @@ -23,12 +23,16 @@ class EnumSumAccountTypes: HKDCURRENT = 'HKD Current' FCYSAVINGS = 'FCY Savings' FCYCURRENT = 'FCY Current' + TIMEDEPOSIT = 'Time Deposit' + UNITTRUST = 'Unit Trusts' class AccountTypes: HKDSAVINGS = 'HKDSavings' HKDCURRENT = 'HKDCurrent' FCYSAVINGS = 'FCYSavings' FCYCURRENT = 'FCYCurrent' + TIMEDEPOSIT = 'TimeDeposit' + UNITTRUST = 'UnitTrust' class TableZone: @@ -211,6 +215,15 @@ def clean_table(self): desc = "" new_balance = 0. for index, row in self.table.iterrows(): + # skip time deposit lines + if ( + row.isnull().all() + or str(row[0]).strip() == "Time" + or str(row[1]).strip() in ("Deposits", "") + or "Principal" in str(row[2]) + or str(row[0]).strip().isdigit() + ): + continue # first line with new currency is previous balance if row[0] != ccy and row[0] != "": if ccy != "": @@ -266,7 +279,9 @@ class TableZoneSum(TableZone): EnumSumAccountTypes.HKDSAVINGS: AccountTypes.HKDSAVINGS, EnumSumAccountTypes.HKDCURRENT: AccountTypes.HKDCURRENT, EnumSumAccountTypes.FCYSAVINGS: AccountTypes.FCYSAVINGS, - EnumSumAccountTypes.FCYCURRENT: AccountTypes.FCYCURRENT + EnumSumAccountTypes.FCYCURRENT: AccountTypes.FCYCURRENT, + EnumSumAccountTypes.TIMEDEPOSIT: AccountTypes.TIMEDEPOSIT, + EnumSumAccountTypes.UNITTRUST: AccountTypes.UNITTRUST } def __init__(self, page_height, page_width, section, account, st_date): @@ -293,9 +308,19 @@ def clean_table(self): # skip first 2 lines that are header part and account narrative for index, row in self.table[2:].iterrows(): logger.debug("process row ({}): <{}>".format(index, row)) + + # skip inverstment title + if row[0] == 'HSBC Premier\n- Investments': + continue + if row[0] is not None and row[0] != "": if row[0] == 'Total': - self.summary['total_balance_hkd'] = self.extract_amount(row[6], row[7]) + total_amount = self.extract_amount(row[6], row[7]) + if self.summary['total_balance_hkd'] is None: + self.summary['total_balance_hkd'] = total_amount + else: + # add investments total + self.summary['total_balance_hkd'] += total_amount continue elif row[0] not in TableZoneSum.map_type.keys(): raise TemplateException("Summary contains an unknow Account type [{}]".format(row[0])) From cd4f67198c09642897a862b1802297a17cc19a2b Mon Sep 17 00:00:00 2001 From: ckyOL <1503001+ckyOL@users.noreply.github.com> Date: Mon, 2 Jun 2025 22:38:55 +0800 Subject: [PATCH 2/3] :sparkles: Add bond category and skip exchange rate row --- hsbcpdf/helpers/accountstatement.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hsbcpdf/helpers/accountstatement.py b/hsbcpdf/helpers/accountstatement.py index a34da12..e53c711 100644 --- a/hsbcpdf/helpers/accountstatement.py +++ b/hsbcpdf/helpers/accountstatement.py @@ -25,6 +25,7 @@ class EnumSumAccountTypes: FCYCURRENT = 'FCY Current' TIMEDEPOSIT = 'Time Deposit' UNITTRUST = 'Unit Trusts' + BOND = 'Bonds/Certificates of Deposit' class AccountTypes: HKDSAVINGS = 'HKDSavings' @@ -33,6 +34,7 @@ class AccountTypes: FCYCURRENT = 'FCYCurrent' TIMEDEPOSIT = 'TimeDeposit' UNITTRUST = 'UnitTrust' + BOND = 'Bond' class TableZone: @@ -281,7 +283,8 @@ class TableZoneSum(TableZone): EnumSumAccountTypes.FCYSAVINGS: AccountTypes.FCYSAVINGS, EnumSumAccountTypes.FCYCURRENT: AccountTypes.FCYCURRENT, EnumSumAccountTypes.TIMEDEPOSIT: AccountTypes.TIMEDEPOSIT, - EnumSumAccountTypes.UNITTRUST: AccountTypes.UNITTRUST + EnumSumAccountTypes.UNITTRUST: AccountTypes.UNITTRUST, + EnumSumAccountTypes.BOND: AccountTypes.BOND } def __init__(self, page_height, page_width, section, account, st_date): @@ -313,6 +316,10 @@ def clean_table(self): if row[0] == 'HSBC Premier\n- Investments': continue + # skip exchange rate + if row[0] == 'Exchange Rate': + continue + if row[0] is not None and row[0] != "": if row[0] == 'Total': total_amount = self.extract_amount(row[6], row[7]) From 534192e2f3a6aaebce98dd356afa48273033f180 Mon Sep 17 00:00:00 2001 From: ckyOL <1503001+ckyOL@users.noreply.github.com> Date: Sun, 1 Mar 2026 21:25:58 +0800 Subject: [PATCH 3/3] :sparkle: Add FCY time deposit category. Skip (DR=Debit \n) line. Add last_dt logic for handling multiple transactions per day --- hsbcpdf/helpers/accountstatement.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/hsbcpdf/helpers/accountstatement.py b/hsbcpdf/helpers/accountstatement.py index e53c711..0d49db1 100644 --- a/hsbcpdf/helpers/accountstatement.py +++ b/hsbcpdf/helpers/accountstatement.py @@ -24,6 +24,7 @@ class EnumSumAccountTypes: FCYSAVINGS = 'FCY Savings' FCYCURRENT = 'FCY Current' TIMEDEPOSIT = 'Time Deposit' + FCYTIMEDEPOSIT = 'FCY Time Deposit' UNITTRUST = 'Unit Trusts' BOND = 'Bonds/Certificates of Deposit' @@ -33,6 +34,7 @@ class AccountTypes: FCYSAVINGS = 'FCYSavings' FCYCURRENT = 'FCYCurrent' TIMEDEPOSIT = 'TimeDeposit' + FCYTIMEDEPOSIT = 'FCYTimeDeposit' UNITTRUST = 'UnitTrust' BOND = 'Bond' @@ -212,6 +214,7 @@ def clean_table(self): logger.debug(shape) logger.debug('table shape: {}'.format(self.table.shape)) + last_dt = "" dt = "" ccy = "" desc = "" @@ -220,10 +223,10 @@ def clean_table(self): # skip time deposit lines if ( row.isnull().all() - or str(row[0]).strip() == "Time" - or str(row[1]).strip() in ("Deposits", "") - or "Principal" in str(row[2]) + or str(row[0]).strip() in ("Time", "No.", "Deposi") or str(row[0]).strip().isdigit() + or str(row[0]).strip() == "" and str(row[1]).strip() == "" and str(row[2]).strip().isdigit() + or str(row[0]).strip() == "" and str(row[1]).strip() == "" and str(row[2]).strip() == "" ): continue # first line with new currency is previous balance @@ -246,13 +249,18 @@ def clean_table(self): new_balance = previous_balance - if row[1] != "": dt = self.extract_date(row[1]) + if row[1] != "": + dt = self.extract_date(row[1]) + last_dt = dt + else: + dt = last_dt + desc = (desc + " " if desc != "" else "") + row[2] credit = row[3] debit = row[4] amount = None - logger.debug("ccy[{}] date[{}] desc[{}] credit[{}] debit[{}]".format(ccy, dt, desc, credit, debit)) + logger.debug("[{}] ccy[{}] date[{}] desc[{}] credit[{}] debit[{}]".format(index, ccy, dt, desc, credit, debit)) if credit is not None and credit != "": amount = float(credit.replace(",", "")) elif debit is not None and debit != "": @@ -283,6 +291,7 @@ class TableZoneSum(TableZone): EnumSumAccountTypes.FCYSAVINGS: AccountTypes.FCYSAVINGS, EnumSumAccountTypes.FCYCURRENT: AccountTypes.FCYCURRENT, EnumSumAccountTypes.TIMEDEPOSIT: AccountTypes.TIMEDEPOSIT, + EnumSumAccountTypes.FCYTIMEDEPOSIT: AccountTypes.FCYTIMEDEPOSIT, EnumSumAccountTypes.UNITTRUST: AccountTypes.UNITTRUST, EnumSumAccountTypes.BOND: AccountTypes.BOND } @@ -320,6 +329,10 @@ def clean_table(self): if row[0] == 'Exchange Rate': continue + # skip (DR=Debit \n) in other line + if row[4] == "(DR=Debit \n)" and row[6] == "(DR=Debit \n)": + continue + if row[0] is not None and row[0] != "": if row[0] == 'Total': total_amount = self.extract_amount(row[6], row[7])