first ruggedy draft
This commit is contained in:
150
apps/api/mousehold_api/routers/projects.py
Normal file
150
apps/api/mousehold_api/routers/projects.py
Normal file
@@ -0,0 +1,150 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from .. import models
|
||||
from ..db import get_session
|
||||
from ..schemas import (
|
||||
PaymentLineCreate,
|
||||
PaymentLineRead,
|
||||
ProjectBudgetLineCreate,
|
||||
ProjectBudgetLineRead,
|
||||
ProjectCreate,
|
||||
ProjectParticipantCreate,
|
||||
ProjectParticipantRead,
|
||||
ProjectPlannedItemCreate,
|
||||
ProjectPlannedItemRead,
|
||||
ProjectRead,
|
||||
ProjectSummary,
|
||||
SettlementSummary,
|
||||
)
|
||||
from ..services.projects import calculate_project_summary
|
||||
from ..services.settlement import calculate_settlement
|
||||
|
||||
router = APIRouter(tags=["projects"])
|
||||
|
||||
|
||||
def _get_project(session: Session, project_id: str) -> models.Project:
|
||||
project = session.get(models.Project, project_id)
|
||||
if not project:
|
||||
raise HTTPException(status_code=404, detail="Project not found")
|
||||
return project
|
||||
|
||||
|
||||
@router.post("/projects", response_model=ProjectRead)
|
||||
def create_project(
|
||||
payload: ProjectCreate, session: Session = Depends(get_session)
|
||||
) -> models.Project:
|
||||
project = models.Project(**payload.model_dump(exclude={"participant_user_ids"}))
|
||||
session.add(project)
|
||||
session.flush()
|
||||
for user_id in payload.participant_user_ids:
|
||||
session.add(models.ProjectParticipant(project_id=project.id, user_id=user_id))
|
||||
session.commit()
|
||||
session.refresh(project)
|
||||
return project
|
||||
|
||||
|
||||
@router.get("/projects", response_model=list[ProjectRead])
|
||||
def list_projects(
|
||||
household_id: str, session: Session = Depends(get_session)
|
||||
) -> list[models.Project]:
|
||||
return list(
|
||||
session.scalars(
|
||||
select(models.Project)
|
||||
.where(models.Project.household_id == household_id)
|
||||
.order_by(models.Project.created_at.desc())
|
||||
).all()
|
||||
)
|
||||
|
||||
|
||||
@router.get("/projects/{project_id}", response_model=ProjectRead)
|
||||
def get_project(project_id: str, session: Session = Depends(get_session)) -> models.Project:
|
||||
return _get_project(session, project_id)
|
||||
|
||||
|
||||
@router.post("/projects/{project_id}/participants", response_model=ProjectParticipantRead)
|
||||
def add_project_participant(
|
||||
project_id: str,
|
||||
payload: ProjectParticipantCreate,
|
||||
session: Session = Depends(get_session),
|
||||
) -> models.ProjectParticipant:
|
||||
_get_project(session, project_id)
|
||||
participant = models.ProjectParticipant(project_id=project_id, **payload.model_dump())
|
||||
session.add(participant)
|
||||
session.commit()
|
||||
session.refresh(participant)
|
||||
return participant
|
||||
|
||||
|
||||
@router.post("/projects/{project_id}/budget-lines", response_model=ProjectBudgetLineRead)
|
||||
def add_project_budget_line(
|
||||
project_id: str,
|
||||
payload: ProjectBudgetLineCreate,
|
||||
session: Session = Depends(get_session),
|
||||
) -> models.ProjectBudgetLine:
|
||||
_get_project(session, project_id)
|
||||
budget_line = models.ProjectBudgetLine(project_id=project_id, **payload.model_dump())
|
||||
session.add(budget_line)
|
||||
session.commit()
|
||||
session.refresh(budget_line)
|
||||
return budget_line
|
||||
|
||||
|
||||
@router.post("/projects/{project_id}/planned-items", response_model=ProjectPlannedItemRead)
|
||||
def add_project_planned_item(
|
||||
project_id: str,
|
||||
payload: ProjectPlannedItemCreate,
|
||||
session: Session = Depends(get_session),
|
||||
) -> models.ProjectPlannedItem:
|
||||
_get_project(session, project_id)
|
||||
planned_item = models.ProjectPlannedItem(project_id=project_id, **payload.model_dump())
|
||||
session.add(planned_item)
|
||||
session.commit()
|
||||
session.refresh(planned_item)
|
||||
return planned_item
|
||||
|
||||
|
||||
@router.post("/projects/{project_id}/payment-lines", response_model=PaymentLineRead)
|
||||
def add_project_payment_line(
|
||||
project_id: str,
|
||||
payload: PaymentLineCreate,
|
||||
session: Session = Depends(get_session),
|
||||
) -> models.PaymentLine:
|
||||
_get_project(session, project_id)
|
||||
if payload.planned_item_id and not session.get(
|
||||
models.ProjectPlannedItem, payload.planned_item_id
|
||||
):
|
||||
raise HTTPException(status_code=404, detail="Planned item not found")
|
||||
payment_line = models.PaymentLine(**payload.model_dump())
|
||||
session.add(payment_line)
|
||||
session.commit()
|
||||
session.refresh(payment_line)
|
||||
return payment_line
|
||||
|
||||
|
||||
@router.get("/projects/{project_id}/summary", response_model=ProjectSummary)
|
||||
def get_project_summary(project_id: str, session: Session = Depends(get_session)) -> ProjectSummary:
|
||||
try:
|
||||
return calculate_project_summary(session, project_id)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=404, detail=str(exc)) from exc
|
||||
|
||||
|
||||
@router.get("/projects/{project_id}/settlement", response_model=SettlementSummary)
|
||||
def get_project_settlement(
|
||||
project_id: str,
|
||||
currency: str = "EUR",
|
||||
include_announced: bool = False,
|
||||
session: Session = Depends(get_session),
|
||||
) -> SettlementSummary:
|
||||
project = _get_project(session, project_id)
|
||||
return calculate_settlement(
|
||||
session,
|
||||
household_id=project.household_id,
|
||||
project_id=project_id,
|
||||
currency=currency,
|
||||
include_announced=include_announced,
|
||||
)
|
||||
Reference in New Issue
Block a user