diff --git a/alembic/versions/37d80de801a7_inheritance.py b/alembic/versions/37d80de801a7_inheritance.py new file mode 100644 index 0000000..f9d7ee4 --- /dev/null +++ b/alembic/versions/37d80de801a7_inheritance.py @@ -0,0 +1,74 @@ +"""Inheritance + +Revision ID: 37d80de801a7 +Revises: 8cc9870b0d74 +Create Date: 2023-01-10 22:41:03.540108+00:00 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "37d80de801a7" +down_revision = "8cc9870b0d74" +branch_labels = None +depends_on = None + + +def upgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.add_column( + "originals", + sa.Column("type", sa.String(), nullable=False), + schema="transactions", + ) + op.add_column( + "originals", + sa.Column("split", sa.Boolean(), nullable=True), + schema="transactions", + ) + op.add_column( + "originals", + sa.Column("original", sa.BigInteger(), nullable=True), + schema="transactions", + ) + op.alter_column( + "originals", + "bank", + existing_type=sa.TEXT(), + nullable=True, + schema="transactions", + ) + op.create_foreign_key( + op.f("fk_originals_original_originals"), + "originals", + "originals", + ["original"], + ["id"], + source_schema="transactions", + referent_schema="transactions", + ondelete="CASCADE", + ) + # ### end Alembic commands ### + + +def downgrade() -> None: + # ### commands auto generated by Alembic - please adjust! ### + op.drop_constraint( + op.f("fk_originals_original_originals"), + "originals", + schema="transactions", + type_="foreignkey", + ) + op.alter_column( + "originals", + "bank", + existing_type=sa.TEXT(), + nullable=False, + schema="transactions", + ) + op.drop_column("originals", "original", schema="transactions") + op.drop_column("originals", "split", schema="transactions") + op.drop_column("originals", "type", schema="transactions") + # ### end Alembic commands ### diff --git a/pfbudget/db/model.py b/pfbudget/db/model.py index b961d6d..adfdf2b 100644 --- a/pfbudget/db/model.py +++ b/pfbudget/db/model.py @@ -74,14 +74,17 @@ class Transaction(Base): id: Mapped[idpk] = mapped_column(init=False) date: Mapped[dt.date] description: Mapped[Optional[str]] - bank: Mapped[bankfk] amount: Mapped[money] + type: Mapped[str] = mapped_column(init=False) + category: Mapped[Optional[TransactionCategory]] = relationship(init=False) note: Mapped[Optional[Note]] = relationship(init=False) tags: Mapped[Optional[set[TransactionTag]]] = relationship(init=False) - def __lt__(self, other): + __mapper_args__ = {"polymorphic_on": "type", "polymorphic_identity": "transaction"} + + def __lt__(self, other: Transaction): return self.date < other.date @@ -90,6 +93,26 @@ idfk = Annotated[ ] +class IsSplit: + split: Mapped[bool] = mapped_column(use_existing_column=True, nullable=True) + + +class BankTransaction(IsSplit, Transaction): + bank: Mapped[bankfk] = mapped_column(nullable=True) + + __mapper_args__ = {"polymorphic_identity": "bank", "polymorphic_load": "inline"} + + +class MoneyTransaction(IsSplit, Transaction): + __mapper_args__ = {"polymorphic_identity": "money"} + + +class SplitTransaction(Transaction): + original: Mapped[idfk] = mapped_column(nullable=True) + + __mapper_args__ = {"polymorphic_identity": "split", "polymorphic_load": "inline"} + + class CategoryGroup(Base): __tablename__ = "categories_groups" diff --git a/pfbudget/input/nordigen.py b/pfbudget/input/nordigen.py index d9cef9a..14e166e 100644 --- a/pfbudget/input/nordigen.py +++ b/pfbudget/input/nordigen.py @@ -7,7 +7,7 @@ from uuid import uuid4 import json import os -from pfbudget.db.model import Transaction +from pfbudget.db.model import BankTransaction from pfbudget.utils import convert from .input import Input @@ -29,7 +29,7 @@ class NordigenInput(Input): self._start = date.min self._end = date.max - def parse(self) -> list[Transaction]: + def parse(self) -> list[BankTransaction]: transactions = [] assert len(self._banks) > 0 diff --git a/pfbudget/utils/converters.py b/pfbudget/utils/converters.py index d1d6630..62461c1 100644 --- a/pfbudget/utils/converters.py +++ b/pfbudget/utils/converters.py @@ -1,8 +1,8 @@ -from datetime import date, timedelta +from datetime import date from functools import singledispatch from pfbudget.common.types import TransactionError -from pfbudget.db.model import Bank, Transaction +from pfbudget.db.model import Bank, BankTransaction from .utils import parse_decimal @@ -13,10 +13,10 @@ def convert(t): @convert.register -def _(json: dict, bank: Bank) -> Transaction: +def _(json: dict, bank: Bank) -> BankTransaction: i = -1 if bank.nordigen.invert else 1 try: - transaction = Transaction( + transaction = BankTransaction( date=date.fromisoformat(json["bookingDate"]), description=json["remittanceInformationUnstructured"], bank=bank.name,