Files
CRM_AGENTES_CARGA/backend/tests/test_catalogs_seed.py
Ernesto Herrera 915bdd19fe feat(crm): ampliar solicitud de servicio y encadenar el ciclo comercial
Solicitud de servicio:
- Campos del documento maestro de cotización (ruta estructurada por país,
  mercancía, dimensiones/bultos, FCL/LCL, servicios adicionales, notas).
- Origen/Destino seleccionables por catálogo de país (seed ya poblado).
- Validación de contacto asociado (422 si no existe).

Ciclo Oportunidad -> Solicitud -> Cotización -> Operación:
- Dirección impo/expo se captura en la Oportunidad y se hereda al ciclo.
- Conversión Oportunidad->Solicitud idempotente con back-link.
- Endpoint Solicitud->Cotización; "Ambas" genera 2 cotizaciones (FCL/LCL).
- Liberación a Operaciones confirma IMPO/EXPO (prefijado) y siembra los hitos.
- Fecha de la cotización (issue_date) por defecto hoy, editable y en el PDF.

Folios auto-generados {LETRA}{AAAA}-{MM}-{NNN}-{DIR} para Oportunidad (O),
Solicitud (S), Cotización (C) y Operación (OP); consecutivo mensual por
compañía y entidad (crm.folio_counters + helper next_folio con bloqueo de fila).

Catálogos: 9 nuevos (tipo_operacion, medio_transporte, tipo_servicio, prioridad,
tipo_mercancia, unidad_medida, tipo_embalaje, servicio_adicional, tipo_documento).

Migración b1c2d3e4f5a6 reversible (upgrade->downgrade->upgrade verificado en PG).
25 pruebas unitarias nuevas (folios, catálogos, solicitudes, cotizaciones,
embarques); suite completa en verde (101 pruebas).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-03 17:51:40 -06:00

50 lines
1.6 KiB
Python

"""Pruebas de la siembra idempotente de catálogos globales del CRM."""
from api.v1.modules.crm.catalogs.models import CatalogItem
from api.v1.modules.crm.catalogs.seed import seed_global_catalogs
# Catálogos nuevos del proceso comercial y una clave base que debe existir en cada uno.
NEW_CATALOGS = {
"tipo_operacion": "importacion",
"medio_transporte": "maritimo",
"tipo_servicio": "puerto_puerto",
"prioridad": "urgente",
"tipo_mercancia": "peligrosa",
"unidad_medida": "kg",
"tipo_embalaje": "pallet",
"servicio_adicional": "seguro",
"tipo_documento": "factura_comercial",
}
def _codes(db, catalog: str) -> set[str]:
return {
row.code
for row in db.query(CatalogItem.code).filter(
CatalogItem.catalog == catalog, CatalogItem.tenant_id.is_(None)
)
}
def test_seed_creates_new_catalogs(db):
seed_global_catalogs(db)
for catalog, base_code in NEW_CATALOGS.items():
codes = _codes(db, catalog)
assert codes, f"El catálogo {catalog} quedó vacío"
assert base_code in codes, f"Falta la clave base {base_code} en {catalog}"
def test_seed_is_idempotent(db):
first = seed_global_catalogs(db)
assert first, "La primera corrida debió sembrar filas"
second = seed_global_catalogs(db)
assert second == {}, "La segunda corrida no debe agregar filas nuevas"
def test_pais_catalog_populated(db):
"""El catálogo pais alimenta Origen/Destino de la solicitud (decisión 6)."""
seed_global_catalogs(db)
codes = _codes(db, "pais")
assert len(codes) > 100
assert "MEX" in codes