From 81c7bb94a4702876f10fdf928f5b0fffc72aea93 Mon Sep 17 00:00:00 2001 From: Keenan Tims Date: Thu, 24 Apr 2025 15:32:33 -0700 Subject: [PATCH] add MBNA parser --- parsers.py | 36 +++++++++++++++++++++++++++++++++++- watcher.py | 4 ++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/parsers.py b/parsers.py index 012d483..d4d8553 100644 --- a/parsers.py +++ b/parsers.py @@ -42,7 +42,7 @@ class RogersBankParser(TransactionParser): body = msg.get_body() if body is None: raise TransactionParsingFailed("No body of message found") - matches = RogersBankParser.EXTRACT_RE.search(body.as_string()) + matches = self.EXTRACT_RE.search(body.as_string()) if matches is None: raise TransactionParsingFailed("No matches for extraction RE") amount = Decimal(matches[1]) @@ -57,3 +57,37 @@ class RogersBankParser(TransactionParser): notes="via email", imported_id=msg["Message-ID"], ) + + +class MBNAParser(TransactionParser): + EXTRACT_RE = re.compile( + r"A purchase of \$(\d+\.\d{2}) from ([^<]+) was made at (\d{1,2}:\d{2} (AM|PM)) UTC on (\d{4}-\d{2}-\d{2})" # noqa: E501 + ) + + def __init__(self, account_id: UUID): + self.account_id = account_id + + def match(self, msg: Message): + return ( + msg["From"] == "MBNA Notifications " + and msg["Subject"] == "MBNA - Transaction Alert" + ) + + def extract(self, msg: EmailMessage) -> Transaction: + body = msg.get_body() + if body is None: + raise TransactionParsingFailed("No body of message found") + matches = self.EXTRACT_RE.search(body.as_string()) + if matches is None: + raise TransactionParsingFailed("No matches for extraction RE") + amount = Decimal(matches[1]) + payee = matches[2] + date = matches[5] + return Transaction( + account=self.account_id, + date=date, + amount=amount, + payee=payee, + notes="via email", + imported_id=msg["Message-ID"], + ) diff --git a/watcher.py b/watcher.py index f8fc680..1360c42 100644 --- a/watcher.py +++ b/watcher.py @@ -78,8 +78,8 @@ async def process_message(msg_b: bytes): trans = parser.extract(msg) info("Submitting transaction to Actual: %s", trans) await submit_transaction(trans) - except TransactionParsingFailed: - warning("Unable to parse message") + except TransactionParsingFailed as e: + warning("Unable to parse message %s", e) except Exception as e: warning("Unexpected exception %s", e)