Aggiungi sequenza prelievo e gestisci destinazioni senza nazione
This commit is contained in:
@@ -81,6 +81,7 @@ from ui_tables import (
|
||||
from user_session import UserSession
|
||||
from version_info import module_version, versioned_title
|
||||
from window_placement import place_window_fullsize_below_parent_later
|
||||
from pickinglist_sequence import open_pickinglist_sequence_window
|
||||
|
||||
__version__ = module_version(__name__)
|
||||
|
||||
@@ -227,18 +228,21 @@ SELECT
|
||||
MAX(Magazzino) AS Magazzino,
|
||||
MAX(Area) AS Area,
|
||||
MAX(Cella) AS Cella,
|
||||
MIN(OrdinePrelievoGruppo) AS OrdinePrelievoGruppo,
|
||||
MIN(Ordinamento) AS Ordinamento,
|
||||
MAX(IDStato) AS IDStato
|
||||
FROM dbo.py_ViewPackingListRestante
|
||||
FROM dbo.py_ViewPackingListPrelievo
|
||||
WHERE DataDocumento > CAST((GETDATE() - :days) AS int)
|
||||
GROUP BY Documento, CodNazione, NAZIONE, Stato
|
||||
ORDER BY MIN(Ordinamento), Documento, NAZIONE, Stato;
|
||||
ORDER BY MIN(OrdinePrelievoGruppo), MIN(Ordinamento), Documento, NAZIONE, Stato;
|
||||
"""
|
||||
|
||||
SQL_PL_DETAILS = """
|
||||
SELECT *
|
||||
FROM dbo.py_ViewPackingListRestante
|
||||
FROM dbo.py_ViewPackingListPrelievo
|
||||
WHERE Documento = :Documento
|
||||
ORDER BY Ordinamento;
|
||||
AND DataDocumento > CAST((GETDATE() - :days) AS int)
|
||||
ORDER BY OrdinePrelievoGruppo, Ordinamento, Pallet;
|
||||
"""
|
||||
|
||||
# -------------------- helpers --------------------
|
||||
@@ -649,6 +653,7 @@ class GestionePickingListFrame(ctk.CTkFrame):
|
||||
self.rows_models: list[PLRow] = []
|
||||
self._detail_cache: Dict[Any, list] = {}
|
||||
self.detail_doc = None
|
||||
self.days_var = tk.StringVar(value="10")
|
||||
self._detail_sort_key: Optional[str] = None
|
||||
self._detail_sort_reverse = False
|
||||
self._detail_sorting = False
|
||||
@@ -699,6 +704,7 @@ class GestionePickingListFrame(ctk.CTkFrame):
|
||||
(loc_text("picking.button.reload", catalog=self._locale_catalog, default="Ricarica"), self.reload_from_db),
|
||||
(loc_text("picking.button.prenota", catalog=self._locale_catalog, default="Prenota"), self.on_prenota),
|
||||
(loc_text("picking.button.sprenota", catalog=self._locale_catalog, default="S-prenota"), self.on_sprenota),
|
||||
(loc_text("picking.button.sequence", catalog=self._locale_catalog, default="Sequenza di prelievo"), self.on_sequence),
|
||||
(loc_text("picking.button.export", catalog=self._locale_catalog, default="Esporta XLSX"), self.on_export)
|
||||
]):
|
||||
ctk.CTkButton(
|
||||
@@ -708,6 +714,20 @@ class GestionePickingListFrame(ctk.CTkFrame):
|
||||
font=theme_font(self._theme, "toolbar_button_font", ("Segoe UI", 10, "bold")),
|
||||
).grid(row=0, column=i, padx=6)
|
||||
|
||||
ctk.CTkLabel(
|
||||
top,
|
||||
text=loc_text("picking.label.days", catalog=self._locale_catalog, default="Giorni:"),
|
||||
font=theme_font(self._theme, "toolbar_label_font", ("Segoe UI", 10)),
|
||||
).grid(row=0, column=5, padx=(18, 4), sticky="e")
|
||||
ctk.CTkOptionMenu(
|
||||
top,
|
||||
values=["10", "15", "20", "30"],
|
||||
variable=self.days_var,
|
||||
width=82,
|
||||
command=lambda _value: self.reload_from_db(),
|
||||
font=theme_font(self._theme, "toolbar_button_font", ("Segoe UI", 10, "bold")),
|
||||
).grid(row=0, column=6, padx=(0, 6), sticky="w")
|
||||
|
||||
# --- micro spinner a destra della toolbar ---
|
||||
self.spinner = ToolbarSpinner(top)
|
||||
self.spinner.widget().grid(row=0, column=10, padx=(8,0)) # largo spazio a destra
|
||||
@@ -998,6 +1018,15 @@ class GestionePickingListFrame(ctk.CTkFrame):
|
||||
documento = _s(self.detail_doc)
|
||||
return documento or None
|
||||
|
||||
def _selected_days(self) -> int:
|
||||
"""Return the selected look-back interval for operational picking lists."""
|
||||
|
||||
try:
|
||||
days = int(str(self.days_var.get()).strip())
|
||||
except Exception:
|
||||
days = 10
|
||||
return days if days in (10, 15, 20, 30) else 10
|
||||
|
||||
# ----- eventi -----
|
||||
@_log_call()
|
||||
def on_row_checked(self, model: PLRow, is_checked: bool):
|
||||
@@ -1013,10 +1042,12 @@ class GestionePickingListFrame(ctk.CTkFrame):
|
||||
self.detail_doc = model.pl.get("Documento")
|
||||
_MODULE_LOGGER.info(f"Documento selezionato per il dettaglio: {self.detail_doc}")
|
||||
self.spinner.start(" Carico dettagli…") # spinner ON
|
||||
days = self._selected_days()
|
||||
|
||||
async def _job():
|
||||
_log_sql("SQL_PL_DETAILS", SQL_PL_DETAILS, {"Documento": self.detail_doc})
|
||||
return await self.db_client.query_json(SQL_PL_DETAILS, {"Documento": self.detail_doc})
|
||||
params = {"Documento": self.detail_doc, "days": days}
|
||||
_log_sql("SQL_PL_DETAILS", SQL_PL_DETAILS, params)
|
||||
return await self.db_client.query_json(SQL_PL_DETAILS, params)
|
||||
|
||||
def _ok(res):
|
||||
# NON fermare lo spinner subito: lo farà _refresh_details_incremental
|
||||
@@ -1058,9 +1089,11 @@ class GestionePickingListFrame(ctk.CTkFrame):
|
||||
# document selected when it is still visible.
|
||||
reselect_documento = self._selected_documento_for_reload()
|
||||
self.spinner.start(" Carico…") # spinner ON
|
||||
days = self._selected_days()
|
||||
async def _job():
|
||||
_log_sql("SQL_PL", SQL_PL, {})
|
||||
return await self.db_client.query_json(SQL_PL, {})
|
||||
params = {"days": days}
|
||||
_log_sql("SQL_PL", SQL_PL, params)
|
||||
return await self.db_client.query_json(SQL_PL, params)
|
||||
def _on_success(res):
|
||||
rows = _rows_to_dicts(res)
|
||||
_log_dataset("SQL_PL", rows)
|
||||
@@ -1156,6 +1189,45 @@ class GestionePickingListFrame(ctk.CTkFrame):
|
||||
self._load_detail_sheet_data(self._detail_rows_to_sheet_data(rows))
|
||||
|
||||
# ----- azioni -----
|
||||
@_log_call()
|
||||
def on_sequence(self):
|
||||
"""Open the pickup-sequence editor for the selected picking list."""
|
||||
|
||||
if not self._can("pickinglist.sequence"):
|
||||
messagebox.showwarning(
|
||||
loc_text("picking.sequence.title", catalog=self._locale_catalog, default="Sequenza di prelievo"),
|
||||
loc_text("picking.sequence.msg.denied", catalog=self._locale_catalog, default="Permesso negato."),
|
||||
parent=self,
|
||||
)
|
||||
return
|
||||
|
||||
model = self._get_selected_model()
|
||||
if not model:
|
||||
messagebox.showinfo(
|
||||
loc_text("picking.sequence.title", catalog=self._locale_catalog, default="Sequenza di prelievo"),
|
||||
loc_text(
|
||||
"picking.sequence.msg.select",
|
||||
catalog=self._locale_catalog,
|
||||
default="Seleziona una Picking List prima di definire la sequenza.",
|
||||
),
|
||||
parent=self,
|
||||
)
|
||||
return
|
||||
|
||||
documento = _s(model.pl.get("Documento"))
|
||||
|
||||
def _on_saved():
|
||||
self._detail_cache.pop(documento, None)
|
||||
self.reload_from_db(reselect_documento=documento)
|
||||
|
||||
open_pickinglist_sequence_window(
|
||||
self.winfo_toplevel(),
|
||||
self.db_client,
|
||||
documento=documento,
|
||||
session=self.session,
|
||||
on_saved=_on_saved,
|
||||
)
|
||||
|
||||
@_log_call()
|
||||
def on_prenota(self):
|
||||
"""Reserve the selected picking list."""
|
||||
|
||||
Reference in New Issue
Block a user