update: Add Global Search on Header, Add Global Audit log for all actions.
This commit is contained in:
@@ -2,6 +2,7 @@ from fastapi import APIRouter, Depends, Query, UploadFile, File
|
||||
from fastapi.responses import StreamingResponse
|
||||
from typing import Optional
|
||||
import io
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from auth.dependencies import require_permission
|
||||
from auth.models import TokenPayload
|
||||
@@ -13,6 +14,8 @@ from crm.quotation_models import (
|
||||
QuotationUpdate,
|
||||
)
|
||||
from crm import quotations_service as svc
|
||||
from database.postgres import get_pg_session
|
||||
from shared.audit import log_action
|
||||
|
||||
router = APIRouter(prefix="/api/crm/quotations", tags=["crm-quotations"])
|
||||
|
||||
@@ -72,11 +75,15 @@ async def create_quotation(
|
||||
body: QuotationCreate,
|
||||
generate_pdf: bool = Query(False),
|
||||
_user: TokenPayload = Depends(require_permission("crm", "edit")),
|
||||
db: AsyncSession = Depends(get_pg_session),
|
||||
):
|
||||
"""
|
||||
Create a quotation. Pass ?generate_pdf=true to immediately generate and upload the PDF.
|
||||
"""
|
||||
return await svc.create_quotation(body, generate_pdf=generate_pdf)
|
||||
q = await svc.create_quotation(body, generate_pdf=generate_pdf)
|
||||
await log_action(db, _user.sub, _user.name or _user.email, "CREATE", "quotation",
|
||||
str(q.id), q.quotation_number or str(q.id))
|
||||
return q
|
||||
|
||||
|
||||
@router.put("/{quotation_id}", response_model=QuotationInDB)
|
||||
@@ -85,19 +92,34 @@ async def update_quotation(
|
||||
body: QuotationUpdate,
|
||||
generate_pdf: bool = Query(False),
|
||||
_user: TokenPayload = Depends(require_permission("crm", "edit")),
|
||||
db: AsyncSession = Depends(get_pg_session),
|
||||
):
|
||||
"""
|
||||
Update a quotation. Pass ?generate_pdf=true to regenerate the PDF.
|
||||
"""
|
||||
return await svc.update_quotation(quotation_id, body, generate_pdf=generate_pdf)
|
||||
old = await svc.get_quotation(quotation_id)
|
||||
q = await svc.update_quotation(quotation_id, body, generate_pdf=generate_pdf)
|
||||
_SKIP = {"updated_at", "id", "items", "pdf_path"}
|
||||
changes = {
|
||||
k: {"old": getattr(old, k, None), "new": getattr(q, k, None)}
|
||||
for k in body.model_fields_set
|
||||
if k not in _SKIP and getattr(old, k, None) != getattr(q, k, None)
|
||||
}
|
||||
await log_action(db, _user.sub, _user.name or _user.email, "UPDATE", "quotation",
|
||||
quotation_id, q.quotation_number or quotation_id, changes=changes or None)
|
||||
return q
|
||||
|
||||
|
||||
@router.delete("/{quotation_id}", status_code=204)
|
||||
async def delete_quotation(
|
||||
quotation_id: str,
|
||||
_user: TokenPayload = Depends(require_permission("crm", "edit")),
|
||||
db: AsyncSession = Depends(get_pg_session),
|
||||
):
|
||||
q = await svc.get_quotation(quotation_id)
|
||||
await svc.delete_quotation(quotation_id)
|
||||
await log_action(db, _user.sub, _user.name or _user.email, "DELETE", "quotation",
|
||||
quotation_id, q.quotation_number if q else quotation_id)
|
||||
|
||||
|
||||
@router.post("/{quotation_id}/regenerate-pdf", response_model=QuotationInDB)
|
||||
|
||||
Reference in New Issue
Block a user