from __future__ import annotations import asyncio from contas_mcp.servers.contas_mcp_server import main def _analysis(): return { "currentInvoice": [ { "type": "servicos_contratados_de_parceiros", "items": [ {"desc": "Tamboro Mensal", "value": "14.99", "contestable": True, "classe": "avulso"}, {"desc": "Tamboro Mensal", "value": "19.99", "contestable": True, "classe": "avulso"}, {"desc": "Outro Produto", "value": "19.99", "contestable": True, "classe": "avulso"}, ], } ] } def test_subject_catalog_does_not_choose_arbitrary_value_for_repeated_subject(): catalog = main._invoice_subject_catalog({"billing_analysis": _analysis()}) tamboro = next(x for x in catalog if x["name"] == "Tamboro Mensal") assert sorted(tamboro["values"]) == [14.99, 19.99] assert tamboro["value"] is None def test_preflight_does_not_resolve_value_from_subject_when_subject_has_multiple_values(monkeypatch): class DummyClient: def billing_analysis(self, _msisdn): return _analysis() class DummyService: client = DummyClient() monkeypatch.setattr(main, "service", DummyService()) args = { "msisdn": "11999999999", "subject": "Tamboro Mensal", "query": "não reconheço esse Tamboro Mensal", "billing_analysis": _analysis(), "resolved_value": "25.5", } # The resolver may continue to normal validation, but it must not retain an # arbitrary/stale resolved_value just because the subject matched. main._preflight_subject("contestar_cobranca", args) assert args["subject"] == "Tamboro Mensal" assert args.get("resolved_value") is None def test_invalid_amount_is_candidate_not_resolved(monkeypatch): async def no_enrich(_name, _args): return None monkeypatch.setattr(main, "_enrich_invoice_context", no_enrich) monkeypatch.setattr(main, "_preflight_subject", lambda *_a, **_k: None) args = { "msisdn": "11999999999", "subject": "Tamboro Mensal", "valor": 25.5, "billing_analysis": _analysis(), "target_tool": "contestar_cobranca", } result = asyncio.run(main._validate_contestation(args)) assert result["eligible"] is False assert result["status"] == "NEEDS_PARAMETER" assert result["parameter"] == "valor" assert result["candidate_value"] == 25.5 assert result["resolved_value"] is None def test_valid_amount_is_resolved_only_after_subject_amount_validation(monkeypatch): async def no_enrich(_name, _args): return None monkeypatch.setattr(main, "_enrich_invoice_context", no_enrich) monkeypatch.setattr(main, "_preflight_subject", lambda *_a, **_k: None) args = { "msisdn": "11999999999", "subject": "Tamboro Mensal", "valor": 19.99, "billing_analysis": _analysis(), "target_tool": "contestar_cobranca", } result = asyncio.run(main._validate_contestation(args)) assert result["eligible"] is True assert result["resolved_value"] == 19.99 resolved = result["transaction_decision"]["resolved_arguments"] assert resolved["subject"] == "Tamboro Mensal" assert resolved["resolved_value"] == 19.99