Persists banks information and requisition ID
This patch saves the bank information in the DB, in a new table. It also adds two new CLI commands, register/unregister, so enter the banking information. (This should later be done internally). It also adds new types alias for the DB transaction type and new converters. Input `transactions` method renamed to `parse`. Issue #18
This commit is contained in:
parent
ad3fe02e4f
commit
0a42db8995
@ -155,6 +155,53 @@ def argparser(manager: Manager) -> argparse.ArgumentParser:
|
||||
)
|
||||
p_report.set_defaults(func=report)
|
||||
|
||||
"""
|
||||
Register bank
|
||||
"""
|
||||
p_register = subparsers.add_parser(
|
||||
"register",
|
||||
description="Register a bank",
|
||||
parents=[help],
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
p_register.add_argument(
|
||||
"bank",
|
||||
type=str,
|
||||
nargs=1,
|
||||
help="bank option help"
|
||||
)
|
||||
p_register.add_argument(
|
||||
"--requisition",
|
||||
type=str,
|
||||
nargs=1,
|
||||
help="requisition option help"
|
||||
)
|
||||
p_register.add_argument("--invert", action="store_true")
|
||||
p_register.add_argument(
|
||||
"--description",
|
||||
type=str,
|
||||
nargs="?",
|
||||
help="description option help"
|
||||
)
|
||||
p_register.set_defaults(func=lambda args: manager.register(vars(args)))
|
||||
|
||||
"""
|
||||
Unregister bank
|
||||
"""
|
||||
p_register = subparsers.add_parser(
|
||||
"unregister",
|
||||
description="Unregister a bank",
|
||||
parents=[help],
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
p_register.add_argument(
|
||||
"bank",
|
||||
type=str,
|
||||
nargs=1,
|
||||
help="bank option help"
|
||||
)
|
||||
p_register.set_defaults(func=lambda args: manager.unregister(vars(args)))
|
||||
|
||||
"""
|
||||
Nordigen API
|
||||
"""
|
||||
|
||||
@ -9,5 +9,5 @@ class Input(ABC):
|
||||
self.options = options
|
||||
|
||||
@abstractmethod
|
||||
def transactions(self) -> Transactions:
|
||||
def parse(self) -> Transactions:
|
||||
return NotImplemented
|
||||
|
||||
@ -1,17 +1,17 @@
|
||||
import json
|
||||
|
||||
from pfbudget.core.input.input import Input
|
||||
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:
|
||||
def parse(self) -> Transactions:
|
||||
try:
|
||||
with open(self.options["json"][0], "r") as f:
|
||||
return [
|
||||
convert(
|
||||
@ -26,3 +26,5 @@ class JsonParser(Input):
|
||||
)
|
||||
for t in json.load(f)["transactions"]["booked"]
|
||||
]
|
||||
except KeyError:
|
||||
print("No json file defined")
|
||||
|
||||
@ -22,7 +22,7 @@ class Client(Input):
|
||||
|
||||
self._client.token = self.__token()
|
||||
|
||||
def transactions(self) -> Transactions:
|
||||
def parse(self) -> Transactions:
|
||||
requisition = self._client.requisition.get_requisition_by_id(self.options["id"])
|
||||
|
||||
for acc in requisition["accounts"]:
|
||||
@ -51,7 +51,7 @@ class Client(Input):
|
||||
|
||||
def download(self, id: str):
|
||||
if len(id) > 0:
|
||||
return self.transactions(id)
|
||||
return self.parse(id)
|
||||
else:
|
||||
print("you forgot the req id")
|
||||
|
||||
|
||||
@ -2,18 +2,40 @@ 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
|
||||
from pfbudget.db.schema import Bank
|
||||
from pfbudget.utils.converters import convert
|
||||
|
||||
|
||||
class Manager:
|
||||
def __init__(self, db: str):
|
||||
self.__db = DatabaseClient(db)
|
||||
self.db = db
|
||||
|
||||
def init(self):
|
||||
self.__db.init()
|
||||
client = DatabaseClient(self.db)
|
||||
client.init()
|
||||
|
||||
def register(self, args: dict):
|
||||
print(args)
|
||||
client = DatabaseClient(self.db)
|
||||
client.register_bank(
|
||||
Bank(
|
||||
(
|
||||
args["bank"][0],
|
||||
args["requisition"][0]
|
||||
if args["requisition"]
|
||||
else args["requisition"],
|
||||
args["invert"],
|
||||
args["description"],
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def unregister(self, args: dict):
|
||||
client = DatabaseClient(self.db)
|
||||
client.unregister_bank(args["bank"][0])
|
||||
|
||||
def parser(self, parser: Input):
|
||||
print(parser.transactions())
|
||||
print(parser.parse())
|
||||
|
||||
def parse(self, filename: str, args: dict):
|
||||
transactions = parse_data(filename, args)
|
||||
|
||||
@ -77,9 +77,12 @@ class DatabaseClient:
|
||||
(
|
||||
("transactions", Q.CREATE_TRANSACTIONS_TABLE),
|
||||
("backups", Q.CREATE_BACKUPS_TABLE),
|
||||
("banks", Q.CREATE_BANKS_TABLE),
|
||||
)
|
||||
)
|
||||
|
||||
"""Transaction table methods"""
|
||||
|
||||
def select_all(self) -> list[Transaction] | None:
|
||||
logger.info(f"Reading all transactions from {self.db}")
|
||||
transactions = self.__execute("SELECT * FROM transactions")
|
||||
@ -184,3 +187,13 @@ class DatabaseClient:
|
||||
dir.mkdir()
|
||||
with open(dir / filename, "w", newline="") as f:
|
||||
csv.writer(f, delimiter="\t").writerows(transactions)
|
||||
|
||||
"""Banks table methods"""
|
||||
|
||||
def register_bank(self, bank: Q.Bank):
|
||||
logger.info(f"Registering bank {bank[0]} with req_id={bank[1]}")
|
||||
self.__execute(Q.ADD_BANK, (bank[0], bank[1], bank[2], bank[3]))
|
||||
|
||||
def unregister_bank(self, bank: str):
|
||||
logger.info(f"Unregistering bank {bank}")
|
||||
self.__execute(Q.DELETE_BANK, (bank,))
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
from decimal import Decimal
|
||||
|
||||
CREATE_TRANSACTIONS_TABLE = """
|
||||
CREATE TABLE IF NOT EXISTS "transactions" (
|
||||
"date" TEXT NOT NULL,
|
||||
@ -10,6 +12,9 @@ CREATE TABLE IF NOT EXISTS "transactions" (
|
||||
);
|
||||
"""
|
||||
|
||||
DbTransaction = tuple[str, str | None, str, Decimal, str | None, str | None, str | None]
|
||||
DbTransactions = list[DbTransaction]
|
||||
|
||||
CREATE_BACKUPS_TABLE = """
|
||||
CREATE TABLE IF NOT EXISTS backups (
|
||||
datetime TEXT NOT NULL,
|
||||
@ -18,12 +23,16 @@ CREATE TABLE IF NOT EXISTS backups (
|
||||
"""
|
||||
|
||||
CREATE_BANKS_TABLE = """
|
||||
CREATE TABLE banks (
|
||||
CREATE TABLE IF NOT EXISTS banks (
|
||||
name TEXT NOT NULL PRIMARY KEY,
|
||||
url TEXT
|
||||
requisition TEXT,
|
||||
invert INTEGER,
|
||||
description TEXT
|
||||
)
|
||||
"""
|
||||
|
||||
Bank = tuple[str, str, bool]
|
||||
|
||||
ADD_TRANSACTION = """
|
||||
INSERT INTO transactions (date, description, bank, value, category) values (?,?,?,?,?)
|
||||
"""
|
||||
@ -83,3 +92,12 @@ WHERE date BETWEEN (?) AND (?)
|
||||
AND category NOT IN {}
|
||||
ORDER BY date ASC
|
||||
"""
|
||||
|
||||
ADD_BANK = """
|
||||
INSERT INTO banks (name, requisition, invert, description) values (?,?,?,?)
|
||||
"""
|
||||
|
||||
DELETE_BANK = """
|
||||
DELETE FROM banks
|
||||
WHERE name = (?)
|
||||
"""
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from functools import singledispatch
|
||||
|
||||
from pfbudget.core.transactions import Transaction, TransactionError, Transactions
|
||||
from pfbudget.db.schema import DbTransaction, DbTransactions
|
||||
|
||||
|
||||
@singledispatch
|
||||
@ -9,20 +10,35 @@ def convert(t):
|
||||
|
||||
|
||||
@convert.register
|
||||
def _(t: Transaction) -> list:
|
||||
def _(t: Transaction) -> DbTransaction:
|
||||
return (t.date, t.description, t.bank, t.value, t.category)
|
||||
|
||||
|
||||
@convert.register
|
||||
def _(t: list) -> Transaction:
|
||||
def convert_dbtransaction(db) -> Transaction:
|
||||
try:
|
||||
return Transaction(t)
|
||||
return Transaction(db)
|
||||
except TransactionError:
|
||||
print(f"{t} is in the wrong format")
|
||||
print(f"{db} is in the wrong format")
|
||||
|
||||
|
||||
def convert_transactions(transactions) -> list[list]:
|
||||
return [convert(c) for c in transactions]
|
||||
convert.register(type(DbTransaction), convert_dbtransaction)
|
||||
|
||||
|
||||
def convert_transactions(ts: Transactions) -> DbTransactions:
|
||||
try:
|
||||
return [convert(t) for t in ts]
|
||||
except TransactionError:
|
||||
print(f"{ts} is in the wrong format")
|
||||
|
||||
|
||||
convert.register(type(Transactions), convert_transactions)
|
||||
|
||||
|
||||
def convert_dbtransactions(ts: DbTransactions) -> Transactions:
|
||||
try:
|
||||
return [convert(t) for t in ts]
|
||||
except TransactionError:
|
||||
print(f"{ts} is in the wrong format")
|
||||
|
||||
|
||||
convert.register(type(DbTransactions), convert_dbtransactions)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user