105 lines
3.4 KiB
Python
105 lines
3.4 KiB
Python
import uuid
|
|
from datetime import date
|
|
from typing import Sequence
|
|
|
|
from sqlalchemy import and_, func, select
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.models.attachment import Attachment
|
|
from app.models.special_expense import SpecialExpense
|
|
from app.models.site import Site
|
|
from app.schemas.special_expense import SpecialExpenseCreate, SpecialExpenseUpdate
|
|
|
|
|
|
async def create_special_expense(
|
|
db: AsyncSession,
|
|
expense_in: SpecialExpenseCreate,
|
|
created_by: uuid.UUID | None,
|
|
) -> SpecialExpense:
|
|
expense = SpecialExpense(
|
|
project_id=expense_in.project_id,
|
|
center_id=expense_in.center_id,
|
|
category=expense_in.category,
|
|
amount=expense_in.amount,
|
|
happen_date=expense_in.happen_date,
|
|
description=expense_in.description,
|
|
is_paid=expense_in.is_paid,
|
|
paid_date=expense_in.paid_date,
|
|
is_verified=expense_in.is_verified,
|
|
verified_date=expense_in.verified_date,
|
|
created_by=created_by,
|
|
)
|
|
db.add(expense)
|
|
await db.commit()
|
|
await db.refresh(expense)
|
|
return expense
|
|
|
|
|
|
async def get_special_expense(db: AsyncSession, expense_id: uuid.UUID) -> SpecialExpense | None:
|
|
result = await db.execute(select(SpecialExpense).where(SpecialExpense.id == expense_id))
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
async def list_special_expenses(
|
|
db: AsyncSession,
|
|
project_id: uuid.UUID,
|
|
center_id: uuid.UUID | None = None,
|
|
center_ids: set[uuid.UUID] | None = None,
|
|
category: str | None = None,
|
|
date_from: date | None = None,
|
|
date_to: date | None = None,
|
|
) -> Sequence[tuple[SpecialExpense, str | None, int]]:
|
|
attachment_count = func.count(Attachment.id).label("attachments_count")
|
|
attachment_types = ["special_expense_voucher", "special_expense_invoice", "special_expense_other"]
|
|
stmt = (
|
|
select(
|
|
SpecialExpense,
|
|
Site.name.label("center_name"),
|
|
attachment_count,
|
|
)
|
|
.outerjoin(Site, Site.id == SpecialExpense.center_id)
|
|
.outerjoin(
|
|
Attachment,
|
|
and_(
|
|
Attachment.entity_type.in_(attachment_types),
|
|
Attachment.entity_id == SpecialExpense.id,
|
|
Attachment.is_deleted.is_(False),
|
|
),
|
|
)
|
|
.where(SpecialExpense.project_id == project_id)
|
|
.group_by(SpecialExpense.id, Site.name)
|
|
.order_by(SpecialExpense.happen_date.desc().nullslast(), SpecialExpense.created_at.desc())
|
|
)
|
|
|
|
if center_id:
|
|
stmt = stmt.where(SpecialExpense.center_id == center_id)
|
|
if center_ids is not None:
|
|
if not center_ids:
|
|
return []
|
|
stmt = stmt.where(SpecialExpense.center_id.in_(center_ids))
|
|
if category:
|
|
stmt = stmt.where(SpecialExpense.category == category)
|
|
if date_from:
|
|
stmt = stmt.where(SpecialExpense.happen_date >= date_from)
|
|
if date_to:
|
|
stmt = stmt.where(SpecialExpense.happen_date <= date_to)
|
|
|
|
result = await db.execute(stmt)
|
|
return result.all()
|
|
|
|
|
|
async def update_special_expense(
|
|
db: AsyncSession, expense: SpecialExpense, expense_in: SpecialExpenseUpdate
|
|
) -> SpecialExpense:
|
|
update_data = expense_in.model_dump(exclude_unset=True)
|
|
for key, value in update_data.items():
|
|
setattr(expense, key, value)
|
|
await db.commit()
|
|
await db.refresh(expense)
|
|
return expense
|
|
|
|
|
|
async def delete_special_expense(db: AsyncSession, expense: SpecialExpense) -> None:
|
|
await db.delete(expense)
|
|
await db.commit()
|