Milestone alpha2

This commit is contained in:
2026-05-22 15:15:43 +02:00
parent a5e704c214
commit d2a1f6a068
4 changed files with 508 additions and 64 deletions

View File

@@ -586,3 +586,236 @@ Dopo approvazione di questo documento:
2. testare il risultato con almeno 3 picking list attive 2. testare il risultato con almeno 3 picking list attive
3. verificare il comportamento sul backoffice 3. verificare il comportamento sul backoffice
4. verificare il comportamento sul barcode (`F1` / `F2`) 4. verificare il comportamento sul barcode (`F1` / `F2`)
---
## Revisione dopo test reale su documenti 133 / 135 / 137
Dopo avere applicato la prima correzione proposta solo sulla stored, il bug **resta presente**:
- prenotando il documento `133`
- la picking list `135` continua a risultare prenotata
Questo comportamento è coerente con le evidenze raccolte:
- `133` e `135` condividono la cella `8057`
- `135` e `137` condividono la cella `1000`
### Conclusione aggiornata
La correzione che agisce **solo** su `Celle.IDStato` non è sufficiente.
Il motivo è strutturale:
1. la stored può anche rendere idempotente `Prenota` / `S-prenota`
2. ma se la UI e il barcode continuano a dedurre lo stato della prenotazione da `Celle.IDStato`
3. una cella condivisa continuerà a far risultare prenotati anche documenti diversi
Quindi il modello corretto deve spostare la **sorgente di verità** della prenotazione:
- **da:** stato della cella
- **a:** documento prenotato attivo
### Nuova architettura proposta
La soluzione corretta è questa:
1. introdurre una piccola tabella di stato, ad esempio `dbo.PickingListReservation`
2. salvare lì il **documento attualmente prenotato**
3. fare in modo che `XMag_ViewPackingList.IDStato` non legga più la prenotazione da `Celle.IDStato`
4. calcolare invece `IDStato` così:
- `1` se `Documento = documento prenotato attivo`
- `0` negli altri casi
In questo modo:
- il backoffice mostra prenotata una sola picking list
- il barcode continua a usare `F1` = `IDStato 1` e `F2` = `IDStato 0`
- le celle condivise `1000` / `8057` non contaminano più altri documenti
### Ruolo residuo di `Celle.IDStato`
`Celle.IDStato` può restare utile come supporto:
- per visualizzazioni legacy
- per evidenziare le celle del documento attivo
- per non rompere altre parti del sistema che si aspettano quel flag
Ma non deve più essere la **fonte primaria** della prenotazione documento.
### Stored definitiva da realizzare
La stored `sp_xExePackingListPallet` deve quindi:
1. mantenere il parametro `@Azione = 'P' | 'S'`
2. aggiornare la tabella `PickingListReservation`
3. opzionalmente riallineare anche `Celle.IDStato`
4. mantenere il log in `LogPackingList`
Semantica definitiva:
- `Prenota`
- se il documento è già quello attivo: nessun effetto
- altrimenti:
- il documento diventa lunico prenotato attivo
- tutte le altre picking list risultano non prenotate
- `S-prenota`
- se il documento non è quello attivo: nessun effetto
- se il documento è quello attivo:
- la prenotazione viene rimossa
- nessun altro documento viene acceso automaticamente
### Nota importante
Questa revisione **supera** la proposta precedente basata soltanto sul reset/set di `Celle.IDStato`.
La patch SQL definitiva deve quindi includere:
1. creazione della tabella `PickingListReservation`
2. `CREATE OR ALTER` della stored `sp_xExePackingListPallet`
3. `CREATE OR ALTER` della vista `XMag_ViewPackingList`
Questo è il primo assetto realmente coerente con il requisito di business:
> una sola picking list prenotata alla volta, anche in presenza di celle condivise.
---
## Evoluzione proposta: usare `ViewPackingListRestante` anche per la lista alta
### Situazione attuale
Nel legacy C# e nel Python attuale la distinzione è questa:
- la **griglia alta** legge la testata aggregata da `XMag_ViewPackingList`
- la **griglia bassa** legge il dettaglio da `ViewPackingListRestante`
La vista `ViewPackingListRestante` è definita come:
```sql
SELECT ...
FROM XMag_ViewPackingList
WHERE Cella <> 9999
```
Quindi:
- `XMag_ViewPackingList` contiene anche le UDC già finite nella locazione convenzionale `9999 = 7G.1.1`
- `ViewPackingListRestante` mostra invece solo le UDC ancora residue
### Conseguenza pratica
Allistante `t = 0` della prenotazione:
- se la picking list non è ancora stata lavorata, `XMag_ViewPackingList` e `ViewPackingListRestante` mostrano di fatto lo stesso insieme di UDC
- le UDC non scaffalate **restano presenti** in entrambe, perché stanno nella cella convenzionale `1000 = 5E1.1`
Dopo che il magazziniere ha iniziato i prelievi:
- le UDC già spedite/prelevate finiscono in `9999 = 7G.1.1`
- quindi spariscono da `ViewPackingListRestante`
- ma restano ancora visibili in `XMag_ViewPackingList`
### Limite del comportamento attuale
Con la summary alta basata su `XMag_ViewPackingList`:
- il comando `Ricarica` può continuare a mostrare picking list già lavorate in parte
- una picking list completamente esaurita può restare visibile nella lista alta
- il contenuto della lista alta non coincide più con il “residuo operativo reale”
In altre parole:
- la griglia bassa mostra il residuo
- la griglia alta mostra ancora lo storico completo
### Modifica proposta
La proposta è:
- usare `ViewPackingListRestante` anche come sorgente della **lista alta aggregata**
quindi sostituire, nella query summary di [gestione_pickinglist.py](C:/devel/python/ware_house/gestione_pickinglist.py):
- `FROM dbo.XMag_ViewPackingList`
con:
- `FROM dbo.ViewPackingListRestante`
mantenendo invariati:
- `GROUP BY Documento, CodNazione, NAZIONE, Stato`
- `COUNT(DISTINCT Pallet)`
- `COUNT(DISTINCT Lotto)`
- `COUNT(DISTINCT Articolo)`
- `SUM(Qta)`
- `MIN(Ordinamento)`
- `MAX(IDStato)`
### Effetti attesi
Con questa modifica:
1. allinizio una picking list nuova continua a comparire normalmente
2. durante il lavoro il pulsante `Ricarica` mostra solo ciò che resta davvero da prelevare
3. le UDC già finite in `7G.1.1` non inquinano più i conteggi della testata
4. una picking list completamente esaurita esce naturalmente dalla lista visibile
5. le UDC non scaffalate continuano a comparire correttamente, perché stanno in `1000 = 5E1.1`, non in `9999`
### Chiusura automatica della prenotazione
Per mantenere coerenti:
- griglia alta
- stato della prenotazione
- comportamento del barcode `F1`
la prenotazione attiva non deve soltanto sparire dalla griglia: deve essere anche **azzerata logicamente** quando il residuo arriva a zero.
La patch SQL definitiva quindi deve fare anche questo:
- dopo ogni movimento, controllare se il documento prenotato ha ancora righe in `ViewPackingListRestante`
- se non ne ha più:
- la prenotazione attiva va portata a `NULL` / `0`
- le eventuali celle residue marcate `IDStato = 1` vanno riportate a `0`
Effetto operativo:
- plist piena allinizio
- plist via via ridotta durante i prelievi
- plist che, allultima UDC, sparisce dalla griglia alta
- e nello stesso momento cessa anche di essere la coda `F1`
### Impatto funzionale
Questa modifica:
- **non è** una replica pedissequa del legacy C#
- ma è un miglioramento operativo coerente con il comportamento atteso dal magazzino
In particolare rende la lista alta:
- più coerente con il significato di “picking list ancora da esaurire”
- allineata al contenuto della griglia bassa
- più utile nei refresh successivi durante il lavoro reale
### Impatto tecnico
Il cambiamento richiesto è piccolo lato Python:
- aggiornare la query summary in [gestione_pickinglist.py](C:/devel/python/ware_house/gestione_pickinglist.py)
Non richiede, in prima battuta:
- modifiche alla stored di prenotazione
- modifiche al barcode
- modifiche a `ViewPackingListRestante`
### Decisione progettuale
Questa modifica va considerata come una scelta esplicita di evoluzione:
- **se vogliamo restare 1:1 col C#**, la lista alta resta su `XMag_ViewPackingList`
- **se vogliamo rendere il modulo più aderente al residuo operativo reale**, conviene passare a `ViewPackingListRestante`

View File

@@ -215,7 +215,7 @@ SELECT
MAX(Cella) AS Cella, MAX(Cella) AS Cella,
MIN(Ordinamento) AS Ordinamento, MIN(Ordinamento) AS Ordinamento,
MAX(IDStato) AS IDStato MAX(IDStato) AS IDStato
FROM dbo.XMag_ViewPackingList FROM dbo.ViewPackingListRestante
GROUP BY Documento, CodNazione, NAZIONE, Stato GROUP BY Documento, CodNazione, NAZIONE, Stato
ORDER BY MIN(Ordinamento), Documento, NAZIONE, Stato; ORDER BY MIN(Ordinamento), Documento, NAZIONE, Stato;
""" """

View File

@@ -65,7 +65,7 @@ class LoginWindow(tk.Toplevel):
self._busy = InlineBusyOverlay(self, self._theme) self._busy = InlineBusyOverlay(self, self._theme)
self.title(loc_text("login.msg.title", catalog=self._locale_catalog, default="Login")) self.title(loc_text("login.msg.title", catalog=self._locale_catalog, default="Login"))
self.geometry("170x145+0+0" if self.compact else str(theme_value(self._theme, "window_geometry", "420x250"))) self.geometry("170x145+0+0" if self.compact else str(theme_value(self._theme, "window_geometry", "235x185+0+0")))
self.resizable(False, False) self.resizable(False, False)
try: try:
if parent is not None and parent.winfo_viewable(): if parent is not None and parent.winfo_viewable():
@@ -88,7 +88,7 @@ class LoginWindow(tk.Toplevel):
def _build_ui(self) -> None: def _build_ui(self) -> None:
"""Build the compact operator login form.""" """Build the compact operator login form."""
body = ttk.Frame(self, padding=8 if self.compact else 12) body = ttk.Frame(self, padding=8 if self.compact else 10)
body.pack(fill="both", expand=True) body.pack(fill="both", expand=True)
body.columnconfigure(1, weight=1) body.columnconfigure(1, weight=1)
@@ -97,8 +97,8 @@ class LoginWindow(tk.Toplevel):
ttk.Label( ttk.Label(
body, body,
text=loc_text("login.heading", catalog=self._locale_catalog, default="Autenticazione operatore"), text=loc_text("login.heading", catalog=self._locale_catalog, default="Autenticazione operatore"),
font=("Segoe UI", 11, "bold"), font=("Segoe UI", 9, "bold"),
).grid(row=0, column=0, columnspan=2, sticky="w", pady=(4, 14)) ).grid(row=0, column=0, columnspan=2, sticky="w", pady=(0, 8))
row_offset = 1 row_offset = 1
ttk.Label(body, text="User:").grid( ttk.Label(body, text="User:").grid(
@@ -127,36 +127,23 @@ class LoginWindow(tk.Toplevel):
) )
self._login_button.grid(row=0, column=0, sticky="ew") self._login_button.grid(row=0, column=0, sticky="ew")
else: else:
self.info_label = ttk.Label(
body,
text=loc_text(
"login.info",
catalog=self._locale_catalog,
default="Per ora tutti gli operatori autenticati possono usare tutte le funzioni.",
),
justify="left",
wraplength=320,
)
self.info_label.grid(row=3, column=0, columnspan=2, sticky="ew", pady=(10, 8))
self.status_label = ttk.Label(body, textvariable=self._status_var, foreground="#555555") self.status_label = ttk.Label(body, textvariable=self._status_var, foreground="#555555")
self.status_label.grid(row=4, column=0, columnspan=2, sticky="w", pady=(2, 2)) self.status_label.grid(row=3, column=0, columnspan=2, sticky="w", pady=(2, 2))
actions = ttk.Frame(body) actions = ttk.Frame(body)
actions.grid(row=5, column=0, columnspan=2, sticky="ew", pady=(6, 0)) actions.grid(row=4, column=0, columnspan=2, sticky="w", pady=(6, 0))
actions.columnconfigure(0, weight=1)
self._cancel_button = ttk.Button( self._cancel_button = ttk.Button(
actions, actions,
text=loc_text("login.button.cancel", catalog=self._locale_catalog, default="Annulla"), text=loc_text("login.button.cancel", catalog=self._locale_catalog, default="Annulla"),
command=self._on_cancel, command=self._on_cancel,
) )
self._cancel_button.grid(row=0, column=1, padx=(0, 8), pady=8) self._cancel_button.grid(row=1, column=0, sticky="ew", pady=(4, 0))
self._login_button = ttk.Button( self._login_button = ttk.Button(
actions, actions,
text=loc_text("login.button.submit", catalog=self._locale_catalog, default="Accedi"), text=loc_text("login.button.submit", catalog=self._locale_catalog, default="OK"),
command=self._on_login, command=self._on_login,
) )
self._login_button.grid(row=0, column=2, pady=8) self._login_button.grid(row=0, column=0, sticky="ew")
self.bind("<Return>", lambda _e: self._on_login()) self.bind("<Return>", lambda _e: self._on_login())
self.bind("<Escape>", lambda _e: self._on_cancel()) self.bind("<Escape>", lambda _e: self._on_cancel())

View File

@@ -3,6 +3,40 @@ GO
SET QUOTED_IDENTIFIER ON SET QUOTED_IDENTIFIER ON
GO GO
/* ============================================================
Patch prenotazione Picking List a livello documento
Obiettivo:
- rendere esclusiva la prenotazione di una sola picking list
- mantenere la stored con lo stesso nome:
dbo.sp_xExePackingListPallet
- introdurre una sorgente di verità per documento prenotato:
dbo.PickingListReservation
- far leggere XMag_ViewPackingList.IDStato da tale stato
e non più soltanto da Celle.IDStato
============================================================ */
IF OBJECT_ID(N'dbo.PickingListReservation', N'U') IS NULL
BEGIN
CREATE TABLE [dbo].[PickingListReservation](
[ID] [tinyint] NOT NULL,
[Documento] [varchar](8) NULL,
[IDOperatore] [int] NULL,
[ModUtente] [varchar](50) NULL,
[ModDataOra] [datetime] NULL,
CONSTRAINT [PK_PickingListReservation] PRIMARY KEY CLUSTERED ([ID] ASC),
CONSTRAINT [CK_PickingListReservation_Singleton] CHECK ([ID] = 1)
) ON [PRIMARY];
END
GO
IF NOT EXISTS (SELECT 1 FROM dbo.PickingListReservation WHERE ID = 1)
BEGIN
INSERT INTO dbo.PickingListReservation (ID, Documento, IDOperatore, ModUtente, ModDataOra)
VALUES (1, NULL, NULL, NULL, GETDATE());
END
GO
CREATE OR ALTER PROCEDURE [dbo].[sp_xExePackingListPallet] CREATE OR ALTER PROCEDURE [dbo].[sp_xExePackingListPallet]
@IDOperatore int, @IDOperatore int,
@Documento varchar(8), @Documento varchar(8),
@@ -13,24 +47,46 @@ BEGIN
SET NOCOUNT ON; SET NOCOUNT ON;
SET @RC = 0; SET @RC = 0;
DECLARE @Nominativo varchar(50); DECLARE @Nominativo varchar(50) = '';
DECLARE @DocumentoPrenotato bit = 0; DECLARE @DocumentoAttivo varchar(8) = NULL;
DECLARE @Description varchar(255) = ''; DECLARE @Description varchar(255) = '';
DECLARE @Message varchar(255) = ''; DECLARE @Message varchar(255) = '';
DECLARE @IDResult int = 0; DECLARE @IDResult int = 0;
DECLARE @ID int = 0; DECLARE @ID int = 0;
DECLARE @Code varchar(64) = @Documento;
SELECT @Nominativo = [Login] SELECT @Nominativo = [Login]
FROM dbo.Operatori FROM dbo.Operatori
WHERE ID = @IDOperatore; WHERE ID = @IDOperatore;
IF @Nominativo IS NULL
SET @Nominativo = 'SYSTEM';
IF @Azione NOT IN ('P', 'S') IF @Azione NOT IN ('P', 'S')
BEGIN BEGIN
SET @RC = -10; SET @RC = -10;
RETURN; RETURN;
END; END;
IF NOT EXISTS (
SELECT 1
FROM dbo.XMag_ViewPackingList
WHERE CAST(Documento AS varchar(8)) = @Documento
)
BEGIN
SET @RC = -20;
RETURN;
END;
IF NOT EXISTS (SELECT 1 FROM dbo.PickingListReservation WHERE ID = 1)
BEGIN
INSERT INTO dbo.PickingListReservation (ID, Documento, IDOperatore, ModUtente, ModDataOra)
VALUES (1, NULL, NULL, NULL, GETDATE());
END;
SELECT @DocumentoAttivo = NULLIF(LTRIM(RTRIM(Documento)), '')
FROM dbo.PickingListReservation
WHERE ID = 1;
DECLARE @TargetCelle TABLE ( DECLARE @TargetCelle TABLE (
IDCella int PRIMARY KEY IDCella int PRIMARY KEY
); );
@@ -38,46 +94,21 @@ BEGIN
INSERT INTO @TargetCelle (IDCella) INSERT INTO @TargetCelle (IDCella)
SELECT DISTINCT Cella SELECT DISTINCT Cella
FROM dbo.XMag_ViewPackingList FROM dbo.XMag_ViewPackingList
WHERE Documento = @Documento WHERE CAST(Documento AS varchar(8)) = @Documento
AND Cella IS NOT NULL; AND Cella IS NOT NULL;
IF NOT EXISTS (SELECT 1 FROM @TargetCelle)
BEGIN
SET @RC = -20;
RETURN;
END;
IF EXISTS (
SELECT 1
FROM dbo.XMag_ViewPackingList
WHERE Documento = @Documento
AND ISNULL(IDStato, 0) = 1
)
BEGIN
SET @DocumentoPrenotato = 1;
END;
IF @Azione = 'P' IF @Azione = 'P'
BEGIN BEGIN
-- Gia' prenotata: nessuna variazione IF @DocumentoAttivo = @Documento
IF @DocumentoPrenotato = 1
RETURN; RETURN;
-- Azzera la prenotazione di tutti gli altri documenti
UPDATE c UPDATE c
SET c.IDStato = 0, SET c.IDStato = 0,
c.ModUtente = @Nominativo, c.ModUtente = @Nominativo,
c.ModDataOra = GETDATE() c.ModDataOra = GETDATE()
FROM dbo.Celle c FROM dbo.Celle c
WHERE c.ID IN ( WHERE ISNULL(c.IDStato, 0) <> 0;
SELECT DISTINCT Cella
FROM dbo.XMag_ViewPackingList
WHERE ISNULL(IDStato, 0) = 1
AND Documento <> @Documento
AND Cella IS NOT NULL
);
-- Prenota soltanto le celle del documento target
UPDATE c UPDATE c
SET c.IDStato = 1, SET c.IDStato = 1,
c.ModUtente = @Nominativo, c.ModUtente = @Nominativo,
@@ -85,27 +116,32 @@ BEGIN
FROM dbo.Celle c FROM dbo.Celle c
INNER JOIN @TargetCelle t ON t.IDCella = c.ID; INNER JOIN @TargetCelle t ON t.IDCella = c.ID;
UPDATE dbo.PickingListReservation
SET Documento = @Documento,
IDOperatore = @IDOperatore,
ModUtente = @Nominativo,
ModDataOra = GETDATE()
WHERE ID = 1;
SELECT TOP 1 @Description = NAZIONE SELECT TOP 1 @Description = NAZIONE
FROM dbo.XMag_ViewPackingList FROM dbo.XMag_ViewPackingList
WHERE Documento = @Documento; WHERE CAST(Documento AS varchar(8)) = @Documento;
EXECUTE @RC = [dbo].[sp_LogPackingList] EXEC dbo.sp_LogPackingList
@ID @ID = @ID,
,@Code @Code = @Documento,
,@Description @Description = @Description,
,@Message OUTPUT @Message = @Message OUTPUT,
,@IDResult OUTPUT; @IDResult = @IDResult OUTPUT;
RETURN; RETURN;
END; END;
IF @Azione = 'S' IF @Azione = 'S'
BEGIN BEGIN
-- Gia' non prenotata: nessuna variazione IF ISNULL(@DocumentoAttivo, '') <> @Documento
IF @DocumentoPrenotato = 0
RETURN; RETURN;
-- Togli la prenotazione soltanto al documento target
UPDATE c UPDATE c
SET c.IDStato = 0, SET c.IDStato = 0,
c.ModUtente = @Nominativo, c.ModUtente = @Nominativo,
@@ -113,7 +149,195 @@ BEGIN
FROM dbo.Celle c FROM dbo.Celle c
INNER JOIN @TargetCelle t ON t.IDCella = c.ID; INNER JOIN @TargetCelle t ON t.IDCella = c.ID;
UPDATE dbo.PickingListReservation
SET Documento = NULL,
IDOperatore = @IDOperatore,
ModUtente = @Nominativo,
ModDataOra = GETDATE()
WHERE ID = 1;
RETURN; RETURN;
END; END;
END; END;
GO GO
CREATE OR ALTER VIEW [dbo].[XMag_ViewPackingList]
AS
WITH Base AS (
SELECT
dbo.vPreparaPackingList.UDC AS Pallet,
dbo.vPreparaPackingList.NUMLOT AS Lotto,
dbo.vPreparaPackingList.CODICE AS Articolo,
dbo.vPreparaPackingList.DESCR AS Descrizione,
dbo.vPreparaPackingList.Qta,
dbo.vPreparaPackingList.NUMDOC AS Documento,
dbo.vPreparaPackingList.Expr1 AS CodNazione,
dbo.vPreparaPackingList.NAZIONE,
CASE
WHEN Expr1 = 'DE' THEN 10
WHEN Expr1 = 'TH' THEN CASE WHEN SUBSTRING(dbo.vPreparaPackingList.DESCRDEST, 1, 2) = 'NA' THEN 11 ELSE 13 END
WHEN Expr1 = 'MEX' THEN 12
ELSE 4
END AS Stato,
ISNULL(dbo.XMag_GiacenzaPallet.NumeroPallet, 0) AS PalletCella,
ISNULL(dbo.XMag_GiacenzaPallet.IDMagazzino, 1) AS Magazzino,
ISNULL(dbo.XMag_GiacenzaPallet.IDArea, 5) AS Area,
ISNULL(dbo.XMag_GiacenzaPallet.IDCella, 1000) AS Cella,
ISNULL(dbo.Celle.Ordinamento, 99999) AS Ordinamento,
ISNULL(dbo.Celle.Corsia + ' - ' + dbo.Celle.Colonna + ' - ' + dbo.Celle.Fila, 'Non scaff.') AS Ubicazione,
SUBSTRING(dbo.vPreparaPackingList.DESCRDEST, 1, 2) AS DEST
FROM dbo.Celle
INNER JOIN dbo.XMag_GiacenzaPallet
ON dbo.Celle.ID = dbo.XMag_GiacenzaPallet.IDCella
RIGHT OUTER JOIN dbo.vPreparaPackingList
ON dbo.XMag_GiacenzaPallet.BarcodePallet COLLATE SQL_Latin1_General_CP1_CI_AS = dbo.vPreparaPackingList.UDC
GROUP BY
dbo.vPreparaPackingList.Expr1,
dbo.vPreparaPackingList.NAZIONE,
dbo.vPreparaPackingList.UDC,
dbo.vPreparaPackingList.NUMDOC,
dbo.vPreparaPackingList.NUMLOT,
dbo.vPreparaPackingList.CODICE,
dbo.vPreparaPackingList.DESCR,
dbo.vPreparaPackingList.Qta,
dbo.XMag_GiacenzaPallet.NumeroPallet,
dbo.XMag_GiacenzaPallet.IDMagazzino,
dbo.XMag_GiacenzaPallet.IDArea,
dbo.XMag_GiacenzaPallet.IDCella,
dbo.Celle.Ordinamento,
dbo.Celle.Corsia,
dbo.Celle.Colonna,
dbo.Celle.Fila,
dbo.vPreparaPackingList.DESCRDEST
)
SELECT TOP 10000
Base.Pallet,
Base.Lotto,
Base.Articolo,
Base.Descrizione,
Base.Qta,
Base.Documento,
Base.CodNazione,
Base.NAZIONE,
Base.Stato,
Base.PalletCella,
Base.Magazzino,
Base.Area,
Base.Cella,
Base.Ordinamento,
Base.Ubicazione,
Base.DEST,
CASE
WHEN pr.Documento IS NOT NULL
AND pr.Documento = CAST(Base.Documento AS varchar(8))
THEN 1
ELSE 0
END AS IDStato
FROM Base
LEFT JOIN dbo.PickingListReservation pr
ON pr.ID = 1
AND NULLIF(LTRIM(RTRIM(pr.Documento)), '') IS NOT NULL
ORDER BY
CASE
WHEN pr.Documento IS NOT NULL
AND pr.Documento = CAST(Base.Documento AS varchar(8))
THEN 1
ELSE 0
END DESC,
Base.Documento,
Base.Ordinamento;
GO
CREATE OR ALTER PROCEDURE [dbo].[sp_xExePackingListPalletPrenota]
@IDOperatore int,
@Documento varchar(8),
@RC int OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET @RC = 0;
DECLARE @Nominativo varchar(50) = '';
SELECT @Nominativo = LOGIN
FROM dbo.Operatori
WHERE ID = @IDOperatore;
IF @Nominativo IS NULL
SET @Nominativo = 'SYSTEM';
UPDATE c
SET c.IDStato = 1,
c.ModUtente = @Nominativo,
c.ModDataOra = GETDATE()
FROM dbo.Celle c
WHERE c.ID IN (
SELECT DISTINCT Cella
FROM dbo.ViewPackingListRestante
WHERE CAST(Documento AS varchar(8)) = @Documento
AND Cella IS NOT NULL
);
END;
GO
CREATE OR ALTER PROCEDURE [dbo].[sp_ControllaPrenotazionePackingListPalletNew]
AS
BEGIN
SET NOCOUNT ON;
DECLARE @Documento varchar(8) = NULL;
DECLARE @IDOperatore int = 0;
DECLARE @Nominativo varchar(50) = 'SYSTEM';
DECLARE @RC int = 0;
SELECT
@Documento = NULLIF(LTRIM(RTRIM(Documento)), ''),
@IDOperatore = ISNULL(IDOperatore, 0),
@Nominativo = ISNULL(NULLIF(LTRIM(RTRIM(ModUtente)), ''), 'SYSTEM')
FROM dbo.PickingListReservation
WHERE ID = 1;
IF ISNULL(@Documento, '') = ''
RETURN;
IF NOT EXISTS (
SELECT 1
FROM dbo.ViewPackingListRestante
WHERE CAST(Documento AS varchar(8)) = @Documento
)
BEGIN
UPDATE dbo.Celle
SET IDStato = 0,
ModUtente = @Nominativo,
ModDataOra = GETDATE()
WHERE ISNULL(IDStato, 0) <> 0;
UPDATE dbo.PickingListReservation
SET Documento = NULL,
IDOperatore = @IDOperatore,
ModUtente = @Nominativo,
ModDataOra = GETDATE()
WHERE ID = 1;
RETURN;
END;
UPDATE dbo.Celle
SET IDStato = 0,
ModUtente = @Nominativo,
ModDataOra = GETDATE()
WHERE ISNULL(IDStato, 0) <> 0;
IF @IDOperatore <= 0
BEGIN
SELECT TOP 1 @IDOperatore = ID
FROM dbo.Operatori
WHERE LOGIN = @Nominativo;
END;
EXEC dbo.sp_xExePackingListPalletPrenota
@IDOperatore = @IDOperatore,
@Documento = @Documento,
@RC = @RC OUTPUT;
END;
GO