From f4e73bd5b95ac22d395c13a481a5ad04d2ee39f5 Mon Sep 17 00:00:00 2001 From: allebonvi Date: Sat, 4 Jul 2026 09:05:14 +0200 Subject: [PATCH] Recupera movimenti barcode dopo risposta persa --- barcode_client.py | 58 +++++++++++++++++++++++++++------ barcode_service.py | 80 ++++++++++++++++++++++++++++++++++++++++++++++ version_info.py | 4 +-- 3 files changed, 130 insertions(+), 12 deletions(-) diff --git a/barcode_client.py b/barcode_client.py index 95badc0..bb167d1 100644 --- a/barcode_client.py +++ b/barcode_client.py @@ -581,17 +581,15 @@ class BarcodeClientApp: result = future.result() except Exception as exc: log_exception("Barcode WMS", exc, context="barcode async operation") - current = self.service.state - current.status_text = "Transazione non completata, ripeti l'operazione." - current.status_color = "#f4cccc" - self._apply_state(current) - messagebox.showerror( - "Barcode WMS", - "Operazione non completata.\n\n" - "Ripeti la lettura o avvisa il responsabile.\n" - "Il dettaglio tecnico e' stato scritto nel log.", - parent=self.root, + self._set_busy(True, "Verifico esito...") + self._pending = asyncio.run_coroutine_threadsafe( + self.service.reconcile_after_submit_exception( + scanned_pallet=self.scanned_var.get(), + destination_barcode=self.destination_var.get(), + ), + self.loop, ) + self.root.after(40, lambda err=exc: self._poll_recovery_future(err)) return if isinstance(result, BarcodeActionResult): @@ -601,6 +599,46 @@ class BarcodeClientApp: elif isinstance(result, BarcodeViewState): self._apply_state(result) + def _show_transaction_error(self) -> None: + messagebox.showerror( + "Barcode WMS", + "Operazione non completata.\n\n" + "Ripeti la lettura o avvisa il responsabile.\n" + "Il dettaglio tecnico e' stato scritto nel log.", + parent=self.root, + ) + + def _poll_recovery_future(self, original_exception: Exception) -> None: + if self._pending is None: + self._set_busy(False) + self._show_transaction_error() + return + if not self._pending.done(): + self.root.after(40, lambda err=original_exception: self._poll_recovery_future(err)) + return + + future = self._pending + self._pending = None + self._set_busy(False) + try: + result = future.result() + except Exception as exc: + log_exception("Barcode WMS", exc, context=f"barcode recovery after {original_exception!r}") + current = self.service.state + current.status_text = "Transazione non completata, ripeti l'operazione." + current.status_color = "#f4cccc" + self._apply_state(current) + self._show_transaction_error() + return + + if isinstance(result, BarcodeActionResult): + self._apply_state(result.state) + if not result.ok: + self.root.bell() + self._show_transaction_error() + elif isinstance(result, BarcodeViewState): + self._apply_state(result) + def _shutdown(self) -> None: try: if self._pending is not None and not self._pending.done(): diff --git a/barcode_service.py b/barcode_service.py index c6d6e5d..33cf4b7 100644 --- a/barcode_service.py +++ b/barcode_service.py @@ -413,6 +413,86 @@ class BarcodeService: return await self.submit(scanned_pallet=pallet, destination_barcode=self.NON_SCAFFALATA_BARCODE) + async def reconcile_after_submit_exception( + self, + *, + scanned_pallet: str, + destination_barcode: str, + ) -> BarcodeActionResult: + """Check whether a failed client round-trip actually committed on SQL Server.""" + + pallet = str(scanned_pallet or "").strip() + destination = str(destination_barcode or "").strip() + if not pallet or not destination or not destination.isdigit(): + self._state.status_text = "Transazione non completata, ripeti l'operazione." + self._state.status_color = self.RED + return BarcodeActionResult(False, self._state, self._state.status_text) + + target_id_cella = 9999 if destination == self.SHIPPED_BARCODE else (1000 if destination == self.NON_SCAFFALATA_BARCODE else None) + target_display = destination + if target_id_cella is None: + resolved_cell = await self.repository.resolve_physical_cell(destination) + if not resolved_cell: + self._state.scanned_pallet = pallet + self._state.destination_barcode = destination + self._state.status_text = "Transazione non completata, ripeti l'operazione." + self._state.status_color = self.RED + self._state.focus_destination = True + return BarcodeActionResult(False, self._state, self._state.status_text) + target_id_cella = int(resolved_cell.id_cella) + target_display = resolved_cell.ubicazione or destination + + current_location = await self.repository.fetch_current_location_by_pallet(pallet) + try: + current_id_cella = int((current_location or {}).get("IDCella") or 0) + except Exception: + current_id_cella = 0 + + if current_id_cella != target_id_cella: + log_runtime_event( + "Barcode WMS", + ( + "MOVE RECOVERY NOT_CONFIRMED " + f"pallet={pallet} " + f"destination={destination} " + f"expected_cell={target_id_cella} " + f"actual_cell={current_id_cella}" + ), + ) + self._state.scanned_pallet = pallet + self._state.destination_barcode = destination + self._state.status_text = "Transazione non completata, ripeti l'operazione." + self._state.status_color = self.RED + return BarcodeActionResult(False, self._state, self._state.status_text) + + last_priority_state = self._current_priority_state + is_recovered_picking = bool(destination == self.SHIPPED_BARCODE and last_priority_state in (0, 1)) + auto_advance_delay_ms = 3000 if is_recovered_picking else 5000 + state = await self._build_post_move_state( + barcode_pallet=pallet, + destination_barcode=destination, + destination_display=target_display, + last_priority_state=last_priority_state, + auto_advance_delay_ms=auto_advance_delay_ms, + ) + state.status_text = ( + "Ok Scarico - risposta persa recuperata" + if is_recovered_picking + else "Movimento completato - risposta persa recuperata" + ) + state.status_color = self.GREEN_YELLOW + self._state = state + log_runtime_event( + "Barcode WMS", + ( + "MOVE RECOVERY CONFIRMED " + f"pallet={pallet} " + f"destination={destination} " + f"cell={target_id_cella}" + ), + ) + return BarcodeActionResult(True, self._state, self._state.status_text) + async def _build_post_move_state( self, *, diff --git a/version_info.py b/version_info.py index 37c27ab..28b875c 100644 --- a/version_info.py +++ b/version_info.py @@ -13,9 +13,9 @@ MODULE_VERSIONS: dict[str, str] = { "async_msssql_query": "1.0.0", "audit_log": "1.0.0", "main": "1.0.1", - "barcode_client": "1.0.18", + "barcode_client": "1.0.19", "barcode_repository": "1.0.5", - "barcode_service": "1.0.14", + "barcode_service": "1.0.15", "busy_overlay": "1.0.0", "db_config": "1.0.0", "gestione_aree": "1.0.1",