ajuste no contas
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -261,6 +261,15 @@ def _preflight_subject(name: str, args: dict[str, Any]) -> dict[str, Any] | None
|
||||
subject = str(args.get("subject") or "").strip()
|
||||
if not msisdn or not subject:
|
||||
return None
|
||||
|
||||
# ``validar_vas_subject`` is the authoritative, side-effect-free resolver
|
||||
# used at the transaction boundary. When it has already canonicalized the
|
||||
# subject and redirected the action to the strategic/bundle workflow, do not
|
||||
# resolve the same subject a second time against invoice evidence. Repeating
|
||||
# resolution with a different catalog can incorrectly turn a previously
|
||||
# ELIGIBLE subject into NEEDS_PARAMETER (the Aya Audiobooks case).
|
||||
if name == "tratar_vas_estrategico" and bool(args.get("_vas_subject_prevalidated")):
|
||||
return None
|
||||
# Contestação pode referenciar qualquer categoria da fatura. Antes do
|
||||
# resolver especializado em serviços/VAS, preserve um item explicitamente
|
||||
# citado no texto que abriu a transação. Isso impede que um plano explícito
|
||||
@@ -507,10 +516,19 @@ def _result_payload(result: Any, *, workflow_name: str) -> dict[str, Any]:
|
||||
|
||||
|
||||
async def _run_workflow(workflow_name: str, args: dict[str, Any]) -> dict[str, Any]:
|
||||
# A workflow execution belongs to one transaction, never to the whole
|
||||
# conversation session. Starting a workflow is therefore always a NEW
|
||||
# execution. The only path allowed to reuse an execution id is
|
||||
# ``retomar_workflow`` below, which calls ``aresume`` explicitly.
|
||||
#
|
||||
# Do not trust/forward a residual ``workflow_execution_id`` from a previous
|
||||
# transaction: WorkflowRuntime.arun() will allocate a fresh UUID.
|
||||
payload_args = dict(args)
|
||||
payload_args.pop("workflow_execution_id", None)
|
||||
result = await get_workflow_runtime().arun(
|
||||
workflow_name,
|
||||
_workflow_payload(workflow_name, args),
|
||||
execution_id=args.get("workflow_execution_id"),
|
||||
_workflow_payload(workflow_name, payload_args),
|
||||
execution_id=None,
|
||||
)
|
||||
payload = _result_payload(result, workflow_name=workflow_name)
|
||||
if workflow_name == "contestacao_tool" and payload.get("status") == "FAILED":
|
||||
@@ -665,10 +683,15 @@ async def _run_cancelamento_com_contestacao(args: dict[str, Any]) -> dict[str, A
|
||||
if social_sec_no:
|
||||
normalized_args["social_sec_no"] = social_sec_no
|
||||
normalized_args["items"] = _normalize_cancel_items(args, holder_msisdn)
|
||||
# Nova transação de cancelamento = nova execução de workflow. Mesmo que
|
||||
# algum envelope antigo carregue ``workflow_execution_id``, ele não pode ser
|
||||
# reutilizado depois que a transação anterior terminou. Resume é tratado
|
||||
# exclusivamente por ``retomar_workflow``/``aresume``.
|
||||
normalized_args.pop("workflow_execution_id", None)
|
||||
cancel_result = await get_workflow_runtime().arun(
|
||||
"cancelamento_vas_avulso",
|
||||
_workflow_payload("cancelamento_vas_avulso", normalized_args),
|
||||
execution_id=args.get("workflow_execution_id"),
|
||||
execution_id=None,
|
||||
)
|
||||
cancel_data = _workflow_result_dict(cancel_result)
|
||||
if cancel_data.get("status") != "COMPLETED":
|
||||
@@ -736,20 +759,48 @@ async def _run_cancelamento_com_contestacao(args: dict[str, Any]) -> dict[str, A
|
||||
total = 0.0
|
||||
for candidate in candidates:
|
||||
subject = str(candidate.get("subject") or (candidate.get("service") or {}).get("name") or "").strip()
|
||||
value = _value_for_subject(normalized_args, subject)
|
||||
requested_value = _value_for_subject(normalized_args, subject)
|
||||
|
||||
# Keep the amount claimed by the user separate from the amount validated
|
||||
# against VAS evidence. The cancellation result already carries the
|
||||
# canonical service object, so a missing user amount must never silently
|
||||
# become R$ 0,00. This also preserves mismatch evidence (e.g. user says
|
||||
# 29,98 while the active VAS is 14,99) for CVAL/observation downstream.
|
||||
service_evidence = candidate.get("service") if isinstance(candidate.get("service"), dict) else {}
|
||||
details = service_evidence.get("details") if isinstance(service_evidence.get("details"), dict) else {}
|
||||
validated_value = (
|
||||
candidate.get("validated_amount")
|
||||
if candidate.get("validated_amount") is not None
|
||||
else candidate.get("validatedAmount")
|
||||
if candidate.get("validatedAmount") is not None
|
||||
else details.get("valor")
|
||||
if details.get("valor") is not None
|
||||
else service_evidence.get("valor")
|
||||
if service_evidence.get("valor") is not None
|
||||
else service_evidence.get("value")
|
||||
if service_evidence.get("value") is not None
|
||||
else service_evidence.get("price")
|
||||
)
|
||||
if validated_value is None:
|
||||
validated_value = requested_value
|
||||
claimed_value = requested_value if requested_value is not None else validated_value
|
||||
|
||||
try:
|
||||
numeric = float(str(value).replace(".", "").replace(",", ".")) if isinstance(value, str) and "," in value else float(value or 0)
|
||||
text = str(validated_value if validated_value is not None else "0")
|
||||
numeric = float(text.replace(".", "").replace(",", ".")) if "," in text else float(text or 0)
|
||||
except Exception:
|
||||
numeric = 0.0
|
||||
total += numeric
|
||||
money = _money_ptbr(value if value is not None else numeric)
|
||||
|
||||
claimed_money = _money_ptbr(claimed_value if claimed_value is not None else 0)
|
||||
validated_money = _money_ptbr(validated_value if validated_value is not None else claimed_value or 0)
|
||||
items.append({
|
||||
"itemName": subject,
|
||||
"item_name": subject,
|
||||
"claimedAmount": money,
|
||||
"validatedAmount": money,
|
||||
"claimed_amount": money,
|
||||
"validated_amount": money,
|
||||
"claimedAmount": claimed_money,
|
||||
"validatedAmount": validated_money,
|
||||
"claimed_amount": claimed_money,
|
||||
"validated_amount": validated_money,
|
||||
})
|
||||
|
||||
contest_payload = {
|
||||
@@ -1334,7 +1385,11 @@ async def _validate_vas_subject(args: dict[str, Any]) -> dict[str, Any]:
|
||||
"resolved_subject": canonical,
|
||||
"entity_resolution": "vas_evidence",
|
||||
"transaction_decision": {
|
||||
"resolved_arguments": {"subject": canonical},
|
||||
"resolved_arguments": {
|
||||
"subject": canonical,
|
||||
"_vas_subject_prevalidated": True,
|
||||
**({"type": resolved_type} if resolved_type else {}),
|
||||
},
|
||||
"target_tool": effective_tool or requested_tool,
|
||||
"action_changed": action_changed,
|
||||
"requires_reconfirmation": action_changed,
|
||||
|
||||
Reference in New Issue
Block a user