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:
parent
0d287624c4
commit
478bd25190
74
alembic/versions/37d80de801a7_inheritance.py
Normal file
74
alembic/versions/37d80de801a7_inheritance.py
Normal 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 ###
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user