from datetime import date from decimal import Decimal from typing import Optional from uuid import UUID, uuid4 from sqlmodel import Field, SQLModel, select, Relationship from pydantic import Field as PydField from account.models import Account from account.schemas import AccountRead from payee.models import Payee, PayeeRead class TransactionBase(SQLModel): transaction_date: date = Field() payment_date: Optional[date] = Field(default=None) class TransactionBaseId(TransactionBase): id: UUID | None = Field(default_factory=uuid4, primary_key=True) class Transaction(TransactionBaseId, table=True): splits: list["Split"] = Relationship(back_populates="transaction") @classmethod def create(cls, transaction, session): transaction_db = cls.model_validate(transaction) session.add(transaction_db) session.commit() session.refresh(transaction_db) return transaction_db @classmethod def list(cls): return select(Transaction).join(Split).join(Account) @classmethod def get(cls, session, transaction_id): return session.get(Transaction, transaction_id) @classmethod def update(cls, session, transaction_db, transaction_data): transaction_db.sqlmodel_update(cls.model_validate(transaction_data)) session.add(transaction_db) session.commit() session.refresh(transaction_db) return transaction_db @classmethod def delete(cls, session, transaction): session.delete(transaction) session.commit() class SplitBase(SQLModel): account_id: UUID = Field(foreign_key="account.id") payee_id: Optional[UUID] = Field(foreign_key="payee.id") amount: Decimal = Field(decimal_places=2) class SplitBaseId(SplitBase): transaction_id: UUID = Field(primary_key=True, foreign_key="transaction.id") id: int = Field(primary_key=True) class SplitRead(SplitBaseId): account: AccountRead payee: PayeeRead | None class TransactionRead(TransactionBaseId): splits: list[SplitRead] class SplitWrite(SplitBase): account_id: UUID = PydField(json_schema_extra={ "foreign_key": { "reference": { "resource": "accounts", "schema": "AccountRead", "label": "name" } } }) payee_id: UUID | None = PydField(json_schema_extra={ "foreign_key": { "reference": { "resource": "payees", "schema": "PayeeRead", "label": "name" } } }) amount: str = PydField(json_schema_extra={"format": "price-bgdc"}) class TransactionWrite(TransactionBase): splits: list[SplitWrite] = PydField(json_schema_extra={"minItems": 1}) class TransactionCreate(TransactionWrite): pass class TransactionUpdate(TransactionWrite): pass class Split(SplitBaseId, table=True): transaction: Transaction = Relationship(back_populates="splits") account: Account | None = Relationship(back_populates="transaction_splits") payee: Payee | None = Relationship() @classmethod def create(cls, transaction_split, session): transaction_split_db = cls.model_validate(transaction_split) session.add(transaction_split_db) session.commit() session.refresh(transaction_split_db) return transaction_split_db @classmethod def update(cls, session, transaction_db, transaction_data): transaction_db.sqlmodel_update(transaction_data) session.add(transaction_db) session.commit() session.refresh(transaction_db) return transaction_db @classmethod def delete(cls, session, transaction): session.delete(transaction) session.commit() class SplitCreate(SplitWrite): pass class SplitUpdate(SplitWrite): pass