Alpha6 barcode non scaffalate e bypass login
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user