151 lines
4.9 KiB
Python
151 lines
4.9 KiB
Python
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,
|
|
)
|