🐛 fix(flows): endurecer validacao e preservar drafts

Impede que consultas de estoque caiam no fluxo de compra, evita reaproveitamento implícito de CPF para criar pedidos e mantém drafts quando a execução da tool falha.

Também preserva corretamente o estado de revisão, limpando o draft apenas quando a operação conclui com sucesso ou quando a confirmação pendente passa a ser o estado principal.
main
parent 14778fac0b
commit 6537808963

@ -15,6 +15,21 @@ from app.services.user.mock_customer_service import hydrate_mock_customer_from_c
class OrderFlowMixin:
def _has_explicit_order_request(self, message: str) -> bool:
normalized = self._normalize_text(message).strip()
order_terms = {
"comprar",
"compra",
"pedido",
"pedir",
"financiar",
"financiamento",
"simular compra",
"realizar pedido",
"fazer um pedido",
}
return any(term in normalized for term in order_terms)
def _is_valid_cpf(self, cpf: str) -> bool:
digits = re.sub(r"\D", "", cpf or "")
if len(digits) != 11:
@ -102,6 +117,7 @@ class OrderFlowMixin:
extracted = self._normalize_order_fields(extracted_fields)
has_intent = normalized_intents.get("order_create", False)
explicit_order_request = self._has_explicit_order_request(message)
if (
draft
@ -118,7 +134,7 @@ class OrderFlowMixin:
self.state.pop_entry("pending_order_drafts", user_id)
return None
if not has_intent and draft is None:
if draft is None and not (has_intent and explicit_order_request):
return None
if draft is None:
@ -128,15 +144,13 @@ class OrderFlowMixin:
}
draft["payload"].update(extracted)
self._try_prefill_order_cpf_from_memory(user_id=user_id, payload=draft["payload"])
self._try_prefill_order_cpf_from_user_profile(user_id=user_id, payload=draft["payload"])
self._try_prefill_order_value_from_memory(user_id=user_id, payload=draft["payload"])
cpf_value = draft["payload"].get("cpf")
if cpf_value and not self._is_valid_cpf(str(cpf_value)):
draft["payload"].pop("cpf", None)
self.state.set_entry("pending_order_drafts", user_id, draft)
return "Para seguir com o pedido, preciso de um CPF valido com 11 digitos."
return "Para seguir com o pedido, preciso de um CPF valido. Pode me informar novamente?"
if cpf_value:
try:
await hydrate_mock_customer_from_cpf(
@ -146,7 +160,7 @@ class OrderFlowMixin:
except ValueError:
draft["payload"].pop("cpf", None)
self.state.set_entry("pending_order_drafts", user_id, draft)
return "Para seguir com o pedido, preciso de um CPF valido com 11 digitos."
return "Para seguir com o pedido, preciso de um CPF valido. Pode me informar novamente?"
valor = draft["payload"].get("valor_veiculo")
if valor is not None:
@ -174,8 +188,7 @@ class OrderFlowMixin:
)
except HTTPException as exc:
return self._http_exception_detail(exc)
finally:
self.state.pop_entry("pending_order_drafts", user_id)
self.state.pop_entry("pending_order_drafts", user_id)
return self._fallback_format_tool_result("realizar_pedido", tool_result)
@ -244,7 +257,6 @@ class OrderFlowMixin:
)
except HTTPException as exc:
return self._http_exception_detail(exc)
finally:
self.state.pop_entry("pending_cancel_order_drafts", user_id)
self.state.pop_entry("pending_cancel_order_drafts", user_id)
return self._fallback_format_tool_result("cancelar_pedido", tool_result)

@ -91,8 +91,7 @@ class ReviewFlowMixin:
)
except HTTPException as exc:
return self._http_exception_detail(exc)
finally:
self.state.pop_entry("pending_review_management_drafts", user_id)
self.state.pop_entry("pending_review_management_drafts", user_id)
return self._fallback_format_tool_result("editar_data_revisao", tool_result)
missing = [field for field in ("protocolo",) if field not in draft["payload"]]
@ -109,8 +108,7 @@ class ReviewFlowMixin:
)
except HTTPException as exc:
return self._http_exception_detail(exc)
finally:
self.state.pop_entry("pending_review_management_drafts", user_id)
self.state.pop_entry("pending_review_management_drafts", user_id)
return self._fallback_format_tool_result("cancelar_agendamento_revisao", tool_result)
def _render_missing_review_fields_prompt(self, missing_fields: list[str]) -> str:
@ -295,9 +293,10 @@ class ReviewFlowMixin:
exc=exc,
user_id=user_id,
)
if self.state.get_entry("pending_review_confirmations", user_id, expire=True):
self.state.pop_entry("pending_review_drafts", user_id)
return self._http_exception_detail(exc)
finally:
self.state.pop_entry("pending_review_drafts", user_id)
self.state.pop_entry("pending_review_drafts", user_id)
self._store_last_review_package(user_id=user_id, payload=draft["payload"])
return self._fallback_format_tool_result("agendar_revisao", tool_result)

Loading…
Cancel
Save