Multiple fixes and cleanups

- Remove unnecessary category null check after db select
- Adds multiple try-catch block for misbehaving parsing
- matplotlib.plt tight_layout moved to figure method
- Fixes debit/credit index with different dates
- Check for existing banks transformed to lower chars, to avoid
capitilization problem
This commit is contained in:
Luís Murta 2021-07-30 20:19:48 +01:00
parent 1f97a4635a
commit 2280b60159
Signed by: satprog
GPG Key ID: DDF2EFC6179009DC
4 changed files with 47 additions and 28 deletions

View File

@ -56,11 +56,10 @@ def categorize_data(db: DBManager):
# 3rd) Classify all else based on regex # 3rd) Classify all else based on regex
if transactions := db.get_uncategorized_transactions(): if transactions := db.get_uncategorized_transactions():
for transaction in transactions: for transaction in transactions:
if not transaction.category: for name, category in categories.items():
for name, category in categories.items(): if matches(transaction, category):
if matches(transaction, category): transaction.category = name
transaction.category = name break
break
db.update_categories( db.update_categories(
[transaction for transaction in transactions if transaction.category] [transaction for transaction in transactions if transaction.category]
) )
@ -150,7 +149,10 @@ def nulls(db: DBManager) -> None:
def matches(transaction: Transaction, category: Options): def matches(transaction: Transaction, category: Options):
if not category.regex: if not category.regex:
return False return False
return any( try:
re.compile(pattern).search(transaction.description.lower()) return any(
for pattern in category.regex re.compile(pattern).search(transaction.description.lower())
) for pattern in category.regex
)
except re.error as e:
print(f"{e}{transaction} {category}")

View File

@ -41,7 +41,7 @@ def monthly(
] ]
) )
plt.figure(figsize=(30, 10)) plt.figure(tight_layout=True)
plt.plot( plt.plot(
list(rrule(MONTHLY, dtstart=start.replace(day=1), until=end.replace(day=1))), list(rrule(MONTHLY, dtstart=start.replace(day=1), until=end.replace(day=1))),
[groups["income"] for _, groups in monthly_transactions], [groups["income"] for _, groups in monthly_transactions],
@ -60,7 +60,6 @@ def monthly(
], ],
) )
plt.legend(loc="upper left") plt.legend(loc="upper left")
plt.tight_layout()
if args["save"]: if args["save"]:
plt.savefig("graph.png") plt.savefig("graph.png")
else: else:

View File

@ -31,7 +31,20 @@ Options = namedtuple(
"MasterCard", "MasterCard",
"AmericanExpress", "AmericanExpress",
], ],
defaults=["", "", "", 1, None, Index(), Index(), False, None, None, None, None], defaults=[
"",
"",
"",
1,
None,
Index(),
Index(),
False,
None,
None,
None,
None,
],
) )
@ -88,6 +101,7 @@ class Parser:
for line in list(open(self.filename, encoding=self.options.encoding))[ for line in list(open(self.filename, encoding=self.options.encoding))[
self.options.start - 1 : self.options.end self.options.start - 1 : self.options.end
] ]
if len(line) > 2
] ]
return transactions return transactions
@ -100,9 +114,10 @@ class Parser:
elif line[options.credit.value]: elif line[options.credit.value]:
index = options.credit index = options.credit
elif options.debit.date != options.credit.date: elif options.debit.date != options.credit.date:
if line[options.debit.date]: negate = 1 if (options.debit.negate or options.credit.negate) else -1
if (negate * utils.parse_decimal(line[options.debit.value])) < 0:
index = options.debit index = options.debit
elif line[options.credit.date]: else:
index = options.credit index = options.credit
elif options.debit.text != options.credit.text: elif options.debit.text != options.credit.text:
if line[options.debit.text]: if line[options.debit.text]:

View File

@ -1,5 +1,5 @@
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from decimal import Decimal from decimal import Decimal, InvalidOperation
from pathlib import Path from pathlib import Path
@ -21,15 +21,18 @@ def parse_decimal(s: str) -> Decimal:
return Decimal(s) return Decimal(s)
except ValueError: except ValueError:
pass pass
s = s.strip().replace(u"\xa0", "").replace(" ", "") try:
s = s.strip().replace("", "").replace("+", "") d = s.strip().replace("\xa0", "").replace(" ", "")
if s.rfind(",") > s.rfind("."): d = d.replace("", "").replace("+", "").replace("EUR", "").strip()
s = s.replace(".", "") if d.rfind(",") > d.rfind("."):
i = s.rfind(",") d = d.replace(".", "")
li = list(s) i = d.rfind(",")
li[i] = "." li = list(d)
s = "".join(li) li[i] = "."
return Decimal(s.replace(",", "")) d = "".join(li)
return Decimal(d.replace(",", ""))
except InvalidOperation:
raise InvalidOperation(f"{s} -> {d}")
def find_credit_institution(fn, banks, creditcards): def find_credit_institution(fn, banks, creditcards):
@ -47,10 +50,10 @@ def find_credit_institution(fn, banks, creditcards):
if not bank: if not bank:
raise WrongFilenameError raise WrongFilenameError
if bank not in banks: if bank.lower() not in [bank.lower() for bank in banks]:
raise BankNotAvailableError raise BankNotAvailableError(f"{fn}: {banks}")
if cc and cc not in creditcards: if cc and cc.lower() not in [cc.lower() for cc in creditcards]:
raise CreditCardNotAvailableError raise CreditCardNotAvailableError(f"{fn}: {banks}")
return bank, cc return bank, cc