Alpha6 barcode non scaffalate e bypass login

This commit is contained in:
2026-06-18 16:13:47 +02:00
parent cc9680c49a
commit 466778ae5f
19 changed files with 1614 additions and 48 deletions

View File

@@ -209,6 +209,9 @@ if _MODULE_LOG_ENABLED:
# -------------------- SQL --------------------
# Operational picking-list management uses the Python-only residual view.
# Unlike the historical view, this dataset intentionally contains only UDCs
# that still have to be exhausted by the warehouse workflow.
SQL_PL = """
SELECT
COUNT(DISTINCT NULLIF(LTRIM(RTRIM(CAST(Pallet AS varchar(32)))), '')) AS Pallet,
@@ -963,7 +966,9 @@ class GestionePickingListFrame(ctk.CTkFrame):
@_log_call()
def on_row_checked(self, model: PLRow, is_checked: bool):
"""Handle row selection changes and refresh the detail section."""
# selezione esclusiva
# Only one backoffice picking list can be selected at a time. Barcode
# F1/F2 priority behavior is derived downstream; this UI controls only
# the explicit Python reservation slot.
if is_checked:
for m in self.rows_models:
if m is not model and m.is_checked():
@@ -1012,6 +1017,9 @@ class GestionePickingListFrame(ctk.CTkFrame):
def reload_from_db(self, first: bool = False, reselect_documento: str | None = None):
"""Load or reload the picking list summary table from the database."""
if reselect_documento is None and not first:
# Preserve the operator context while the barcode may be consuming
# rows: Ricarica refreshes master and detail but keeps the selected
# document selected when it is still visible.
reselect_documento = self._selected_documento_for_reload()
self.spinner.start(" Carico…") # spinner ON
async def _job():
@@ -1126,6 +1134,8 @@ class GestionePickingListFrame(ctk.CTkFrame):
documento = _s(model.pl.get("Documento"))
current = int(model.pl.get("IDStato") or 0)
desired = 1
# Idempotent semantics: Prenota never toggles a list off. If the list
# is already reserved, S-prenota remains the only explicit release path.
if current == desired:
messagebox.showinfo("Prenota", f"La Picking List {documento} è già prenotata.")
return
@@ -1138,6 +1148,8 @@ class GestionePickingListFrame(ctk.CTkFrame):
self.spinner.start(" Prenoto…")
async def _job():
# Use the Python-specific py_* stored procedure so C# legacy
# procedures can coexist unchanged on the same database.
return await sp_xExePackingListPallet_async(self.db_client, id_operatore, documento, "P")
def _ok(res: SPResult):
@@ -1200,6 +1212,8 @@ class GestionePickingListFrame(ctk.CTkFrame):
documento = _s(model.pl.get("Documento"))
current = int(model.pl.get("IDStato") or 0)
desired = 0
# Idempotent semantics: S-prenota never reserves a list; if the list is
# already free, the operation is a no-op rather than an implicit toggle.
if current == desired:
messagebox.showinfo("S-prenota", f"La Picking List {documento} è già NON prenotata.")
return
@@ -1212,6 +1226,8 @@ class GestionePickingListFrame(ctk.CTkFrame):
self.spinner.start(" S-prenoto…")
async def _job():
# Same Python-only procedure as Prenota, with action S to release
# the singleton reservation and clear affected cell states.
return await sp_xExePackingListPallet_async(self.db_client, id_operatore, documento, "S")
def _ok(res: SPResult):