Files
agent_contas/tests/migration/test_tim_event_metadata_parity.py

267 lines
10 KiB
Python

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"