add neo parser
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
import re
|
||||
from abc import ABC, abstractmethod
|
||||
from collections.abc import Sequence
|
||||
from datetime import date, datetime
|
||||
from decimal import Decimal
|
||||
from email.message import EmailMessage, Message
|
||||
from logging import info, warning
|
||||
from typing import Any, Optional, Sequence
|
||||
from logging import debug, info, warning
|
||||
from typing import Any, Optional
|
||||
from uuid import UUID
|
||||
|
||||
from bs4 import BeautifulSoup
|
||||
@@ -308,3 +309,42 @@ class ScotiaBankParser(TransactionParser):
|
||||
return self.extract_transaction(msg)
|
||||
info("Subject `%s` didn't match any extractors", msg["Subject"])
|
||||
return None
|
||||
|
||||
|
||||
class NeoFinancialParser(TransactionParser):
|
||||
PURCHASE_EXTRACT_RE = re.compile(
|
||||
r"your purchase of \$(?P<amount>[0-9]+\.[0-9]{2}) at (?P<payee>.+) on (?P<date>(January|February|March|April|May|June|July|August|September|October|November|December) \d{1,2}(st|nd|rd|th)?, \d{4})", # noqa: E501
|
||||
re.MULTILINE,
|
||||
)
|
||||
|
||||
def __init__(self, account_id: UUID):
|
||||
self.account_id = account_id
|
||||
|
||||
def match(self, msg: Message) -> bool:
|
||||
return msg["From"] == "Neo Financial <info@neofinancial.com>" and msg[
|
||||
"Subject"
|
||||
].startswith("You earned")
|
||||
|
||||
def extract_purchase(self, msg: EmailMessage) -> Optional[Transaction]:
|
||||
content = self.get_content(msg, preferencelist=["plain"])
|
||||
matches = self.PURCHASE_EXTRACT_RE.search(content)
|
||||
if matches is None:
|
||||
debug(f"No match on\n\n{content}")
|
||||
raise TransactionParsingFailed("no matches for purchase extraction RE")
|
||||
|
||||
amount = Decimal(matches["amount"].replace(",", "")) * -1
|
||||
# Use date from email header, it seems to match the body and includes TZ info
|
||||
date = parse_email_time(msg["Date"]).date()
|
||||
return Transaction(
|
||||
account=self.account_id,
|
||||
date=date,
|
||||
amount=amount,
|
||||
payee=matches["payee"],
|
||||
notes="via email",
|
||||
imported_id=msg["Message-ID"],
|
||||
)
|
||||
|
||||
def extract(self, msg: EmailMessage) -> Optional[Transaction]:
|
||||
if msg["Subject"].startswith("You earned"):
|
||||
return self.extract_purchase(msg)
|
||||
return None
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "actual-imap-poll"
|
||||
version = "0.1.3"
|
||||
version = "0.2.0"
|
||||
description = "Poll an IMAP mailbox looking for transactions to submit to Actual Budget"
|
||||
authors = [
|
||||
{name = "Keenan Tims",email = "ktims@gotroot.ca"}
|
||||
|
||||
Reference in New Issue
Block a user