import pytest from fastapi import HTTPException from api.v1.modules.crm.accounts import service as accounts_service from api.v1.modules.crm.accounts.dto import AccountCreate from api.v1.modules.crm.contacts import service as contacts_service from api.v1.modules.crm.contacts.dto import ContactCreate from api.v1.modules.crm.opportunities import service as opp_service from api.v1.modules.crm.opportunities.dto import OpportunityCreate from api.v1.modules.crm.service_requests import service from api.v1.modules.crm.service_requests.dto import ( RateRequestCreate, ServiceRequestCreate, ServiceRequestFromOpportunityInput, ServiceRequestUpdate, ) T, C = 1, 1 def test_create_service_request(db): acc = accounts_service.create_account(db, AccountCreate(name="Cliente"), T, C) sr = service.create_service_request( db, ServiceRequestCreate( account_id=acc.id, operation_type="exportacion", transport_mode="maritimo", service_type="puerta_puerta", origin="Manzanillo", destination="Long Beach", incoterm="FOB", load_type="FCL", ), T, C, user_id="dev", ) assert sr.id is not None assert sr.status == "nueva" assert sr.created_by == "dev" def test_service_request_rejects_unknown_account(db): with pytest.raises(HTTPException) as exc: service.create_service_request(db, ServiceRequestCreate(account_id=999, operation_type="importacion"), T, C) assert exc.value.status_code == 422 def test_filter_by_operation_and_status(db): service.create_service_request(db, ServiceRequestCreate(operation_type="exportacion"), T, C) service.create_service_request(db, ServiceRequestCreate(operation_type="importacion"), T, C) exp = service.get_service_requests(db, T, C, operation_type="exportacion") assert len(exp) == 1 and exp[0].operation_type == "exportacion" def test_rate_request_requires_service_request(db): with pytest.raises(HTTPException) as exc: service.create_rate_request( db, RateRequestCreate(service_request_id=999, concept="flete_internacional"), T, C ) assert exc.value.status_code == 404 def test_rate_request_ok_and_listed(db): sr = service.create_service_request(db, ServiceRequestCreate(operation_type="exportacion"), T, C) service.create_rate_request( db, RateRequestCreate(service_request_id=sr.id, concept="flete_internacional", rate_amount=1200, currency="USD"), T, C, ) rates = service.get_rate_requests(db, T, C, service_request_id=sr.id) assert len(rates) == 1 and rates[0].concept == "flete_internacional" def test_update_service_request_status(db): sr = service.create_service_request(db, ServiceRequestCreate(operation_type="exportacion"), T, C) upd = service.update_service_request(db, sr.id, ServiceRequestUpdate(status="en_analisis"), T, C) assert upd.status == "en_analisis" # ----- Campos del documento maestro de cotización ----- def test_create_service_request_new_fields(db): sr = service.create_service_request( db, ServiceRequestCreate( operation_type="importacion", load_type="LCL", priority="alta", origin_country="CHN", origin_city="Shanghai", destination_country="MEX", destination_city="Manzanillo", cargo_value=15000, insurance_required=True, hazardous_imo=True, pieces_count=12, net_weight=800, measurement_unit="kg", additional_services=["seguro", "despacho_aduanal"], payment_method="99", client_notes="Manejo con cuidado", ), T, C, ) assert sr.origin_country == "CHN" assert sr.insurance_required is True assert sr.hazardous_imo is True assert sr.additional_services == ["seguro", "despacho_aduanal"] assert sr.pieces_count == 12 def test_service_request_rejects_unknown_contact(db): with pytest.raises(HTTPException) as exc: service.create_service_request( db, ServiceRequestCreate(operation_type="importacion", contact_id=999), T, C ) assert exc.value.status_code == 422 def test_service_request_generates_folio(db): sr = service.create_service_request(db, ServiceRequestCreate(operation_type="exportacion"), T, C) assert sr.reference is not None assert sr.reference.startswith("S") assert sr.reference.endswith("-E") def test_service_request_accepts_ambas(db): sr = service.create_service_request( db, ServiceRequestCreate(operation_type="exportacion", load_type="AMBAS"), T, C ) assert sr.load_type == "AMBAS" def test_from_opportunity_inherits_operation_type_and_backlink(db): acc = accounts_service.create_account(db, AccountCreate(name="Cliente"), T, C) contact = contacts_service.create_contact( db, ContactCreate(account_id=acc.id, first_name="Ana"), T, C ) opp = opp_service.create_opportunity( db, OpportunityCreate(name="Negocio", account_id=acc.id, contact_id=contact.id, operation_type="importacion"), T, C, ) sr = service.create_from_opportunity( db, opp.id, ServiceRequestFromOpportunityInput(transport_mode="aereo"), T, C, user_id="dev" ) # Hereda dirección y contacto de la oportunidad assert sr.operation_type == "importacion" assert sr.contact_id == contact.id assert sr.opportunity_id == opp.id assert sr.reference.startswith("S") and sr.reference.endswith("-I") # Back-link en la oportunidad refreshed = opp_service.get_opportunity(db, opp.id, T, C) assert refreshed.converted_service_request_id == sr.id def test_from_opportunity_idempotent(db): opp = opp_service.create_opportunity( db, OpportunityCreate(name="Negocio", operation_type="exportacion"), T, C ) first = service.create_from_opportunity(db, opp.id, ServiceRequestFromOpportunityInput(), T, C) second = service.create_from_opportunity(db, opp.id, ServiceRequestFromOpportunityInput(), T, C) assert first.id == second.id # no crea una segunda solicitud def test_from_opportunity_without_direction_fails(db): opp = opp_service.create_opportunity(db, OpportunityCreate(name="Sin dirección"), T, C) with pytest.raises(HTTPException) as exc: service.create_from_opportunity(db, opp.id, ServiceRequestFromOpportunityInput(), T, C) assert exc.value.status_code == 422