From b47dc542f26a192f664ddbc94da8ff64513e8354 Mon Sep 17 00:00:00 2001 From: Ernesto Herrera Date: Fri, 7 Aug 2026 07:43:53 -0600 Subject: [PATCH] feat(crm): Cotizaciones/Cotizador vinculados (Fase B) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Lista de cotizaciones muestra la Solicitud referenciada (QuoteResponse enriquecido con service_request_reference; columna con enlace a la solicitud). - Cotizador vinculable a una solicitud (?service_request_id=) → prellena modo (mapper transport+load→RateMode), ruta, peso/dimensiones, etc. - Cotizador vinculable a una cotización (?quote_id=) → botón "Agregar" por opción que crea el concepto de flete + cargos en la cotización y regresa a ella. - Botón "Cotizador" en el detalle de la cotización (entrada vinculada). Suite de cotizaciones en verde. svelte-check sin errores nuevos. Co-Authored-By: Claude Opus 4.8 --- backend/api/v1/modules/crm/quotes/dto.py | 1 + backend/api/v1/modules/crm/quotes/service.py | 13 +++- frontend/src/lib/api/crm/commercial.ts | 1 + .../dashboard/crm/cotizaciones/+page.svelte | 2 + .../crm/cotizaciones/[id]/+page.svelte | 3 +- .../dashboard/crm/cotizador/+page.svelte | 75 ++++++++++++++++++- 6 files changed, 91 insertions(+), 4 deletions(-) diff --git a/backend/api/v1/modules/crm/quotes/dto.py b/backend/api/v1/modules/crm/quotes/dto.py index 0af9bd4..bf08c92 100644 --- a/backend/api/v1/modules/crm/quotes/dto.py +++ b/backend/api/v1/modules/crm/quotes/dto.py @@ -85,6 +85,7 @@ class QuoteResponse(QuoteBase): model_config = ConfigDict(from_attributes=True) id: int + service_request_reference: str | None = None # folio de la solicitud referenciada status: str total_cost: Decimal total_sale: Decimal diff --git a/backend/api/v1/modules/crm/quotes/service.py b/backend/api/v1/modules/crm/quotes/service.py index 5afeea2..f24c634 100644 --- a/backend/api/v1/modules/crm/quotes/service.py +++ b/backend/api/v1/modules/crm/quotes/service.py @@ -73,7 +73,18 @@ def get_quotes( query = query.filter(Quote.account_id == account_id) if search: query = query.filter(Quote.reference.ilike(f"%{search}%")) - return query.order_by(Quote.created_at.desc()).all() + quotes = query.order_by(Quote.created_at.desc()).all() + # Enriquecer con el folio de la solicitud referenciada (para verlo en la lista) + sr_ids = {q.service_request_id for q in quotes if q.service_request_id} + if sr_ids: + refs = dict( + db.query(ServiceRequest.id, ServiceRequest.reference) + .filter(ServiceRequest.id.in_(sr_ids)) + .all() + ) + for q in quotes: + q.service_request_reference = refs.get(q.service_request_id) + return quotes def get_quote(db: Session, quote_id: int, tenant_id: int, company_id: int) -> Quote: diff --git a/frontend/src/lib/api/crm/commercial.ts b/frontend/src/lib/api/crm/commercial.ts index 3afe080..850c42c 100644 --- a/frontend/src/lib/api/crm/commercial.ts +++ b/frontend/src/lib/api/crm/commercial.ts @@ -106,6 +106,7 @@ export interface Quote { id: number; reference: string | null; service_request_id: number | null; + service_request_reference: string | null; account_id: number | null; currency: string; load_type: string | null; diff --git a/frontend/src/routes/dashboard/crm/cotizaciones/+page.svelte b/frontend/src/routes/dashboard/crm/cotizaciones/+page.svelte index cc5317a..09be57f 100644 --- a/frontend/src/routes/dashboard/crm/cotizaciones/+page.svelte +++ b/frontend/src/routes/dashboard/crm/cotizaciones/+page.svelte @@ -93,6 +93,7 @@ Folio + Solicitud Estatus Total venta Margen @@ -103,6 +104,7 @@ {#each filtered as q (q.id)} {q.reference ?? `#${q.id}`} + {#if q.service_request_id}{q.service_request_reference ?? `#${q.service_request_id}`}{:else}{/if} {labelOf(QUOTE_STATUS, q.status)} {formatMoney(q.total_sale, q.currency)} {formatMoney(q.margin, q.currency)} diff --git a/frontend/src/routes/dashboard/crm/cotizaciones/[id]/+page.svelte b/frontend/src/routes/dashboard/crm/cotizaciones/[id]/+page.svelte index 9b227b8..85a7711 100644 --- a/frontend/src/routes/dashboard/crm/cotizaciones/[id]/+page.svelte +++ b/frontend/src/routes/dashboard/crm/cotizaciones/[id]/+page.svelte @@ -1,5 +1,5 @@