add CIBC purchase parser

This commit is contained in:
2025-11-23 22:16:35 -08:00
parent e690a2c4d2
commit 35381a4c1d

View File

@@ -178,11 +178,16 @@ class CIBCParser(TransactionParser):
flags=re.MULTILINE, flags=re.MULTILINE,
) )
PURCHASE_EXTRACT_RE = re.compile(
r"made a purchase with your CIBC.*ending in (?P<account>\d{4}) for \$(?P<amount>\d+\.\d{2}) at (?P<payee>.*?).<br", # noqa: E501
re.MULTILINE,
)
def __init__(self, account_map: dict[int, UUID]): def __init__(self, account_map: dict[int, UUID]):
self._account_map = account_map self._account_map = account_map
def match(self, msg: Message) -> bool: def match(self, msg: Message) -> bool:
return msg["From"] == "CIBC Banking <mailbox.noreply@cibc.com>" return msg["From"] == "CIBC Banking <Mailbox.noreply@cibc.com>"
def extract_payment(self, msg: EmailMessage): def extract_payment(self, msg: EmailMessage):
content = self.get_content(msg) content = self.get_content(msg)
@@ -209,10 +214,37 @@ class CIBCParser(TransactionParser):
imported_id=msg["Message-ID"], imported_id=msg["Message-ID"],
) )
def extract_purchase(self, msg: EmailMessage) -> Optional[Transaction]:
content = self.get_content(msg)
matches = self.PURCHASE_EXTRACT_RE.search(content)
if matches is None:
raise TransactionParsingFailed("no matches for extraction RE")
amount = Decimal(matches["amount"].replace(",", "")) * -1
date = parse_email_time(msg["Date"]).date()
account_ref = int(matches["account"])
if account_ref not in self._account_map:
warning("Account %s not in account map, skipping transaction", account_ref)
return None
account_id = self._account_map[account_ref]
return Transaction(
account=account_id,
date=date,
amount=amount,
payee=matches["payee"],
notes="via email",
imported_id=msg["Message-ID"],
)
def extract(self, msg: EmailMessage) -> Optional[Transaction]: def extract(self, msg: EmailMessage) -> Optional[Transaction]:
match msg["Subject"]: match msg["Subject"]:
case "New payment to your credit card": case "New payment to your credit card":
return self.extract_payment(msg) return self.extract_payment(msg)
case "New purchase on your credit card":
return self.extract_purchase(msg)
return None return None