Changing Account/category structure and Adding transactions and splits

This commit is contained in:
2025-01-25 01:56:41 +01:00
parent 38c5a69130
commit cda36315c3
20 changed files with 424 additions and 160 deletions

View File

View File

@@ -0,0 +1,127 @@
from decimal import Decimal
from uuid import UUID, uuid4
from sqlmodel import Field, SQLModel, select, Relationship
from pydantic import Field as PydField
from account.models import Account, AccountRead
from payee.models import Payee, PayeeRead
class TransactionBase(SQLModel):
pass
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(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: 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
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 = PydField(json_schema_extra={
"foreign_key": {
"reference": {
"resource": "payees",
"schema": "PayeeRead",
"label": "name"
}
}
})
class TransactionWrite(TransactionBase):
splits: list[SplitWrite] = Field()
class TransactionCreate(TransactionWrite):
pass
class TransactionUpdate(TransactionWrite):
pass
class Split(SplitBaseId, table=True):
transaction: Transaction = Relationship(back_populates="splits")
account: Account | None = Relationship()
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

View File

@@ -0,0 +1,46 @@
from uuid import UUID
from fastapi import APIRouter, HTTPException, Depends
from fastapi_pagination import Page
from fastapi_pagination.ext.sqlmodel import paginate
from transaction.models import Transaction, TransactionCreate, TransactionRead, TransactionUpdate
from db import SessionDep
from user.manager import get_current_user
router = APIRouter()
@router.post("")
def create_transaction(transaction: TransactionCreate, session: SessionDep, current_user=Depends(get_current_user)) -> TransactionRead:
result = Transaction.create(transaction, session)
return result
@router.get("")
def read_transactions(session: SessionDep, current_user=Depends(get_current_user)) -> Page[TransactionRead]:
return paginate(session, Transaction.list())
@router.get("/{transaction_id}")
def read_transaction(transaction_id: UUID, session: SessionDep, current_user=Depends(get_current_user)) -> TransactionRead:
transaction = Transaction.get(session, transaction_id)
if not transaction:
raise HTTPException(status_code=404, detail="Transaction not found")
return transaction
@router.put("/{transaction_id}")
def update_transaction(transaction_id: UUID, transaction: TransactionUpdate, session: SessionDep, current_user=Depends(get_current_user)) -> TransactionRead:
db_transaction = Transaction.get(session, transaction_id)
if not db_transaction:
raise HTTPException(status_code=404, detail="Transaction not found")
transaction_data = transaction.model_dump(exclude_unset=True)
transaction = Transaction.update(session, db_transaction, transaction_data)
return transaction
@router.delete("/{transaction_id}")
def delete_transaction(transaction_id: UUID, session: SessionDep, current_user=Depends(get_current_user)):
transaction = Transaction.get(session, transaction_id)
if not transaction:
raise HTTPException(status_code=404, detail="Transaction not found")
Transaction.delete(session, transaction)
return {"ok": True}