diff --git a/pfbudget/cli/runnable.py b/pfbudget/cli/runnable.py index 378b54a..3618a9f 100644 --- a/pfbudget/cli/runnable.py +++ b/pfbudget/cli/runnable.py @@ -2,8 +2,9 @@ from pathlib import Path import argparse import re -from pfbudget.core.manager import Manager from pfbudget.core.categories import categorize_data +from pfbudget.core.manager import Manager +from pfbudget.core.input.json import JsonParser from pfbudget.db.client import DatabaseClient import pfbudget.reporting.graph import pfbudget.reporting.report @@ -74,7 +75,7 @@ def argparser(manager: Manager) -> argparse.ArgumentParser: parents=[help], formatter_class=argparse.ArgumentDefaultsHelpFormatter, ) - p_init.set_defaults(func=lambda args: DatabaseClient(args.database).init()) + p_init.set_defaults(func=lambda args: manager.init()) """ Exporting @@ -155,10 +156,10 @@ def argparser(manager: Manager) -> argparse.ArgumentParser: p_report.set_defaults(func=report) """ - Init Nordigen session: get new access token + Nordigen API """ p_nordigen_access = subparsers.add_parser( - "init", + "token", description="Get new access token", parents=[help], formatter_class=argparse.ArgumentDefaultsHelpFormatter, @@ -204,6 +205,20 @@ def argparser(manager: Manager) -> argparse.ArgumentParser: p_nordigen_list.add_argument("country", nargs=1, type=str) p_nordigen_list.set_defaults(func=lambda args: Client().banks(args.country[0])) + """ + Nordigen JSONs + """ + p_nordigen_json = subparsers.add_parser( + "json", + description="", + parents=[help], + formatter_class=argparse.ArgumentDefaultsHelpFormatter, + ) + p_nordigen_json.add_argument("json", nargs=1, type=str) + p_nordigen_json.add_argument("bank", nargs=1, type=str) + p_nordigen_json.add_argument("--invert", action=argparse.BooleanOptionalAction) + p_nordigen_json.set_defaults(func=lambda args: manager.parser(JsonParser(vars(args)))) + return parser @@ -231,11 +246,17 @@ def graph(args): """ start, end = pfbudget.utils.parse_args_period(args) if args.option == "monthly": - pfbudget.reporting.graph.monthly(DatabaseClient(args.database), vars(args), start, end) + pfbudget.reporting.graph.monthly( + DatabaseClient(args.database), vars(args), start, end + ) elif args.option == "discrete": - pfbudget.reporting.graph.discrete(DatabaseClient(args.database), vars(args), start, end) + pfbudget.reporting.graph.discrete( + DatabaseClient(args.database), vars(args), start, end + ) elif args.option == "networth": - pfbudget.reporting.graph.networth(DatabaseClient(args.database), vars(args), start, end) + pfbudget.reporting.graph.networth( + DatabaseClient(args.database), vars(args), start, end + ) def report(args): diff --git a/pfbudget/core/input/input.py b/pfbudget/core/input/input.py new file mode 100644 index 0000000..debd3bb --- /dev/null +++ b/pfbudget/core/input/input.py @@ -0,0 +1,13 @@ +from abc import ABC, abstractmethod + +from pfbudget.core.transactions import Transactions + + +class Input(ABC): + @abstractmethod + def __init__(self, options: dict): + self.options = options + + @abstractmethod + def transactions(self) -> Transactions: + return NotImplemented diff --git a/pfbudget/core/input/json.py b/pfbudget/core/input/json.py new file mode 100644 index 0000000..bc5235f --- /dev/null +++ b/pfbudget/core/input/json.py @@ -0,0 +1,28 @@ +import json + +from pfbudget.core.transactions import Transactions +from pfbudget.utils.converters import convert +from pfbudget.utils.utils import parse_decimal + +from .input import Input + + +class JsonParser(Input): + def __init__(self, options): + super().__init__(options) + + def transactions(self) -> Transactions: + with open(self.options["json"][0], "r") as f: + return [ + convert( + [ + t["bookingDate"], + t["remittanceInformationUnstructured"], + self.options["bank"][0], + parse_decimal(t["transactionAmount"]["amount"]) + if not self.options["invert"] + else -parse_decimal(t["transactionAmount"]["amount"]), + ], + ) + for t in json.load(f)["transactions"]["booked"] + ] diff --git a/pfbudget/core/input/nordigen.py b/pfbudget/core/input/nordigen.py index 64107af..1afa470 100644 --- a/pfbudget/core/input/nordigen.py +++ b/pfbudget/core/input/nordigen.py @@ -1,15 +1,20 @@ from dotenv import load_dotenv -from json import dump from nordigen import NordigenClient from uuid import uuid4 import os import webbrowser +from .input import Input +from pfbudget.core.transactions import Transactions +from pfbudget.utils.converters import convert +from pfbudget.utils.utils import parse_decimal + load_dotenv() -class Client: - def __init__(self): +class Client(Input): + def __init__(self, options: dict): + super().__init__(options) self._client = NordigenClient( secret_key=os.environ.get("SECRET_KEY"), secret_id=os.environ.get("SECRET_ID"), @@ -17,6 +22,24 @@ class Client: self._client.token = self.__token() + def transactions(self) -> Transactions: + requisition = self._client.requisition.get_requisition_by_id(self.options["id"]) + + for acc in requisition["accounts"]: + account = self._client.account_api(acc) + d = account.get_transactions()["transactions"] + return [ + convert( + t["bookingDate"], + t["remittanceInformationUnstructured"], + self.options["bank"], + parse_decimal(t["transactionAmount"]["amount"]) + if not self.options["invert"] + else -parse_decimal(t["transactionAmount"]["amount"]), + ) + for t in d["booked"] + ] + def token(self): token = self._client.generate_token() print(f"New access token: {token}") @@ -32,19 +55,6 @@ class Client: else: print("you forgot the req id") - def transactions(self, id): - requisition = self._client.requisition.get_requisition_by_id(id) - - # transactions_list = [] - for acc in requisition["accounts"]: - account = self._client.account_api(acc) - print(account.get_metadata()) - with open("cetelem.json", "w") as f: - dump(account.get_transactions(), f, indent=4) - # print(dumps(account.get_transactions(), indent=4)) - - # print(transactions_list) - def banks(self, country: str): print(self._client.institution.get_institutions(country)) diff --git a/pfbudget/core/manager.py b/pfbudget/core/manager.py index 6faab87..a6458db 100644 --- a/pfbudget/core/manager.py +++ b/pfbudget/core/manager.py @@ -1,3 +1,4 @@ +from pfbudget.core.input.input import Input from pfbudget.core.input.parsers import parse_data from pfbudget.core.transactions import Transaction from pfbudget.db.client import DatabaseClient @@ -8,13 +9,19 @@ class Manager: def __init__(self, db: str): self.__db = DatabaseClient(db) + def init(self): + self.__db.init() + + def parser(self, parser: Input): + print(parser.transactions()) + + def parse(self, filename: str, args: dict): + transactions = parse_data(filename, args) + self.add_transactions(transactions) + def transactions() -> list[Transaction]: pass def add_transactions(self, transactions: list[Transaction]): converted = convert(transactions) self.__db.insert_transactions(converted) - - def parse(self, filename: str, args: dict): - transactions = parse_data(filename, args) - self.add_transactions(transactions) diff --git a/pfbudget/core/transactions.py b/pfbudget/core/transactions.py index 406c87d..19c3531 100644 --- a/pfbudget/core/transactions.py +++ b/pfbudget/core/transactions.py @@ -101,3 +101,6 @@ class Transaction: return "{} {} {}€ at {}".format( self.date.strftime("%d/%m/%y"), self.category, self.value, self.bank ) + + +Transactions = list[Transaction] diff --git a/pfbudget/utils/converters.py b/pfbudget/utils/converters.py index 8d780cb..75780dd 100644 --- a/pfbudget/utils/converters.py +++ b/pfbudget/utils/converters.py @@ -1,6 +1,6 @@ from functools import singledispatch -from pfbudget.core.transactions import Transaction +from pfbudget.core.transactions import Transaction, TransactionError, Transactions @singledispatch @@ -14,5 +14,15 @@ def _(t: Transaction) -> list: @convert.register -def _(transactions: list) -> list[list]: +def _(t: list) -> Transaction: + try: + return Transaction(t) + except TransactionError: + print(f"{t} is in the wrong format") + + +def convert_transactions(transactions) -> list[list]: return [convert(c) for c in transactions] + + +convert.register(type(Transactions), convert_transactions)