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

@@ -9,7 +9,7 @@ from concurrent.futures import Future
from tkinter import messagebox, ttk
from typing import Callable
from runtime_support import ensure_stdio, run_with_fatal_log
from runtime_support import configure_exception_logging, ensure_stdio, log_exception, run_with_fatal_log
ensure_stdio("warehouse_barcode")
@@ -19,21 +19,43 @@ from barcode_repository import BarcodeRepository
from barcode_service import BarcodeActionResult, BarcodeService, BarcodeViewState
from db_config import build_dsn_from_config, ensure_db_config
from login_window import prompt_login_compact
from user_session import create_user_session
from version_info import module_version, versioned_title
__version__ = module_version(__name__)
BYPASS_LOGIN = True
BYPASS_LOGIN_USER = {
"operator_id": 4,
"login": "MAG1",
"nominativo": "MAG1",
"privilegio": 3,
"codice_unita": "U1",
}
def _build_bypass_session():
"""Create the temporary MAG1 session used while field testing the barcode."""
return create_user_session(
operator_id=int(BYPASS_LOGIN_USER["operator_id"]),
login=str(BYPASS_LOGIN_USER["login"]),
nominativo=str(BYPASS_LOGIN_USER["nominativo"]),
privilegio=int(BYPASS_LOGIN_USER["privilegio"]),
codice_unita=str(BYPASS_LOGIN_USER["codice_unita"]),
)
class BarcodeClientApp:
"""Single-window Tk barcode client modeled after the C# legacy form."""
NON_SCAFFALATA_BARCODE = "9001000"
SHIPPED_BARCODE = "9000000"
BARCODE_MAX_WIDTH = 320
BARCODE_MAX_HEIGHT = 400
DESKTOP_THRESHOLD_WIDTH = 1024
DESKTOP_THRESHOLD_HEIGHT = 768
DESKTOP_WINDOW_WIDTH = 465
DESKTOP_WINDOW_HEIGHT = 531
def __init__(self, root: tk.Tk, db_client: AsyncMSSQLClient, session, loop: asyncio.AbstractEventLoop):
self.root = root
self.db_client = db_client
@@ -174,11 +196,11 @@ class BarcodeClientApp:
self.btn_f1 = ttk.Button(buttons, text="[F1] H Priority", command=lambda: self._start_queue(1))
self.btn_f1.grid(row=0, column=0, padx=(0, 4), pady=(0, button_pad_y), sticky="ew")
self.btn_submit = ttk.Button(buttons, text="[Ent] Salva", command=self._submit)
self.btn_submit = ttk.Button(buttons, text="[Ent] Carica", command=self._submit)
self.btn_submit.grid(row=0, column=1, padx=(4, 0), pady=(0, button_pad_y), sticky="ew")
self.btn_f2 = ttk.Button(buttons, text="[F2] L Priority", command=lambda: self._start_queue(0))
self.btn_f2.grid(row=1, column=0, padx=(0, 4), sticky="ew")
self.btn_unload = ttk.Button(buttons, text="[F4] Elimina", command=self._begin_manual_unload)
self.btn_unload = ttk.Button(buttons, text="[F4] Scarica", command=self._begin_manual_unload)
self.btn_unload.grid(row=1, column=1, padx=(4, 0), sticky="ew")
self.busy_cover = tk.Frame(self.root, bg="#d9d9d9")
@@ -274,7 +296,7 @@ class BarcodeClientApp:
def _bind_keys(self) -> None:
self.root.bind("<F1>", lambda _e: self._start_queue(1))
self.root.bind("<F2>", lambda _e: self._start_queue(0))
self.root.bind("<F4>", lambda _e: self._begin_manual_unload())
self.root.bind("<F4>", self._on_unload_key)
self.pallet_entry.bind("<Return>", self._on_pallet_enter)
self.destination_entry.bind("<Return>", self._on_destination_enter)
@@ -318,7 +340,7 @@ class BarcodeClientApp:
self.info4_var.set(state.expected_pallet)
self.status_band.configure(bg=state.status_color or self._status_colors["red"])
destination_readonly = state.mode in ("priority_high", "priority_low", "manual_unload")
destination_readonly = bool(getattr(state, "destination_readonly", False))
try:
self.destination_entry.configure(state="normal")
if destination_readonly:
@@ -326,10 +348,18 @@ class BarcodeClientApp:
except Exception:
pass
if state.mode == "confirm" and state.status_text == "Ok Scarico":
is_completed_move = (
str(state.status_text or "").startswith("Ok Scarico")
or str(state.status_text or "").startswith("Ok Carico")
)
if state.mode == "confirm" and is_completed_move:
next_queue = self._queue_id_from_label(state.queue_label)
if next_queue is not None:
self._auto_advance_id = self.root.after(1200, lambda q=next_queue: self._start_queue(q))
delay_ms = int(getattr(state, "auto_advance_delay_ms", 0) or 0)
if next_queue is not None and delay_ms > 0:
self._auto_advance_id = self.root.after(
delay_ms,
lambda q=next_queue: self._start_queue(q),
)
self.root.after(20, self._focus_primary_input)
@@ -356,8 +386,11 @@ class BarcodeClientApp:
destination = str(self.destination_var.get() or "").strip()
if not pallet:
return "break"
if destination == "9000000":
self._submit()
if destination in (self.NON_SCAFFALATA_BARCODE, self.SHIPPED_BARCODE):
if bool(getattr(self.service.state, "destination_readonly", False)):
self._submit()
else:
self._focus_destination_input()
return "break"
self.destination_var.set("")
self._focus_destination_input()
@@ -372,7 +405,21 @@ class BarcodeClientApp:
self._focus_primary_input()
return "break"
def _on_unload_key(self, _event=None) -> str:
self._begin_manual_unload()
return "break"
def _begin_manual_unload(self) -> None:
pallet = str(self.scanned_var.get() or "").strip()
destination = str(self.destination_var.get() or "").strip()
if pallet and destination in (self.NON_SCAFFALATA_BARCODE, self.SHIPPED_BARCODE):
# Legacy barcode flow: F4/Scarica confirms the prepared unload destination.
self._submit()
return
if pallet and not destination:
self.destination_var.set(self.NON_SCAFFALATA_BARCODE)
self._submit()
return
self._apply_state(self.service.begin_manual_unload())
def _start_queue(self, id_stato: int) -> None:
@@ -425,11 +472,18 @@ class BarcodeClientApp:
try:
result = future.result()
except Exception as exc:
log_exception("Barcode WMS", exc, context="barcode async operation")
current = self.service.state
current.status_text = f"Errore operativo: {exc}"
current.status_text = "Transazione non completata, ripeti l'operazione."
current.status_color = "#f4cccc"
self._apply_state(current)
messagebox.showerror("Barcode WMS", f"Operazione fallita:\n{exc}", parent=self.root)
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,
)
return
if isinstance(result, BarcodeActionResult):
@@ -463,6 +517,7 @@ def main() -> int:
loop = get_global_loop()
bootstrap = tk.Tk()
bootstrap.withdraw()
configure_exception_logging("Barcode WMS", root=bootstrap, loop=loop)
config = ensure_db_config(loop, parent=bootstrap)
if not config:
@@ -471,7 +526,7 @@ def main() -> int:
return 1
db_client = AsyncMSSQLClient(build_dsn_from_config(config))
session = prompt_login_compact(bootstrap, db_client)
session = _build_bypass_session() if BYPASS_LOGIN else prompt_login_compact(bootstrap, db_client)
if session is None:
try:
fut = asyncio.run_coroutine_threadsafe(db_client.dispose(), loop)