fix(crm): correcciones de revisión adversarial en servicios de dominio

- convert_lead valida embudo/etapa en el scope tenant/company (evita fuga multi-tenant y 500)
- oportunidades: estado/probabilidad/cierre se derivan de la etapa también en create/update (no solo move)
- oportunidades: valida que la etapa pertenezca al embudo indicado
- cuentas: country por defecto 'MX' (el server_default no aplicaba con NULL explícito)
- convert_lead: contact_name se normaliza (evita first_name vacío)
- +4 tests que fijan el comportamiento corregido (28 en verde)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Aduanasoft
2026-07-14 09:53:56 -06:00
parent af02145332
commit 3b8da8b4cc
5 changed files with 187 additions and 41 deletions

View File

@@ -1,3 +1,6 @@
import pytest
from fastapi import HTTPException
from api.v1.modules.crm.leads import service
from api.v1.modules.crm.leads.dto import LeadConvert, LeadCreate
from api.v1.modules.crm.pipelines import service as pipelines_service
@@ -6,6 +9,13 @@ from api.v1.modules.crm.pipelines.dto import PipelineCreate, StageCreate
T, C = 1, 1
def test_convert_rejects_invalid_stage(db):
lead = service.create_lead(db, LeadCreate(name="P", company_name="Empresa"), T, C)
with pytest.raises(HTTPException) as exc:
service.convert_lead(db, lead.id, LeadConvert(create_opportunity=True, stage_id=999), T, C)
assert exc.value.status_code == 422
def test_create_lead_defaults_to_new(db):
lead = service.create_lead(db, LeadCreate(name="Prospecto X", company_name="XYZ SA"), T, C)
assert lead.status == "new"