Export/Import categories and groups

This commit is contained in:
Luís Murta 2023-01-23 00:06:36 +00:00
parent dd0aaa01b8
commit 8760f5a0a4
Signed by: satprog
GPG Key ID: 169EF1BBD7049F94
5 changed files with 85 additions and 3 deletions

View File

@ -241,6 +241,10 @@ if __name__ == "__main__":
| pfbudget.Operation.ImportCategoryRules | pfbudget.Operation.ImportCategoryRules
| pfbudget.Operation.ExportTagRules | pfbudget.Operation.ExportTagRules
| pfbudget.Operation.ImportTagRules | pfbudget.Operation.ImportTagRules
| pfbudget.Operation.ExportCategories
| pfbudget.Operation.ImportCategories
| pfbudget.Operation.ExportCategoryGroups
| pfbudget.Operation.ImportCategoryGroups
): ):
keys = {"file"} keys = {"file"}
assert args.keys() >= keys, f"missing {args.keys() - keys}" assert args.keys() >= keys, f"missing {args.keys() - keys}"

View File

@ -286,6 +286,14 @@ def category(parser: argparse.ArgumentParser):
group = commands.add_parser("group") group = commands.add_parser("group")
category_group(group) category_group(group)
export = commands.add_parser("export")
export.set_defaults(op=Operation.ExportCategories)
export_args(export)
pimport = commands.add_parser("import")
pimport.set_defaults(op=Operation.ImportCategories)
export_args(pimport)
def category_group(parser: argparse.ArgumentParser): def category_group(parser: argparse.ArgumentParser):
commands = parser.add_subparsers(required=True) commands = parser.add_subparsers(required=True)
@ -298,6 +306,14 @@ def category_group(parser: argparse.ArgumentParser):
remove.set_defaults(op=Operation.GroupRemove) remove.set_defaults(op=Operation.GroupRemove)
remove.add_argument("group", nargs="+", type=str) remove.add_argument("group", nargs="+", type=str)
export = commands.add_parser("export")
export.set_defaults(op=Operation.ExportCategoryGroups)
export_args(export)
pimport = commands.add_parser("import")
pimport.set_defaults(op=Operation.ImportCategoryGroups)
export_args(pimport)
def category_rule(parser: argparse.ArgumentParser): def category_rule(parser: argparse.ArgumentParser):
commands = parser.add_subparsers(required=True) commands = parser.add_subparsers(required=True)

View File

@ -43,6 +43,10 @@ class Operation(Enum):
ImportCategoryRules = auto() ImportCategoryRules = auto()
ExportTagRules = auto() ExportTagRules = auto()
ImportTagRules = auto() ImportTagRules = auto()
ExportCategories = auto()
ImportCategories = auto()
ExportCategoryGroups = auto()
ImportCategoryGroups = auto()
class TransactionError(Exception): class TransactionError(Exception):

View File

@ -11,6 +11,7 @@ from pfbudget.db.model import (
Category, Category,
CategoryGroup, CategoryGroup,
CategoryRule, CategoryRule,
CategorySchedule,
CategorySelector, CategorySelector,
Link, Link,
MoneyTransaction, MoneyTransaction,
@ -255,6 +256,41 @@ class Manager:
with self.db.session() as session: with self.db.session() as session:
session.add(rules) session.add(rules)
case Operation.ExportCategories:
with self.db.session() as session:
self.dump(params[0], session.get(Category))
case Operation.ImportCategories:
# rules = [Category(**row) for row in self.load(params[0])]
categories = []
for row in self.load(params[0]):
category = Category(row["name"], row["group"])
if len(row["rules"]) > 0:
# Only category rules could have been created with a rule
rules = row["rules"]
for rule in rules:
del rule["type"]
category.rules = set(CategoryRule(**rule) for rule in rules)
if row["schedule"]:
category.schedule = CategorySchedule(**row["schedule"])
categories.append(category)
if self.certify(categories):
with self.db.session() as session:
session.add(categories)
case Operation.ExportCategoryGroups:
with self.db.session() as session:
self.dump(params[0], session.get(CategoryGroup))
case Operation.ImportCategoryGroups:
groups = [CategoryGroup(**row) for row in self.load(params[0])]
if self.certify(groups):
with self.db.session() as session:
session.add(groups)
def parse(self, filename: Path, args: dict): def parse(self, filename: Path, args: dict):
return parse_data(filename, args) return parse_data(filename, args)

View File

@ -146,13 +146,17 @@ class SplitTransaction(Transaction):
return super().format | dict(original=self.original) return super().format | dict(original=self.original)
class CategoryGroup(Base): class CategoryGroup(Base, Export):
__tablename__ = "categories_groups" __tablename__ = "categories_groups"
name: Mapped[str] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(primary_key=True)
@property
def format(self) -> dict[str, Any]:
return dict(name=self.name)
class Category(Base):
class Category(Base, Export):
__tablename__ = "categories_available" __tablename__ = "categories_available"
name: Mapped[str] = mapped_column(primary_key=True) name: Mapped[str] = mapped_column(primary_key=True)
@ -170,6 +174,15 @@ class Category(Base):
def __repr__(self) -> str: def __repr__(self) -> str:
return f"Category(name={self.name}, group={self.group}, #rules={len(self.rules)}, schedule={self.schedule})" return f"Category(name={self.name}, group={self.group}, #rules={len(self.rules)}, schedule={self.schedule})"
@property
def format(self) -> dict[str, Any]:
return dict(
name=self.name,
group=self.group.format if self.group else None,
rules=[rule.format for rule in self.rules],
schedule=self.schedule.format if self.schedule else None,
)
catfk = Annotated[ catfk = Annotated[
str, str,
@ -282,7 +295,7 @@ class Period(enum.Enum):
scheduleperiod = Annotated[Selector, mapped_column(Enum(Period, inherit_schema=True))] scheduleperiod = Annotated[Selector, mapped_column(Enum(Period, inherit_schema=True))]
class CategorySchedule(Base): class CategorySchedule(Base, Export):
__tablename__ = "categories_schedules" __tablename__ = "categories_schedules"
name: Mapped[catfk] = mapped_column(primary_key=True) name: Mapped[catfk] = mapped_column(primary_key=True)
@ -290,6 +303,15 @@ class CategorySchedule(Base):
period_multiplier: Mapped[Optional[int]] period_multiplier: Mapped[Optional[int]]
amount: Mapped[Optional[int]] amount: Mapped[Optional[int]]
@property
def format(self) -> dict[str, Any]:
return dict(
name=self.name,
period=self.period,
period_multiplier=self.period_multiplier,
amount=self.amount,
)
class Link(Base): class Link(Base):
__tablename__ = "links" __tablename__ = "links"