diff options
-rw-r--r-- | src/journal_lib/dataclasses.py | 83 |
1 files changed, 81 insertions, 2 deletions
diff --git a/src/journal_lib/dataclasses.py b/src/journal_lib/dataclasses.py index 73b81e9..9c9729f 100644 --- a/src/journal_lib/dataclasses.py +++ b/src/journal_lib/dataclasses.py @@ -1,7 +1,11 @@ import sys -from dataclasses import dataclass +from copy import deepcopy +from dataclasses import dataclass, field +from decimal import Decimal +from datetime import datetime FORCE_NOCOLOR = False +DATE_FORMAT = "%Y-%m-%d" def set_force_nocolor(value: bool): @@ -29,6 +33,22 @@ class JournalEntryTransaction: currency: str | None amount: str | None comment: str | None + sign: int = field(init=False) + amount_value: int = field(init=False) + + def __post_init__(self): + if self.amount is not None: + if self.amount.startswith("-"): + self.sign = -1 + else: + self.sign = 1 + + self.amount_value = Decimal(self.amount.lstrip("-+")) + else: + self.sign = 1 + + def key(self): + return (self.account, abs(Decimal(self.amount)), self.currency) @dataclass @@ -58,15 +78,74 @@ class JournalEntry: amount_code = "32m" if transaction.amount[0] == "-": amount_code = "31m" + else: + t += " " t += f" {anesc(amount_code)}{format_amount(transaction.amount, transaction.currency)}{anesc('0m')}" if transaction.comment is not None: t += f" {anesc('38m')}{transaction.comment}{anesc('0m')}" s += t + f"{anesc('0m')}\n" for comment in self.comments: - s += f" {anesc('38m')}{comment}{anesc('0m')}\n" + s += f" ; {anesc('38m')}{comment}{anesc('0m')}\n" return s + "\n" + def __lt__(self, other): + return self.date < other.date + + def get_comment_by_label(self, label: str): + return next( + ( + comment[len(label) + 2 :] + for comment in self.comments + if comment.startswith(label) + ), + None, + ) + + @property + def from_dump_account(self): + # Extract the first comment that starts with "FROM_DUMP_ACCOUNT", if any + return self.get_comment_by_label("FROM_DUMP_ACCOUNT") + + @property + def class_info(self): + # Extract the first comment that starts with "FROM_DUMP_ACCOUNT", if any + return self.get_comment_by_label("CLASS_INFO") + + def potential_transfer(self, other, date_skew=3): + date_diff = abs((self.date - other.date).days) + if date_diff > date_skew: + return False + return True + + def likely_transfer(self, other, date_skew=3): + self_date = datetime.strptime(self.date, DATE_FORMAT) + other_date = datetime.strptime(other.date, DATE_FORMAT) + date_diff = abs((self_date - other_date).days) + if date_diff > date_skew: + return False + + # Check for inverse matching transactions + for self_trans in self.transactions: + inverse_match_found = False + for other_trans in other.transactions: + if ( + self_trans.account != other_trans.account + and self_trans.amount_value == other_trans.amount_value + and self_trans.currency == other_trans.currency + and self_trans.sign != other_trans.sign + ): + inverse_match_found = True + break + + if not inverse_match_found: + return False + + if self.from_dump_account == other.from_dump_account: + return False + + return True + @dataclass class JournalAccountDef: |