Update the export operation

to work with the Manager.
Also removes the run method from the runnable.py, since everything is
done in the __main__.py file of the pfbudget module.
This commit is contained in:
Luís Murta 2023-01-08 17:35:48 +00:00
parent 9500e808de
commit 9b45ee4817
Signed by: satprog
GPG Key ID: 169EF1BBD7049F94
10 changed files with 79 additions and 36 deletions

View File

@ -251,4 +251,12 @@ if __name__ == "__main__":
pfbudget.types.Link(args["original"][0], link) for link in args["links"] pfbudget.types.Link(args["original"][0], link) for link in args["links"]
] ]
pfbudget.Manager(db, verbosity, args).action(op, params) case pfbudget.Operation.Export:
assert args.keys() >= {"interval", "start", "end", "year", "all", "banks", "file"}
start, end = pfbudget.parse_args_period(args)
params = [start, end]
if not args["all"]:
params.append(args["banks"])
params.append(args["file"][0])
pfbudget.Manager(db, verbosity).action(op, params)

View File

@ -1,4 +1,3 @@
from pathlib import Path
import argparse import argparse
import datetime as dt import datetime as dt
import decimal import decimal
@ -6,7 +5,6 @@ import re
from pfbudget.common.types import Operation from pfbudget.common.types import Operation
from pfbudget.db.model import AccountType, Period from pfbudget.db.model import AccountType, Period
from pfbudget.input.nordigen import NordigenInput
from pfbudget.db.sqlite import DatabaseClient from pfbudget.db.sqlite import DatabaseClient
import pfbudget.reporting.graph import pfbudget.reporting.graph
import pfbudget.reporting.report import pfbudget.reporting.report
@ -29,7 +27,6 @@ class DataFileMissing(Exception):
def argparser() -> argparse.ArgumentParser: def argparser() -> argparse.ArgumentParser:
universal = argparse.ArgumentParser(add_help=False) universal = argparse.ArgumentParser(add_help=False)
universal.add_argument( universal.add_argument(
"-db", "-db",
@ -75,16 +72,13 @@ def argparser() -> argparse.ArgumentParser:
) )
p_init.set_defaults(command=Operation.Init) p_init.set_defaults(command=Operation.Init)
""" # Exports transactions to .csv file
Exporting export = subparsers.add_parser("export", parents=[period])
""" export.set_defaults(op=Operation.Export)
p_export = subparsers.add_parser( export.add_argument("file", nargs=1, type=str)
"export", export_banks = export.add_mutually_exclusive_group()
description="Exports the selected database to a .csv file", export_banks.add_argument("--all", action="store_true")
parents=[universal], export_banks.add_argument("--banks", nargs="+", type=str)
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
p_export.set_defaults(func=lambda args: DatabaseClient(args.database).export())
# Parse from .csv # Parse from .csv
parse = subparsers.add_parser("parse") parse = subparsers.add_parser("parse")
@ -403,9 +397,3 @@ def link(parser: argparse.ArgumentParser):
dismantle.set_defaults(op=Operation.Dismantle) dismantle.set_defaults(op=Operation.Dismantle)
dismantle.add_argument("original", nargs=1, type=int) dismantle.add_argument("original", nargs=1, type=int)
dismantle.add_argument("links", nargs="+", type=int) dismantle.add_argument("links", nargs="+", type=int)
def run():
args = vars(argparser().parse_args())
assert "op" in args, "No operation selected"
return args["op"], args

View File

@ -33,6 +33,7 @@ class Operation(Enum):
NordigenAdd = auto() NordigenAdd = auto()
NordigenMod = auto() NordigenMod = auto()
NordigenDel = auto() NordigenDel = auto()
Export = auto()
class TransactionError(Exception): class TransactionError(Exception):

View File

@ -1,8 +1,7 @@
from pathlib import Path from pathlib import Path
from pfbudget.input.input import Input from pfbudget.common.types import Operation
from pfbudget.input.nordigen import NordigenInput from pfbudget.core.categorizer import Categorizer
from pfbudget.input.parsers import parse_data
from pfbudget.db.client import DbClient from pfbudget.db.client import DbClient
from pfbudget.db.model import ( from pfbudget.db.model import (
Bank, Bank,
@ -15,15 +14,14 @@ from pfbudget.db.model import (
Tag, Tag,
TagRule, TagRule,
) )
from pfbudget.common.types import Operation from pfbudget.input.nordigen import NordigenInput
from pfbudget.core.categorizer import Categorizer from pfbudget.input.parsers import parse_data
from pfbudget.utils import convert from pfbudget.output.csv import CSV
from pfbudget.output.output import Output
class Manager: class Manager:
def __init__(self, db: str, verbosity: int = 0, args: dict = {}): def __init__(self, db: str, verbosity: int = 0):
self._args = args
self._db = db self._db = db
self._verbosity = verbosity self._verbosity = verbosity
@ -143,6 +141,19 @@ class Manager:
links = [link.link for link in params] links = [link.link for link in params]
session.remove_links(original, links) session.remove_links(original, links)
case Operation.Export:
with self.db.session() as session:
if len(params) < 4:
banks = [bank.name for bank in session.banks()]
transactions = session.transactions(params[0], params[1], banks)
else:
transactions = session.transactions(
params[0], params[1], params[2]
)
csvwriter: Output = CSV(params[-1])
csvwriter.report(transactions)
# def init(self): # def init(self):
# client = DatabaseClient(self.__db) # client = DatabaseClient(self.__db)
# client.init() # client.init()
@ -176,12 +187,8 @@ class Manager:
@property @property
def db(self) -> DbClient: def db(self) -> DbClient:
return DbClient(self._db, self._verbosity > 0) return DbClient(self._db, self._verbosity > 2)
@db.setter @db.setter
def db(self, url: str): def db(self, url: str):
self._db = url self._db = url
@property
def args(self) -> dict:
return self._args

View File

@ -1,4 +1,5 @@
from dataclasses import asdict from dataclasses import asdict
from datetime import date
from sqlalchemy import create_engine, delete, select, update from sqlalchemy import create_engine, delete, select, update
from sqlalchemy.dialects.postgresql import insert from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.orm import Session, joinedload, selectinload from sqlalchemy.orm import Session, joinedload, selectinload
@ -128,6 +129,14 @@ class DbClient:
stmt = select(Transaction).where(~Transaction.category.has()) stmt = select(Transaction).where(~Transaction.category.has())
return self.__session.scalars(stmt).all() return self.__session.scalars(stmt).all()
def transactions(self, min: date, max: date, banks: list[str]):
stmt = select(Transaction).where(
Transaction.date >= min,
Transaction.date <= max,
Transaction.bank.in_(banks),
)
return self.__session.scalars(stmt).all()
def categories(self) -> list[Category]: def categories(self) -> list[Category]:
stmt = select(Category) stmt = select(Category)
return self.__session.scalars(stmt).all() return self.__session.scalars(stmt).all()
@ -136,5 +145,9 @@ class DbClient:
stmt = select(Tag) stmt = select(Tag)
return self.__session.scalars(stmt).all() return self.__session.scalars(stmt).all()
def banks(self) -> list[Bank]:
stmt = select(Bank)
return self.__session.scalars(stmt).all()
def session(self) -> ClientSession: def session(self) -> ClientSession:
return self.ClientSession(self.engine) return self.ClientSession(self.engine)

View File

@ -6,4 +6,4 @@ from pfbudget.db.model import Transaction
class Input(ABC): class Input(ABC):
@abstractmethod @abstractmethod
def parse(self) -> list[Transaction]: def parse(self) -> list[Transaction]:
return NotImplemented return NotImplementedError

View File

@ -0,0 +1 @@
__all__ = ["csv", "output"]

17
pfbudget/output/csv.py Normal file
View File

@ -0,0 +1,17 @@
from csv import writer
from pfbudget.db.model import Transaction
from .output import Output
class CSV(Output):
def __init__(self, filename: str):
self.fn = filename
def report(self, transactions: list[Transaction]):
with open(self.fn, "w", newline="") as f:
w = writer(f, delimiter="\t")
w.writerows(
[(t.date, t.description, t.amount, t.bank) for t in transactions]
)

View File

@ -0,0 +1,9 @@
from abc import ABC, abstractmethod
from pfbudget.db.model import Transaction
class Output(ABC):
@abstractmethod
def report(self, transactions: list[Transaction]):
raise NotImplementedError

View File

@ -61,7 +61,6 @@ def find_credit_institution(fn, banks, creditcards):
def parse_args_period(args: dict): def parse_args_period(args: dict):
start, end = date.min, date.max start, end = date.min, date.max
print(args)
if args["start"]: if args["start"]:
start = datetime.strptime(args["start"][0], "%Y/%m/%d").date() start = datetime.strptime(args["start"][0], "%Y/%m/%d").date()