Stabilizza picking barcode e patch cumulativa online

This commit is contained in:
2026-07-04 17:03:55 +02:00
parent 5dd7139b19
commit 77da8d9bad
13 changed files with 1153 additions and 97 deletions

View File

@@ -32,8 +32,10 @@ WHERE Ordinamento > 0
AND NOT EXISTS (
SELECT 1
FROM dbo.py_BarcodePickingListSkip AS s
WHERE s.Documento = CAST(pl.Documento AS varchar(50))
AND s.Pallet = CAST(pl.Pallet AS varchar(50))
WHERE s.Documento COLLATE Latin1_General_CI_AS =
CAST(pl.Documento AS varchar(50)) COLLATE Latin1_General_CI_AS
AND s.Pallet COLLATE Latin1_General_CI_AS =
CAST(pl.Pallet AS varchar(50)) COLLATE Latin1_General_CI_AS
AND s.IDStato = pl.IDStato
AND s.Risolto = 0
)
@@ -52,7 +54,7 @@ SELECT TOP (1)
Ordinamento,
IDStato
FROM dbo.py_XMag_ViewPackingList
WHERE Pallet = :pallet
WHERE Pallet COLLATE Latin1_General_CI_AS = :pallet COLLATE Latin1_General_CI_AS
ORDER BY Ordinamento;
"""
@@ -63,7 +65,7 @@ SELECT TOP (1)
Prodotto,
Descrizione
FROM dbo.vXTracciaProdotti
WHERE Pallet = :pallet
WHERE Pallet COLLATE Latin1_General_CI_AS = :pallet COLLATE Latin1_General_CI_AS
ORDER BY Lotto;
"""
@@ -77,7 +79,7 @@ SELECT TOP (1)
FROM dbo.XMag_GiacenzaPallet AS g
LEFT JOIN dbo.Celle AS c
ON c.ID = g.IDCella
WHERE g.BarcodePallet = :pallet;
WHERE g.BarcodePallet COLLATE Latin1_General_CI_AS = :pallet COLLATE Latin1_General_CI_AS;
"""
SQL_OPEN_LOCATIONS_BY_PALLET = """
@@ -90,7 +92,7 @@ SELECT
FROM dbo.XMag_GiacenzaPallet AS g
LEFT JOIN dbo.Celle AS c
ON c.ID = g.IDCella
WHERE g.BarcodePallet = :pallet
WHERE g.BarcodePallet COLLATE Latin1_General_CI_AS = :pallet COLLATE Latin1_General_CI_AS
ORDER BY g.IDCella;
"""
@@ -103,6 +105,19 @@ WHERE g.IDCella = :id_cella
ORDER BY g.BarcodePallet;
"""
SQL_CLOSED_PICKING_BY_PALLET = """
SELECT TOP (1)
BarcodePallet,
NumeroPallet,
IDMagazzino,
IDArea,
IDCella,
IDStato
FROM dbo.XMag_GiacenzaPalletPlistChiuse
WHERE BarcodePallet COLLATE Latin1_General_CI_AS = :pallet COLLATE Latin1_General_CI_AS
ORDER BY IDCella DESC;
"""
SQL_RESOLVE_PHYSICAL_CELL = """
DECLARE @raw int = TRY_CONVERT(int, :destination);
DECLARE @cell_id int =
@@ -151,7 +166,7 @@ IF NOT EXISTS (
SELECT 1
FROM dbo.py_BarcodePickingListSkip
WHERE Documento = :documento
AND Pallet = :pallet
AND Pallet COLLATE Latin1_General_CI_AS = :pallet COLLATE Latin1_General_CI_AS
AND IDStato = :id_stato
AND Risolto = 0
)
@@ -182,6 +197,37 @@ SELECT
:id_stato AS IDStato;
"""
SQL_ACTIVE_SKIPPED_DOCUMENT = """
SELECT TOP (1)
s.Documento,
COUNT(*) AS SkippedCount
FROM dbo.py_BarcodePickingListSkip AS s
WHERE s.IDStato = :id_stato
AND s.Risolto = 0
AND EXISTS (
SELECT 1
FROM dbo.py_ViewPackingListRestante AS pl
WHERE CAST(pl.Documento AS varchar(50)) COLLATE Latin1_General_CI_AS =
s.Documento COLLATE Latin1_General_CI_AS
AND pl.IDStato = :id_stato
)
GROUP BY s.Documento
ORDER BY MIN(s.DataOra);
"""
SQL_RELEASE_PICKING_DOCUMENT = """
SET NOCOUNT ON;
DECLARE @RC int = 0;
EXEC dbo.py_sp_xExePackingListPallet
@IDOperatore = :id_operatore,
@Documento = :documento,
@Azione = 'S',
@RC = @RC OUTPUT;
SELECT CAST(@RC AS int) AS RC;
"""
def _rows_to_dicts(res: dict[str, Any] | None) -> list[dict[str, Any]]:
"""Convert ``query_json`` payloads to a list of row dictionaries."""
@@ -265,6 +311,13 @@ class BarcodeRepository:
res = await self.db_client.query_json(SQL_OPEN_PALLETS_BY_CELL, {"id_cella": int(id_cella)})
return _rows_to_dicts(res)
async def fetch_closed_picking_by_pallet(self, pallet: str) -> dict[str, Any] | None:
"""Return a closed picking-list row for a pallet already considered shipped."""
res = await self.db_client.query_json(SQL_CLOSED_PICKING_BY_PALLET, {"pallet": str(pallet or "").strip()})
rows = _rows_to_dicts(res)
return rows[0] if rows else None
async def skip_picking_pallet(
self,
*,
@@ -304,6 +357,35 @@ class BarcodeRepository:
),
)
async def fetch_active_skipped_document(self, id_stato: int) -> dict[str, Any] | None:
"""Return a reserved document whose remaining pallets were all skipped."""
res = await self.db_client.query_json(SQL_ACTIVE_SKIPPED_DOCUMENT, {"id_stato": int(id_stato)})
rows = _rows_to_dicts(res)
return rows[0] if rows else None
async def release_picking_document(self, *, documento: str, operator_id: int) -> int:
"""Release a reserved picking-list document without closing its residual rows."""
params = {
"documento": str(documento or "").strip(),
"id_operatore": int(operator_id),
}
log_runtime_event(
"Barcode WMS",
f"PICKING AUTO RELEASE START documento={params['documento']} operator={params['id_operatore']}",
)
res = await self.db_client.query_json(SQL_RELEASE_PICKING_DOCUMENT, params, as_dict_rows=True, commit=True)
rows = _rows_to_dicts(res)
rc = 0
if rows:
try:
rc = int(rows[0].get("RC") or 0)
except Exception:
rc = 0
log_runtime_event("Barcode WMS", f"PICKING AUTO RELEASE END documento={params['documento']} rc={rc}")
return rc
async def resolve_physical_cell(self, destination: str) -> DestinationCell | None:
"""Accept either an internal cell ID or the scanned legacy cell barcode."""