from __future__ import annotations from typing import Any from app.domain.contas.pro_rata_rules import calculate_refund, payment_message from app.domain.contas.workflow_actions import build_contas_workflow_actions def planos(*, days_other=25, liquid=67.99): return [ {"desc":"TIM Controle Smart 8 0 (096/POS/SMP)","days":None,"valor_bruto":92.99,"valor_final":liquid,"msisdn":"44998254771","is_controle":True}, {"desc":"TIM Black A 8 0 (114/POS/SMP)","days":days_other,"valor_bruto":158.30,"valor_final":83.38,"msisdn":"44998254771","is_controle":False}, ] def invoice(danfe=None): return { "Fatura Resumo":[{"desc":"PERÍODO","period":"19/09 a 18/10"},{"desc":"EMISSÃO","emissao":"29/10/2025"}], "DANFE-COM": danfe or {"Planos":{"TIM Controle Smart 8 0":[ {"desc":"TIM Controle Smart 8 0","valor_final":40.0}, {"desc":"Aya Books Premium","valor_final":15.0}, {"desc":"Mulheres Positivas","valor_final":10.0}, ]}}, } def test_calculo_pro_rata_usa_liquido_periodo_e_danfe(): out=calculate_refund(planos=planos(), invoice_detail=invoice()) assert out["dias_ciclo"] == 30 assert out["dias_controle"] == 5 assert out["valor_liquido"] == "67.99" assert out["valor_devolver"] == "56.66" assert out["invoice_amount"] == "56.66" assert [x["itemName"] for x in out["items"]] == ["TIM Controle Smart 8 0","Aya Books Premium","Mulheres Positivas"] assert sum(float(x["validatedAmount"]) for x in out["items"]) == 56.66 def test_calculo_pro_rata_outro_plano_30_dias_considera_um_dia_controle(): out=calculate_refund(planos=planos(days_other=30), invoice_detail=invoice({"Planos":{"TIM Controle Smart 8 0":[{"desc":"TIM Controle Smart 8 0","valor_final":67.99}]}})) assert out["dias_controle"] == 1 assert float(out["valor_devolver"]) > 65 def test_calculo_falha_sem_periodo(): data=invoice(); data["Fatura Resumo"]=[] try: calculate_refund(planos=planos(), invoice_detail=data) except ValueError as exc: assert "Periodo" in str(exc) else: raise AssertionError("esperava falha") def test_calculo_falha_quando_danfe_nao_cobre_credito(): data=invoice({"Planos":{"TIM Controle Smart 8 0":[{"desc":"TIM Controle Smart 8 0","valor_final":1.0}]}}) try: calculate_refund(planos=planos(), invoice_detail=data) except ValueError as exc: assert "insuficientes" in str(exc) else: raise AssertionError("esperava falha") def test_mensagem_pagamento_sms_soma_items_e_protocolo(): msg=payment_message({ "items":[{"itemName":"Plano X","validatedAmount":10},{"itemName":"Extra","validatedAmount":4.99}], "format_text":"sms","barcode":"123","protocolo_id":"9988" }) assert "R$ 14,99" in msg assert "codigo de barras atualizado" in msg assert "9988" in msg class Client: def __init__(self): self.payload=None def contestar(self,payload): self.payload=payload return {"protocol_number":"PRT-1","sms_sent":True,"barcode":"3419","contestation_id":"C-1"} class Service: def __init__(self): self.client=Client() def buscar_fatura_detalhada(self, **kwargs): return {"parsed_content":invoice()} def test_action_definir_devolucao_busca_danfe_quando_ausente(): svc=Service(); reg=build_contas_workflow_actions(svc) action=reg.get("definir_devolucao_ajuste_pro_rata") out=action({"planos":planos(),"invoice_id":"INV","customer_id":"C","msisdn":"44998254771"},{"input":{}}) assert out["success"] is True assert out["invoice_amount"] == "56.66" assert out["items"] def test_action_contestacao_pro_rata_usa_items_e_totais(): svc=Service(); reg=build_contas_workflow_actions(svc) action=reg.get("executar_contestacao_plano_controle") devolucao={"items":[{"itemName":"Plano X","itemType":"PRO_RATA","claimedAmount":20.0,"validatedAmount":12.5}],"invoice_amount":"12.50","invoice_amount_open":"12.50"} out=action({"devolucao":devolucao,"msisdn":"44998254771","customer_id":"C1","invoice_id":"I1","cpf":"123.456.789-00"},{"input":{}}) assert out["success"] is True assert svc.client.payload["tipo_atendimento"] == "pro_rata" assert svc.client.payload["skip_invoice_item_validation"] is True assert svc.client.payload["invoiceAmount"] == "12.50" assert svc.client.payload["socialSecNo"] == "12345678900" assert out["devolucao"]["format_text"] == "sms" def test_orientar_pagamento_mantem_composicao_no_llm_do_framework(): svc=Service(); reg=build_contas_workflow_actions(svc) action=reg.get("orientar_pagamento_pro_rata") out=action({"devolucao":{"items":[{"itemName":"Plano X","validatedAmount":10}],"format_text":"conta_futura"}},{"input":{}}) assert "R$ 10,00" in out["mensagem"] assert out["requires_llm_composition"] is True assert "fonte de verdade" in out["response_instruction"]