From 943dd57d4afc008de75d4cfb1f0ede6c2808f36c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vitor=20Hugo=20Belorio=20Sim=C3=A3o?= Date: Thu, 12 Mar 2026 17:49:21 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(review):=20aceitar=20data=20?= =?UTF-8?q?relativa=20parcial=20no=20reaproveitamento=20de=20revisao?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - reconhece respostas como 'hoje' e 'amanha' no reuso do ultimo veiculo mesmo sem horario - preserva a data-base relativa e permite completar o agendamento em uma segunda mensagem so com o horario - adiciona teste para reaproveitamento com data relativa seguida de horario --- app/services/flows/review_flow.py | 8 +++++ tests/test_conversation_adjustments.py | 46 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/app/services/flows/review_flow.py b/app/services/flows/review_flow.py index c2636e0..b3a37ce 100644 --- a/app/services/flows/review_flow.py +++ b/app/services/flows/review_flow.py @@ -100,6 +100,14 @@ class ReviewFlowMixin: continue parts = match.groupdict() return f"{int(parts['day']):02d}/{int(parts['month']):02d}/{int(parts['year']):04d}" + + normalized_text = self._normalize_text(message).strip() + if self.normalizer.extract_hhmm_from_text(message): + return None + if "hoje" in normalized_text: + return datetime.now().strftime("%d/%m/%Y") + if "amanha" in normalized_text: + return (datetime.now() + timedelta(days=1)).strftime("%d/%m/%Y") return None def _merge_review_base_date_with_time(self, message: str, payload: dict) -> None: diff --git a/tests/test_conversation_adjustments.py b/tests/test_conversation_adjustments.py index c3d3d6a..9b8b76e 100644 --- a/tests/test_conversation_adjustments.py +++ b/tests/test_conversation_adjustments.py @@ -1311,6 +1311,52 @@ class ReviewFlowDraftTests(unittest.IsolatedAsyncioTestCase): self.assertEqual(registry.calls[0][1]["data_hora"], "18/08/2026 10:00") self.assertIn("REV-TESTE-123", final_response) + async def test_review_flow_reuses_vehicle_with_relative_date_only_and_requests_missing_time(self): + state = FakeState( + entries={ + "pending_review_reuse_confirmations": { + 21: { + "payload": { + "placa": "ABC1263", + "modelo": "Onix", + "ano": 2024, + "km": 50000, + "revisao_previa_concessionaria": False, + }, + "expires_at": datetime.utcnow() + timedelta(minutes=30), + } + } + } + ) + registry = FakeRegistry() + flow = ReviewFlowHarness(state=state, registry=registry) + today_text = datetime.now().strftime("%d/%m/%Y") + + response = await flow._try_collect_and_schedule_review( + message="eu gostaria de marcar para hoje", + user_id=21, + extracted_fields={}, + intents={}, + turn_decision={"intent": "review_schedule", "domain": "review", "action": "collect_review_schedule"}, + ) + + draft = state.get_entry("pending_review_drafts", 21) + self.assertIsNotNone(draft) + self.assertEqual(draft["payload"].get("data_hora_base"), today_text) + self.assertIn("Agora me informe o horario desejado", response) + + final_response = await flow._try_collect_and_schedule_review( + message="as 14 horas", + user_id=21, + extracted_fields={}, + intents={}, + turn_decision={"intent": "review_schedule", "domain": "review", "action": "collect_review_schedule"}, + ) + + self.assertEqual(registry.calls[0][0], "agendar_revisao") + self.assertEqual(registry.calls[0][1]["data_hora"], f"{today_text} 14:00") + self.assertIn("REV-TESTE-123", final_response) + async def test_review_flow_clears_stale_pending_confirmation_when_user_starts_new_schedule(self): state = FakeState( entries={