Projeto do Agent Contas ORACLE
This commit is contained in:
346
tests/migration/test_cancel_wrapper_remaining_parity.py
Normal file
346
tests/migration/test_cancel_wrapper_remaining_parity.py
Normal file
@@ -0,0 +1,346 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
def _result(name: str, status: str, output: dict, *, error: str | None = None):
|
||||
return {
|
||||
"execution_id": f"exec-{name}",
|
||||
"workflow_name": name,
|
||||
"workflow_version": 1,
|
||||
"status": status,
|
||||
"output": output,
|
||||
"state": {},
|
||||
"trace": [],
|
||||
"error": error,
|
||||
"error_details": None,
|
||||
}
|
||||
|
||||
|
||||
class _Service:
|
||||
def consultar_faturas(self, *, msisdn: str):
|
||||
return {
|
||||
"billingProfile": {"customer": {"document": "12345678901", "customerId": "344575482"}},
|
||||
"paymentItems": [{"invoiceId": "5536806781", "dueDate": "2025-08-11"}],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_success_implicito_por_cancelados_sem_flag_success(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i = 0
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.i += 1
|
||||
if self.i == 1:
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"cancelados": [{"msisdn": payload["msisdn"], "servico": "Tamboro Mensal", "valor": "14,99"}],
|
||||
"itens_para_contestacao": [{"msisdn": payload["msisdn"], "subject": "Tamboro Mensal"}],
|
||||
}})
|
||||
return _result(name, "COMPLETED", {
|
||||
"registrar_protocolo": {"protocolo_id": "PRT-D2EFF9B40B", "protocol_closed": True},
|
||||
"abrir_contestacao_cliente": {"success": True, "contested_items": [{"itemName": "Tamboro Mensal", "status": "INICIADA"}]},
|
||||
})
|
||||
|
||||
runtime = Runtime()
|
||||
monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
|
||||
monkeypatch.setattr(main, "service", _Service())
|
||||
result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "Tamboro Mensal", "valor": "14,99"})
|
||||
assert result["success"] is True
|
||||
assert result["protocol_closed"] is True
|
||||
assert result["contestacao_protocol"] == "PRT-D2EFF9B40B"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_lista_explicita_vazia_de_candidatos_nao_faz_fallback_para_cancelados(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.calls = []
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.calls.append(name)
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"cancelados": [{"msisdn": payload["msisdn"], "servico": "TIM Fashion Mensal"}],
|
||||
"contestation_candidates": [],
|
||||
}})
|
||||
|
||||
runtime = Runtime()
|
||||
monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
|
||||
result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "TIM Fashion Mensal", "valor": "14,99"})
|
||||
assert runtime.calls == ["cancelamento_vas_avulso"]
|
||||
assert result["success"] is True
|
||||
assert "contestacao_workflow" not in result
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_no_match_nao_contesta_valor_nem_chama_contestacao(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.calls = []
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.calls.append(name)
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"results": [{"success": False, "subject": "Inexistente", "error": "serviço não encontrado", "reason": "service_not_found"}],
|
||||
"contestation_candidates": [],
|
||||
"nao_encontrados": [{"servico": "Inexistente"}],
|
||||
}})
|
||||
|
||||
runtime = Runtime()
|
||||
monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
|
||||
result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "Inexistente", "valor": "99,99"})
|
||||
assert runtime.calls == ["cancelamento_vas_avulso"]
|
||||
assert result["success"] is False
|
||||
assert "contestacao_workflow" not in result
|
||||
assert "99,99" not in result["mensagem"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_protocol_closed_da_contestacao_e_preservado(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i = 0
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.i += 1
|
||||
if self.i == 1:
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"results": [{"success": True, "subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"]}],
|
||||
"contestation_candidates": [{"success": True, "subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"]}],
|
||||
}})
|
||||
return _result(name, "COMPLETED", {
|
||||
"registrar_protocolo": {"protocolo_id": "PRT-200", "protocol_closed": True},
|
||||
"abrir_contestacao_cliente": {"success": True, "contested_items": [{"itemName": "TIM Fashion Mensal", "status": "INICIADA"}], "protocol_closed": True},
|
||||
})
|
||||
|
||||
runtime = Runtime()
|
||||
monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
|
||||
monkeypatch.setattr(main, "service", _Service())
|
||||
result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "TIM Fashion Mensal", "valor": "14,99"})
|
||||
assert result["success"] is True
|
||||
assert result["protocol_closed"] is True
|
||||
assert result["contestacao_protocol"] == "PRT-200"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_sms_flag_interno_nao_vaza_no_contrato_externo(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i = 0
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.i += 1
|
||||
if self.i == 1:
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"results": [{"success": True, "subject": "Conteudo Premium", "msisdn": payload["msisdn"]}],
|
||||
"contestation_candidates": [{"success": True, "subject": "Conteudo Premium", "msisdn": payload["msisdn"]}],
|
||||
}})
|
||||
return _result(name, "COMPLETED", {
|
||||
"registrar_protocolo": {"protocolo_id": "PRT-201"},
|
||||
"abrir_contestacao_cliente": {"success": True},
|
||||
"enviar_sms": {"success": True, "sms_sent": True},
|
||||
})
|
||||
|
||||
runtime = Runtime()
|
||||
monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
|
||||
monkeypatch.setattr(main, "service", _Service())
|
||||
result = await main._run_cancelamento_com_contestacao({"msisdn": "5511988887777", "subject": "Conteudo Premium", "valor": "9,90"})
|
||||
assert result["contestacao_protocol"] == "PRT-201"
|
||||
assert "sms_sent" not in result
|
||||
assert result["sms_not_send_error"] is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_cancelamento_com_protocolo_sem_item_contestado_continua_resolvido(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i = 0
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.i += 1
|
||||
if self.i == 1:
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"cancelados": [{"msisdn": payload["msisdn"], "servico": "Tamboro Mensal"}],
|
||||
"itens_para_contestacao": [{"msisdn": payload["msisdn"], "subject": "Tamboro Mensal"}],
|
||||
"protocolos_por_linha": [{"msisdn": payload["msisdn"], "protocolo_id": "PRT-CANCEL-1"}],
|
||||
}})
|
||||
return _result(name, "COMPLETED", {
|
||||
"registrar_protocolo": {"protocolo_id": "PRT-CONTEST-1"},
|
||||
"abrir_contestacao_cliente": {"success": True, "contested_items": [], "not_contested_items": [], "contested_invoice_amount_open": "0"},
|
||||
})
|
||||
|
||||
runtime = Runtime()
|
||||
monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
|
||||
monkeypatch.setattr(main, "service", _Service())
|
||||
result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "Tamboro Mensal", "valor": "14,99"})
|
||||
assert result["success"] is True
|
||||
assert result["recomenda_finalizacao"] is True
|
||||
assert result["status_finalizacao_sugerido"] == "resolvido"
|
||||
assert result["protocols_for_response"] == ["PRT-CANCEL-1", "PRT-CONTEST-1"]
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_falha_sms_e_propagada_sem_expor_sms_sent(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i = 0
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.i += 1
|
||||
if self.i == 1:
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"results": [{"success": True, "subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"]}],
|
||||
"contestation_candidates": [{"success": True, "subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"]}],
|
||||
}})
|
||||
return _result(name, "COMPLETED", {
|
||||
"registrar_protocolo": {"protocolo_id": "PRT-101"},
|
||||
"abrir_contestacao_cliente": {"success": True},
|
||||
"enviar_sms": {"success": False, "sms_sent": False, "sms_not_send_error": True},
|
||||
})
|
||||
|
||||
runtime = Runtime()
|
||||
monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
|
||||
monkeypatch.setattr(main, "service", _Service())
|
||||
result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "TIM Fashion Mensal", "valor": "14,99"})
|
||||
assert result["success"] is True
|
||||
assert result["sms_not_send_error"] is True
|
||||
assert "sms_sent" not in result
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_candidato_explicito_e_contestado_mesmo_sem_cancelamento_bem_sucedido(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i = 0; self.calls=[]
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.i += 1; self.calls.append((name, payload))
|
||||
if self.i == 1:
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"results": [{"success": False, "subject": "Inexistente", "reason": "service_not_found", "error": "não encontrado"}],
|
||||
"contestation_candidates": [{"success": False, "subject": "Inexistente", "msisdn": payload["msisdn"], "iu_reason": "service_not_found"}],
|
||||
}})
|
||||
return _result(name, "COMPLETED", {
|
||||
"registrar_protocolo": {"protocolo_id": "PRT-CANDIDATO"},
|
||||
"abrir_contestacao_cliente": {"success": True, "contested_items": [{"itemName": "Inexistente", "status": "INICIADA"}]},
|
||||
})
|
||||
|
||||
runtime = Runtime()
|
||||
monkeypatch.setattr(main, "get_workflow_runtime", lambda: runtime)
|
||||
monkeypatch.setattr(main, "service", _Service())
|
||||
result = await main._run_cancelamento_com_contestacao({"msisdn": "5511999999999", "subject": "Inexistente", "valor": "14,99"})
|
||||
assert [x[0] for x in runtime.calls] == ["cancelamento_vas_avulso", "contestacao_tool"]
|
||||
assert runtime.calls[1][1]["items"][0]["itemName"] == "Inexistente"
|
||||
assert runtime.calls[1][1]["items"][0]["claimedAmount"] == "14,99"
|
||||
assert result["contestacao_protocol"] == "PRT-CANDIDATO"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("reason,error", [("block_vas_failed", "Timeout no bloqueio"), ("cancel_vas_failed", "Erro no cancelamento")])
|
||||
async def test_falha_parcial_rt01_ainda_dispara_rt02(monkeypatch, reason, error):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i=0; self.calls=[]
|
||||
async def arun(self, name, payload, execution_id=None):
|
||||
self.i += 1; self.calls.append((name,payload))
|
||||
if self.i == 1:
|
||||
return _result(name, "COMPLETED", {"cancelar_vas_avulso": {
|
||||
"results": [{"success": False, "subject": "TIM Fashion Mensal", "reason": reason, "error": error}],
|
||||
"nao_cancelados": [{"servico": "TIM Fashion Mensal", "motivo": reason, "erro": error}],
|
||||
"contestation_candidates": [{"subject": "TIM Fashion Mensal", "msisdn": payload["msisdn"], "motivo": reason, "erro": error}],
|
||||
}})
|
||||
return _result(name, "COMPLETED", {
|
||||
"registrar_protocolo": {"protocolo_id": "PRT-RT02"},
|
||||
"abrir_contestacao_cliente": {"success": True, "contested_items": [{"itemName": "TIM Fashion Mensal", "status": "INICIADA"}]},
|
||||
})
|
||||
|
||||
runtime=Runtime()
|
||||
monkeypatch.setattr(main,"get_workflow_runtime",lambda:runtime)
|
||||
monkeypatch.setattr(main,"service",_Service())
|
||||
result=await main._run_cancelamento_com_contestacao({"msisdn":"5511999999999","subject":"TIM Fashion Mensal","valor":"14,99"})
|
||||
assert [x[0] for x in runtime.calls] == ["cancelamento_vas_avulso","contestacao_tool"]
|
||||
assert result["contestacao_protocol"] == "PRT-RT02"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_holder_msisdn_nao_e_trocado_pela_linha_dependente(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i=0; self.calls=[]
|
||||
async def arun(self,name,payload,execution_id=None):
|
||||
self.i += 1; self.calls.append((name,payload))
|
||||
if self.i == 1:
|
||||
return _result(name,"COMPLETED",{"cancelar_vas_avulso":{
|
||||
"results":[{"success":True,"subject":"TIM Fashion Mensal","msisdn":"5511888880000"}],
|
||||
"contestation_candidates":[{"success":True,"subject":"TIM Fashion Mensal","msisdn":"5511888880000"}],
|
||||
}})
|
||||
return _result(name,"COMPLETED",{"registrar_protocolo":{"protocolo_id":"PRT-FAM"},"abrir_contestacao_cliente":{"success":True}})
|
||||
|
||||
runtime=Runtime()
|
||||
monkeypatch.setattr(main,"get_workflow_runtime",lambda:runtime)
|
||||
monkeypatch.setattr(main,"service",_Service())
|
||||
await main._run_cancelamento_com_contestacao({
|
||||
"msisdn":"5511888880000",
|
||||
"holder_msisdn":"5511999999999",
|
||||
"items":[{"msisdn":"5511888880000","name":"TIM Fashion Mensal","value":"14,99"}],
|
||||
})
|
||||
assert runtime.calls[0][1]["msisdn"] == "5511999999999"
|
||||
assert runtime.calls[1][1]["msisdn"] == "5511999999999"
|
||||
assert runtime.calls[1][1]["dependent_invoice_item"] is True
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_item_do_titular_nao_e_marcado_como_dependente(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i=0; self.calls=[]
|
||||
async def arun(self,name,payload,execution_id=None):
|
||||
self.i += 1; self.calls.append((name,payload))
|
||||
if self.i == 1:
|
||||
return _result(name,"COMPLETED",{"cancelar_vas_avulso":{
|
||||
"results":[{"success":True,"subject":"TIM Games","msisdn":"5511999999999"}],
|
||||
"contestation_candidates":[{"success":True,"subject":"TIM Games","msisdn":"5511999999999"}],
|
||||
}})
|
||||
return _result(name,"COMPLETED",{"registrar_protocolo":{"protocolo_id":"PRT-TIT"},"abrir_contestacao_cliente":{"success":True}})
|
||||
|
||||
runtime=Runtime()
|
||||
monkeypatch.setattr(main,"get_workflow_runtime",lambda:runtime)
|
||||
monkeypatch.setattr(main,"service",_Service())
|
||||
await main._run_cancelamento_com_contestacao({"msisdn":"5511999999999","subject":"TIM Games","valor":"9,90"})
|
||||
assert runtime.calls[1][1]["dependent_invoice_item"] is False
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_titular_e_dependentes_permancem_em_uma_unica_contestacao(monkeypatch):
|
||||
import contas_mcp.servers.contas_mcp_server.main as main
|
||||
|
||||
class Runtime:
|
||||
def __init__(self): self.i=0; self.calls=[]
|
||||
async def arun(self,name,payload,execution_id=None):
|
||||
self.i += 1; self.calls.append((name,payload))
|
||||
if self.i == 1:
|
||||
cands=[
|
||||
{"success":True,"subject":"TIM Games","msisdn":"5511999999999"},
|
||||
{"success":True,"subject":"TIM Fashion Mensal","msisdn":"5511888880000"},
|
||||
{"success":True,"subject":"Tamboro Mensal","msisdn":"5511777770000"},
|
||||
]
|
||||
return _result(name,"COMPLETED",{"cancelar_vas_avulso":{"results":cands,"contestation_candidates":cands}})
|
||||
return _result(name,"COMPLETED",{"registrar_protocolo":{"protocolo_id":"PRT-FAM-3"},"abrir_contestacao_cliente":{"success":True}})
|
||||
|
||||
runtime=Runtime()
|
||||
monkeypatch.setattr(main,"get_workflow_runtime",lambda:runtime)
|
||||
monkeypatch.setattr(main,"service",_Service())
|
||||
await main._run_cancelamento_com_contestacao({
|
||||
"msisdn":"5511999999999",
|
||||
"items":[
|
||||
{"msisdn":"5511999999999","name":"TIM Games","value":"9,90"},
|
||||
{"msisdn":"5511888880000","name":"TIM Fashion Mensal","value":"14,99"},
|
||||
{"msisdn":"5511777770000","name":"Tamboro Mensal","value":"8,50"},
|
||||
],
|
||||
})
|
||||
assert [x[0] for x in runtime.calls] == ["cancelamento_vas_avulso","contestacao_tool"]
|
||||
contest=runtime.calls[1][1]
|
||||
assert contest["msisdn"] == "5511999999999"
|
||||
assert {x["itemName"] for x in contest["items"]} == {"TIM Games","TIM Fashion Mensal","Tamboro Mensal"}
|
||||
assert contest["dependent_invoice_item"] is True
|
||||
Reference in New Issue
Block a user