"""Локальная очередь заказов (синхронизируется из CRM) — список, вкладки, правка, удаление.""" from __future__ import annotations from fastapi import APIRouter, Depends, HTTPException, Request, status from app.api.deps import CashierUser, CrmClientDep, SessionDep, require_any from app.db.models.audit import AuditAction from app.schemas.orders import OrderRowOut, OrdersSummaryOut, OrderUpdateIn from app.services import audit from app.services import orders as orders_service from app.services import receipts as receipts_service from app.services.orders import OrderTab router = APIRouter(prefix="/orders", tags=["orders"], dependencies=[Depends(require_any)]) @router.get("", response_model=list[OrderRowOut], response_model_by_alias=False) async def list_orders( session: SessionDep, crm: CrmClientDep, tab: OrderTab = OrderTab.NO_RECEIPT ) -> list[OrderRowOut]: # by_alias=False: без этого FastAPI сериализует вложенные OrderGoodOut через # CRM-алиасы (SKU/Name/...) вместо snake_case полей, которые ждёт фронтенд. await orders_service.sync_orders_from_crm(session, crm) orders = await orders_service.list_orders(session, tab=tab) receipts = await receipts_service.latest_receipts_by_order( session, [order.id for order in orders] ) return [OrderRowOut.from_order(order, receipts.get(order.id)) for order in orders] @router.get("/summary", response_model=OrdersSummaryOut) async def orders_summary(session: SessionDep) -> OrdersSummaryOut: count, kopecks = await orders_service.cod_in_transit(session) return OrdersSummaryOut( cod_in_transit_count=count, cod_in_transit_amount=f"{kopecks / 100:.2f}" ) @router.patch("/{order_id}", response_model=OrderRowOut, response_model_by_alias=False) async def update_order( order_id: str, payload: OrderUpdateIn, request: Request, session: SessionDep, actor: CashierUser, ) -> OrderRowOut: try: result = await orders_service.update_order(session, order_id, payload) except orders_service.OrderEditError as exc: raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=str(exc)) from exc if result is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Заказ не найден") order, changed = result if changed: await audit.record( session, action=AuditAction.ORDER_UPDATED, user=actor, entity_type="order", entity_id=order.id, payload={"fields": changed}, request=request, ) await session.commit() receipts = await receipts_service.latest_receipts_by_order(session, [order.id]) return OrderRowOut.from_order(order, receipts.get(order.id)) @router.delete("/{order_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_order( order_id: str, request: Request, session: SessionDep, actor: CashierUser ) -> None: order = await orders_service.delete_order(session, order_id) if order is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Заказ не найден") await audit.record( session, action=AuditAction.ORDER_DELETED, user=actor, entity_type="order", entity_id=order.id, request=request, ) await session.commit()