from __future__ import annotations import json from agent_framework.analytics.tim_payload_mapper import map_analytics_event_to_tim_flat_payload from app.domain.contas.workflow_actions import build_contas_workflow_actions def _event(result: dict, code: str) -> dict: return next(x for x in result.get("business_events", []) if x.get("code") == code) def test_contestacao_vaa_metadata_preserva_contexto_tim_original(): class Client: def billing_analysis(self, msisdn): return {"currentInvoice": [{"desc": "Serviços de valor adicionado", "items": [{"desc": "VAS Musica", "value": 29.9, "classe": "avulso"}]}]} def contestar(self, payload): return {"barcode": "8469", "itemsResponse": []} class Service: client = Client() action = build_contas_workflow_actions(Service()).get("abrir_contestacao_cliente") state = { "input": { "session_id": "sess-1", "message_id": "msg-1", "ura_call_id": "CALL-123", "channel_id": "URA", } } result = action( { "msisdn": "11999998888", "protocolo_id": "PRT-11", "invoice_id": "3000135012", "servico": "VAS Musica", "valor": 29.9, }, state, ) payload = _event(result, "VAA.006")["payload"] assert payload["agentId"] == "contas" assert payload["channelId"] == "URA" assert payload["gsm"] == "11999998888" assert payload["uraCallId"] == "CALL-123" assert payload["sessionId"] == "sess-1" assert payload["messageId"] == "msg-1" assert payload["agentProtocolId"] == "PRT-11" assert payload["adjustedProtocol"] == "PRT-11" assert payload["billingId"] == "3000135012" assert payload["adjustedItems"] == ["VAS Musica"] assert payload["adjustedItemsAmount"] == ["29.9"] assert json.loads(payload["agentSpecificData"]) == { "adjustedItems": ["VAS Musica"], "adjustedItemsAmount": ["29.9"], } def test_contestacao_vaa007_falha_preserva_protocolo_e_itens(): class Client: def billing_analysis(self, msisdn): return {"currentInvoice": [{"desc": "Serviços de valor adicionado", "items": [{"desc": "VAS Musica", "value": 29.9, "classe": "avulso"}]}]} def contestar(self, payload): raise RuntimeError("falha provider") class Service: client = Client() action = build_contas_workflow_actions(Service()).get("abrir_contestacao_cliente") result = action( {"msisdn": "119", "protocolo_id": "PRT-11", "invoice_id": "INV-1", "servico": "VAS Musica", "valor": 29.9}, {"input": {"channel_id": "URA", "ura_call_id": "CALL-1"}}, ) payload = _event(result, "VAA.007")["payload"] assert payload["agentProtocolId"] == "PRT-11" assert payload["adjustedProtocol"] == "PRT-11" assert payload["adjustedItems"] == ["VAS Musica"] assert payload["adjustedItemsAmount"] == ["29.9"] def test_tim_payload_mapper_aceita_agent_specific_data_json_string_historico(): mapped = map_analytics_event_to_tim_flat_payload( "VAA.006", { "eventType": "VAA.006", "payload": { "tag": "VAA.006", "agentProtocolId": "P1", "agentSpecificData": '{"billingId":"3000131180","item":"VAS"}', }, }, ) assert mapped["agentProtocolId"] == "P1" assert mapped["agentSpecificData"] == {"billingId": "3000131180", "item": "VAS"} def test_finalizacao_cvn010_preserva_protocolos_e_contexto_ura(): from app.domain.contas.service import ContasDomainService class Client: def abrir_protocolo(self, payload): return {"interactionProtocol": "INFO-123"} def status_sr(self, payload): return {"ok": True} action = build_contas_workflow_actions(ContasDomainService(client=Client())).get("finalizar_atendimento_action") result = action( { "status": "resolvido", "summary": "ok", "msisdn": "11999999999", "social_sec_no": "123", "session_id": "sess-final", "message_id": "msg-final", "ura_call_id": "CALL-FINAL", "ura_protocol_id": "URA-123", "channel_id": "URA", "invoice_id": "3000131180", "business_workflows_executed": ["invoice_explanation"], "invoice_explanation_base": "Explicação.", }, {"input": {}}, ) payload = _event(result, "CVN.010")["payload"] assert payload["agentProtocolId"] == "INFO-123" assert payload["adjustedProtocol"] == "INFO-123" assert payload["uraProtocolId"] == "URA-123" assert payload["uraCallId"] == "CALL-FINAL" assert payload["channelId"] == "URA" assert payload["billingId"] == "3000131180" assert json.loads(payload["agentSpecificData"]) == {"billingId": "3000131180"} def test_vas_estrategico_veb_preserva_turno_e_contexto_ura(): class Client: def abrir_protocolo(self, payload): return {"interactionProtocol": "VEB-123"} class Service: client = Client() action = build_contas_workflow_actions(Service()).get("registrar_atendimento_vas_estrategico") result = action( { "linhas": [{"msisdn": "5511999999999"}], "mensagem_base": "Informação sobre cancelamento.", }, { "input": { "resposta_usuario": "NAO", "customer_message": "Não quero manter o serviço.", "ura_call_id": "155344608", "channel_id": "ura", "message_id": "msg-005", } }, ) codes = [x["code"] for x in result["business_events"]] assert codes == ["VEB.004", "VEB.006", "VEB.007"] payload = _event(result, "VEB.004")["payload"] assert payload["uraCallId"] == "155344608" assert payload["channelId"] == "ura" assert payload["messageId"] == "msg-005" assert payload["customerMessage"] == "NAO" assert payload["llmResponse"] == "Informação sobre cancelamento." def test_finalizacao_mpi006_e_sad001_preservam_metadata_conversacional(): from app.domain.contas.service import ContasDomainService class Client: def abrir_protocolo(self, payload): return {"interactionProtocol": "INFO-321"} def status_sr(self, payload): return {"ok": True} action = build_contas_workflow_actions(ContasDomainService(client=Client())).get("finalizar_atendimento_action") result = action( { "status": "resolvido", "summary": "Cliente entendeu.", "msisdn": "11999999999", "invoice_id": "3000131180", "business_workflows_executed": ["invoice_explanation"], "invoice_explanation_base": "Explicação dos valores da fatura", "customer_message": "Sim, entendi", "llm_response": "Perfeito, fico feliz em ajudar.", "message_id": "msg-final", "session_id": "sess-final", "channel_id": "URA", "ura_call_id": "CALL-FINAL", "session_end_at": "2026-06-11T12:00:00Z", }, {"input": {}}, ) mpi = _event(result, "MPI.006")["payload"] assert mpi["customerMessage"] == "Sim, entendi" assert mpi["llmResponse"] == "Perfeito, fico feliz em ajudar." assert mpi["billingId"] == "3000131180" assert mpi["messageId"] == "msg-final" assert mpi["sessionId"] == "sess-final" sad = _event(result, "SAD.001")["payload"] assert sad["llmResponse"] == "Perfeito, fico feliz em ajudar." assert sad["messageId"] == "msg-final" assert sad["sessionEndAt"] == 1781179200000 def test_vas_bundle_nao_defera_protocolo_e_emite_veb005(): class Client: def __init__(self): self.calls = 0 def abrir_protocolo(self, payload): self.calls += 1 return {"interactionProtocol": "SHOULD-NOT-HAPPEN"} client = Client() class Service: pass service = Service(); service.client = client action = build_contas_workflow_actions(service).get("registrar_atendimento_vas_estrategico") result = action( { "linhas": [{"msisdn": "5511999999999", "bundle_names": ["TIM Segurança"]}], "mensagem_base": "Bundle incluso no plano.", }, {"input": {"resposta_usuario": "NAO", "ura_call_id": "CALL-1", "channel_id": "URA", "message_id": "M1"}}, ) assert [x["code"] for x in result["business_events"]] == ["VEB.004", "VEB.005", "VEB.007"] assert client.calls == 0 assert result["protocol_closed"] is False assert result["protocol_deferred_to_finalization"] is True assert result["suppress_cvn_protocol_ic"] is True assert result["informational_vas_types"] == ["bundle"] def test_invoice_explanation_mpi005_preserva_turno_e_contexto(): class Service: pass action = build_contas_workflow_actions(Service()).get("registrar_atendimento_invoice_explanation") result = action( {"caminho": "NAO", "invoice_id": "INV-9"}, {"input": {"customer_message": "Ainda não entendi", "message_id": "M9", "session_id": "S9", "channel_id": "URA", "ura_call_id": "C9"}}, ) payload = _event(result, "MPI.005")["payload"] assert payload["customerMessage"] == "Ainda não entendi" assert payload["messageId"] == "M9" assert payload["sessionId"] == "S9" assert payload["channelId"] == "URA" assert payload["uraCallId"] == "C9" assert payload["billingId"] == "INV-9" def test_pro_rata_mpi010_preserva_contexto_do_turno(): class Service: pass action = build_contas_workflow_actions(Service()).get("preparar_pro_rata") result = action( {"planos": [], "msisdn": "11999999999"}, {"input": {"customer_message": "Por que veio proporcional?", "message_id": "MP1", "session_id": "SP1", "channel_id": "web"}}, ) payload = _event(result, "MPI.010")["payload"] assert payload["gsm"] == "11999999999" assert payload["customerMessage"] == "Por que veio proporcional?" assert payload["messageId"] == "MP1" assert payload["sessionId"] == "SP1" assert payload["channelId"] == "web"