Changing Account/category structure and Adding transactions and splits
This commit is contained in:
0
api/app/transaction/__init__.py
Normal file
0
api/app/transaction/__init__.py
Normal file
127
api/app/transaction/models.py
Normal file
127
api/app/transaction/models.py
Normal 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
|
||||
46
api/app/transaction/routes.py
Normal file
46
api/app/transaction/routes.py
Normal 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}
|
||||
Reference in New Issue
Block a user