Subclass the Transaction with multiple children

Each children is essentually a type of transaction. We currently have:
- bank transactions
- money transactions
- split transactions

The table inheritance is implemented as a single table, with a
polymorphic type and Null columns.

Adds a IsSplit interface, which will later be used for the category
views, so as to not repeat transactions.
This commit is contained in:
Luís Murta 2023-01-10 23:42:37 +00:00
parent 0d287624c4
commit 478bd25190
Signed by: satprog
GPG Key ID: 169EF1BBD7049F94
4 changed files with 105 additions and 8 deletions

View File

@ -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 ###

View File

@ -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"

View File

@ -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

View File

@ -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,