Files
agent_contas/tests/migration/test_original_vas_cancellation_message.py

353 lines
14 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Paridade do compositor determinístico com o prompt
``fluxo_vas_cancelamento_resposta_cliente`` (regras 1.1, 28).
Os goldens de sucesso/erro/SMS vêm dos próprios exemplos do prompt em
``builtin/prompts/vas_cancellation_response.yaml``.
"""
from __future__ import annotations
from app.domain.contas.vas_cancellation_message import (
compose_vas_cancellation_message,
)
PRT = "PRT475D8F1C1F"
def test_regra_3_sucesso_com_sms_singular() -> None:
# Exemplo do prompt: "Exemplo (sucesso com SMS)".
msg = compose_vas_cancellation_message(
{
"contested_items": [{"itemName": "Tamboro Mensal"}],
"contested_invoice_amount_open": "22,00",
"sms_sent": True,
"sms_not_send_error": False,
"msisdn": "11999999999",
"contestacao_protocol": PRT,
}
)
assert msg == (
"O cancelamento foi concluído com sucesso. O valor contestado foi retirado "
"da sua fatura. Enviamos um SMS com o novo código de barras e o valor "
"atualizado. O prazo para pagamento é de 4 dias. "
f"Seu número de protocolo é {PRT}."
)
def test_regra_3_e_6_2_falha_no_sms_plural() -> None:
# Exemplo do prompt: "Exemplo (sucesso com falha no SMS)".
msg = compose_vas_cancellation_message(
{
"contested_items": [
{"itemName": "Tamboro Mensal"},
{"itemName": "TIM Fashion"},
],
"contested_invoice_amount_open": "22,00",
"sms_sent": True,
"sms_not_send_error": True,
"msisdn": "11999999999",
"contestacao_protocol": PRT,
}
)
assert msg == (
"O cancelamento dos itens foi concluído com sucesso. O valor total de "
"R$ 22,00 foi retirado da sua fatura. Identificamos uma instabilidade no "
"envio do SMS com o novo código para pagamento. Você pode consultar o "
"código atualizado e o prazo de pagamento diretamente no app Meu TIM. "
f"Seu número de protocolo é {PRT}."
)
def test_regra_2_credito_plural_com_regra_5() -> None:
# Baseado no "Exemplo (crédito em fatura)" do prompt; o conector "No entanto,"
# era floreio do LLM — a forma determinística segue o template literal da regra 5.
msg = compose_vas_cancellation_message(
{
"contested_items": [
{"itemName": "Aluguel de Série 1"},
{"itemName": "Aluguel de Série 2"},
],
"not_contested_items": [{"itemName": "Tamboro Mensal"}],
"contested_invoice_amount_open": "22,00",
"sms_sent": False,
"contestacao_protocol": PRT,
}
)
assert msg == (
"O cancelamento dos itens foi feito com sucesso. O crédito no valor total "
"de R$ 22,00 ficou registrado como crédito para sua próxima fatura. "
"Não foi possível contestar o item Tamboro Mensal. "
f"Seu número de protocolo é {PRT}."
)
def test_regra_2_credito_singular() -> None:
msg = compose_vas_cancellation_message(
{
"contested_items": [{"itemName": "Tamboro Mensal"}],
"contested_invoice_amount_open": "22,00",
"sms_sent": False,
"contestacao_protocol": PRT,
}
)
assert msg == (
"O cancelamento do item Tamboro Mensal no valor de R$ 22,00 foi concluído "
"com sucesso. O valor contestado ficou registrado como crédito para sua "
f"próxima fatura. Seu número de protocolo é {PRT}."
)
def test_regra_8_erro_terminal_copia_literal_e_protocolo() -> None:
# Exemplo do prompt: "Exemplo (falha, usando um dos textos de ...)".
erro = (
"Verifiquei aqui que este item já foi contestado anteriormente, por isso "
"não consigo seguir com uma nova contestação. Peço que aguarde um instante."
)
msg = compose_vas_cancellation_message(
{
"contestation_error_description": erro,
"contestacao_protocol": PRT,
}
)
assert msg == f"{erro} Seu número de protocolo é {PRT}."
def test_regra_8_adiciona_ponto_quando_texto_nao_termina_em_pontuacao() -> None:
msg = compose_vas_cancellation_message(
{
"contestation_error_description": "Não foi possível processar",
"contestacao_protocol": PRT,
}
)
assert msg == f"Não foi possível processar. Seu número de protocolo é {PRT}."
def test_regra_8_item_ja_contestado_informa_cancelamentos_realizados() -> None:
msg = compose_vas_cancellation_message(
{
"cancelados": [{"servico": "A"}, {"servico": "B"}],
"contestation_error_description": (
"Verifiquei aqui que estes itens já foram contestados anteriormente, "
"por isso não consigo seguir com uma nova contestação."
),
"contestacao_protocol": PRT,
}
)
assert msg == (
"O cancelamento dos itens A e B foi concluído com sucesso. "
"Verifiquei aqui que estes itens já foram contestados anteriormente, "
"por isso não consigo seguir com uma nova contestação. "
f"Seu número de protocolo é {PRT}."
)
def test_regra_1_1_misto_credito() -> None:
msg = compose_vas_cancellation_message(
{
"itens_ja_contestados": ["Tamboro Mensal"],
"contested_items": [{"itemName": "TIM Fashion"}],
"contested_invoice_amount_open": "10,00",
"sms_sent": False,
"contestacao_protocol": PRT,
}
)
assert msg == (
"Identifiquei que o item Tamboro Mensal já havia sido contestado "
"anteriormente e, por esse motivo, não é possível registrar uma nova "
"contestação para ele. Já a contestação do item TIM Fashion no valor de "
"R$ 10,00 foi concluída com sucesso. O valor contestado ficou registrado "
f"como crédito para sua próxima fatura. Seu número de protocolo é {PRT}."
)
def test_regra_1_1_misto_com_sms_aplica_regra_6() -> None:
msg = compose_vas_cancellation_message(
{
"itens_ja_contestados": ["A", "B"],
"contested_items": [{"itemName": "C"}, {"itemName": "D"}],
"contested_invoice_amount_open": "30,00",
"sms_sent": True,
"sms_not_send_error": False,
"msisdn": "11988887777",
"contestacao_protocol": PRT,
}
)
assert msg == (
"O cancelamento foi concluído com sucesso. O valor contestado foi retirado "
"da sua fatura. Enviamos um SMS com o novo código de barras e o valor "
"atualizado. O prazo para pagamento é de 4 dias. "
f"Seu número de protocolo é {PRT}."
)
def test_sms_enviado_prevalece_quando_contested_items_esta_vazio() -> None:
# Regressão do trace 6ae8bd24: SMS efetivamente enviado nunca vira crédito.
msg = compose_vas_cancellation_message(
{
"itens_ja_contestados": ["Tamboro Mensal"],
"contested_items": [],
"contested_invoice_amount_open": "22,00",
"sms_sent": True,
"contestacao_protocol": PRT,
}
)
assert msg == (
"O cancelamento foi concluído com sucesso. O valor contestado foi retirado "
"da sua fatura. Enviamos um SMS com o novo código de barras e o valor "
"atualizado. O prazo para pagamento é de 4 dias. "
f"Seu número de protocolo é {PRT}."
)
assert "próxima fatura" not in msg
def test_regra_7_protocolos_multiplos() -> None:
msg = compose_vas_cancellation_message(
{
"contested_items": [{"itemName": "Tamboro Mensal"}],
"contested_invoice_amount_open": "22,00",
"sms_sent": False,
"contestacao_protocols": ["PRTAAA", "PRTBBB"],
}
)
assert msg.endswith("Seus números de protocolo são PRTAAA e PRTBBB.")
def test_no_match_credito_todos_nao_encontrados_singular() -> None:
# Cenário 2 (crédito): serviço não localizado na plataforma; valor contestado.
msg = compose_vas_cancellation_message(
{
"success": True,
"contested_items": [{"itemName": "Tamboro Mensal"}],
"nao_encontrados": [{"servico": "Tamboro Mensal"}],
"cancelados": [],
"contested_invoice_amount_open": "22,00",
"sms_sent": False,
"contestacao_protocol": PRT,
}
)
assert msg == (
"O valor total de R$ 22,00 ficou registrado como crédito para sua próxima "
"fatura. Sobre o cancelamento do serviço Tamboro Mensal, não consegui "
"realizar por aqui. Você pode cancelar pelo App Meu TIM, na opção "
f"Gerenciar Benefícios. Seu número de protocolo é {PRT}."
)
def test_no_match_sms_todos_nao_encontrados() -> None:
# Cenário 2 (SMS/boleto): valor retirado + SMS + no-match.
msg = compose_vas_cancellation_message(
{
"success": True,
"contested_items": [{"itemName": "Tamboro Mensal"}],
"nao_encontrados": [{"servico": "Tamboro Mensal"}],
"cancelados": [],
"contested_invoice_amount_open": "22,00",
"sms_sent": True,
"sms_not_send_error": False,
"msisdn": "11999999999",
"contestacao_protocol": PRT,
}
)
assert msg == (
"O valor total de R$ 22,00 foi retirado da sua fatura. Enviamos um SMS com "
"o novo código de barras e o valor atualizado. O prazo para pagamento é de "
"4 dias. Sobre o cancelamento do serviço Tamboro "
"Mensal, não consegui realizar por aqui. Você pode cancelar pelo App Meu "
f"TIM, na opção Gerenciar Benefícios. Seu número de protocolo é {PRT}."
)
def test_no_match_misto_credito() -> None:
# Cenário 3 (crédito): A,B,C cancelados; D,E,F no-match.
msg = compose_vas_cancellation_message(
{
"success": True,
"contested_items": [{"itemName": x} for x in ("A", "B", "C", "D", "E", "F")],
"cancelados": [{"servico": x} for x in ("A", "B", "C")],
"nao_encontrados": [{"servico": x} for x in ("D", "E", "F")],
"contested_invoice_amount_open": "60,00",
"sms_sent": False,
"contestacao_protocol": PRT,
}
)
assert msg == (
"O valor total de R$ 60,00 ficou registrado como crédito para sua próxima "
"fatura. O cancelamento dos serviços A, B e C foram realizados com sucesso. "
"Não consegui realizar por aqui o cancelamento dos serviços D, E e F. Você "
"pode cancelá-los pelo App Meu TIM, na opção Gerenciar Benefícios. "
f"Seu número de protocolo é {PRT}."
)
def test_no_match_misto_sms() -> None:
# Cenário 3 (SMS/boleto).
msg = compose_vas_cancellation_message(
{
"success": True,
"contested_items": [{"itemName": x} for x in ("A", "B", "C", "D", "E", "F")],
"cancelados": [{"servico": x} for x in ("A", "B", "C")],
"nao_encontrados": [{"servico": x} for x in ("D", "E", "F")],
"contested_invoice_amount_open": "60,00",
"sms_sent": True,
"sms_not_send_error": False,
"msisdn": "11988887777",
"contestacao_protocol": PRT,
}
)
assert msg == (
"O valor total de R$ 60,00 foi retirado da sua fatura. Enviamos um SMS com "
"o novo código de barras e o valor atualizado. O prazo para pagamento é de "
"4 dias. O cancelamento dos serviços A, B e C foram "
"realizados com sucesso. Não consegui realizar por aqui o cancelamento dos "
"serviços D, E e F. Você pode cancelá-los pelo App Meu TIM, na opção "
f"Gerenciar Benefícios. Seu número de protocolo é {PRT}."
)
def test_no_match_misto_singular_cada_lista() -> None:
# Concordância: 1 cancelado + 1 no-match.
msg = compose_vas_cancellation_message(
{
"success": True,
"contested_items": [{"itemName": "A"}, {"itemName": "B"}],
"cancelados": [{"servico": "A"}],
"nao_encontrados": [{"servico": "B"}],
"contested_invoice_amount_open": "20,00",
"sms_sent": False,
"contestacao_protocol": PRT,
}
)
assert msg == (
"O valor total de R$ 20,00 ficou registrado como crédito para sua próxima "
"fatura. O cancelamento do serviço A foi realizado com sucesso. Não "
"consegui realizar por aqui o cancelamento do serviço B. Você pode "
f"cancelá-lo pelo App Meu TIM, na opção Gerenciar Benefícios. Seu número "
f"de protocolo é {PRT}."
)
def test_sucesso_sem_itens_detalhados_gera_confirmacao_generica() -> None:
# Sem itens contestados/não contestados/já contestados, mas cancelamento OK:
# confirmação neutra + protocolo (regra 7).
msg = compose_vas_cancellation_message(
{
"success": True,
"contested_items": [],
"not_contested_items": [],
"contestacao_protocol": PRT,
}
)
assert msg == f"O cancelamento foi concluído com sucesso. Seu número de protocolo é {PRT}."
def test_sucesso_sem_itens_e_sem_protocolo_so_confirmacao() -> None:
# Protocolo de cancelamento (não de contestação) é anexado pelo backend, não aqui.
msg = compose_vas_cancellation_message({"success": True, "contested_items": []})
assert msg == "O cancelamento foi concluído com sucesso."
def test_payload_nao_classificavel_sem_sucesso_retorna_vazio() -> None:
assert compose_vas_cancellation_message({}) == ""
assert compose_vas_cancellation_message({"success": False}) == ""
assert compose_vas_cancellation_message("nao-mapping") == "" # type: ignore[arg-type]