Files
ERP/backend/app/routers/quote_events.py
T
ZCode 253c922280 revert: restore production to the state before 730d0bd (PM/RBAC work moved to 'pm')
Their three commits (730d0bd, 5a9b543, 387edfb) reached production by push and
auto-deployed. 387edfb expects a users.username column that the live database does
not have, so POST /api/v1/auth/login was returning HTTP 500. Their schema changes
never applied either (projects still has only id, name, description, start_date,
pm_user_id, created_at), so nothing depends on the reverted code.

This commit sets the tree back to exactly a02b3ea — verified with git diff against
it — while keeping history linear: the work itself is preserved on 'pm' at 387edfb.
2026-09-26 17:41:07 +00:00

52 lines
2.0 KiB
Python

"""Quote events — audit timeline. Manual creation is restricted to event_type=note."""
from fastapi import APIRouter, Depends, Query
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from app.db.engine import get_db
from app.models.procurement import Quote, QuoteEvent
from app.schemas.procurement import NoteEventIn
from app.services.expand_service import event_to_dict
from app.utils.errors import NotFoundError, ValidationError
from app.utils.pagination import paginate, sort_query
router = APIRouter(prefix="/quotes/{quote_id}/events", tags=["quote-events"])
@router.get("")
async def list_events(
quote_id,
page: int = Query(1, ge=1),
page_size: int = Query(20, ge=1, le=100),
event_type: str | None = None,
sort: str | None = None,
db: AsyncSession = Depends(get_db),
):
quote = await db.get(Quote, quote_id)
if quote is None:
raise NotFoundError("پیشنهاد (استعلام) یافت نشد")
stmt = select(QuoteEvent).where(QuoteEvent.quote_id == quote_id)
if event_type:
stmt = stmt.where(QuoteEvent.event_type == event_type)
stmt = sort_query(stmt, QuoteEvent, sort, default="occurred_at") # contract default: ASC
items, meta = await paginate(stmt, page, page_size, db)
return {"data": [event_to_dict(e) for e in items], "meta": meta}
@router.post("", status_code=201)
async def create_event(quote_id, payload: NoteEventIn, db: AsyncSession = Depends(get_db)):
quote = await db.get(Quote, quote_id)
if quote is None:
raise NotFoundError("پیشنهاد (استعلام) یافت نشد")
if payload.event_type != "note":
raise ValidationError("فقط رویدادهای note به صورت دستی ثبت می‌شوند", field="event_type")
event = QuoteEvent(
quote_id=quote.id,
event_type="note",
payload=payload.payload or {},
actor=payload.actor,
)
db.add(event)
await db.flush()
return {"data": event_to_dict(event)}