Files
ware_house/ordinamento.md

415 lines
13 KiB
Markdown

# Ordinamento di prelievo delle celle
## 1. Scopo del documento
Questo documento descrive il significato e l'origine del campo
`dbo.Celle.Ordinamento`, il modo in cui viene utilizzato per proporre le UDC al
barcode e le differenze riscontrate tra i due magazzini storici:
- Area 5, identificata nel database legacy come magazzino `MDE5`;
- Area 6, identificata nel database legacy come magazzino `MDE6`.
Nel linguaggio operativo si parla di Area 5 e Area 6. Nel modello legacy,
tuttavia, la tabella `Magazzini` contiene `MDE5` e `MDE6`, mentre la tabella
`Aree` contiene le singole corsie o scaffali. Gli ID della tabella `Aree` non
devono quindi essere confusi con i nomi operativi Area 5 e Area 6.
Le conclusioni riportate derivano da:
- struttura e dati correnti della tabella `dbo.Celle`;
- stored procedure legacy contenute in `script.sql`;
- viste usate dalle picking list;
- codice Python del barcode e della gestione picking list;
- confronto tra `ID`, ubicazione e `Ordinamento` delle celle reali.
## 2. Significato di `Celle.Ordinamento`
`Celle.Ordinamento` e' una priorita' numerica associata all'anagrafica della
cella. Rappresenta la posizione della cella nel percorso predefinito di
prelievo.
Il campo non indica:
- la quantita' di UDC presenti;
- la priorita' della picking list;
- lo stato libero o occupato della cella;
- l'ordine cronologico di inserimento delle UDC;
- l'ID della UDC;
- la distanza calcolata dinamicamente dal barcode.
Il valore non viene ricalcolato durante un versamento o un prelievo. E' un dato
statico dell'anagrafica della cella, salvo interventi amministrativi o
procedure specifiche di rinumerazione.
Il tipo SQL storico e' `float`, ma nei dati analizzati viene usato come numero
intero progressivo. Nella futura riprogettazione sarebbe preferibile un tipo
intero o una struttura esplicita di percorso.
## 3. Dove viene assegnato
La stored procedure legacy `dbo.spt_SaveCelle` riceve il parametro
`@Ordinamento` e lo salva direttamente:
```sql
UPDATE Celle
SET Ordinamento = @Ordinamento
WHERE ID = @ID;
```
Se la cella non esiste, la stessa stored procedure esegue una `INSERT` e
inserisce il valore ricevuto. La procedura non contiene una formula per
calcolarlo: chi crea o modifica la cella deve decidere il valore e passarlo.
Nel database non risultano trigger sulla tabella `Celle` che aggiornino
automaticamente `Ordinamento`.
Sono state individuate anche procedure legacy di supporto:
- `CreaNuoveCelle`;
- `CreaNuoveCelleMDE6`;
- `CreaNuoveCelleMDE6_BIS`;
- `sp_OrdinaCelle`;
- `spt_SaveCelle`.
Le procedure di creazione MDE6 impostano normalmente:
```sql
SET @Ordinamento = @ID;
```
La procedura `sp_OrdinaCelle` dimostra invece che il campo puo' essere
rinumerato in un secondo momento per rappresentare un percorso differente
dall'ID della cella.
## 4. Uso durante una picking list
Le viste operative associano ogni UDC alla cella corrente e recuperano
`Celle.Ordinamento`. Il barcode richiede la prima riga residua secondo l'ordine
effettivo.
Prima dell'introduzione della sequenza personalizzata, il criterio principale
era sostanzialmente:
```sql
ORDER BY Ordinamento;
```
Questo significa che il barcode non percorre tutte le celle del magazzino. La
vista contiene soltanto le UDC ancora presenti nella picking list: le celle che
non contengono una UDC richiesta vengono saltate automaticamente.
Esempio: se il percorso contiene le celle con ordine `1001`, `1002`, `1003` e
`1004`, ma la picking list contiene UDC soltanto nelle celle `1001` e `1004`, il
barcode propone direttamente la UDC di `1001` e poi quella di `1004`.
## 5. Ordinamento dell'Area 5 / MDE5
### 5.1 Caratteristica generale
Nell'Area 5 `Ordinamento` non coincide normalmente con l'ID della cella. Dai
dati emerge un percorso fisico costruito intenzionalmente, verosimilmente
hardcoded o rinumerato durante la configurazione iniziale del magazzino.
Le corsie principali coinvolte sono:
- `1A`;
- `2B`;
- `3C`;
- `4D`.
Il percorso iniziale delle corsie `1A` e `2B` e' a serpentina. Le due corsie
vengono trattate come lati o scaffali adiacenti di uno stesso tragitto fisico.
### 5.2 Esempio reale dell'inizio del percorso
```text
Ordine Ubicazione ID cella
1001 1A.1.e 1005
1002 1A.1.d 1004
1003 1A.1.c 1003
1004 1A.1.b 1002
1005 1A.1.a 1001
1007 2B.1.e 2005
1008 2B.1.d 2004
1009 2B.1.c 2003
1010 2B.1.b 2002
1011 2B.1.a 2001
1013 2B.2.e 2011
1014 2B.2.d 2010
1015 2B.2.c 2009
1016 2B.2.b 2008
1017 2B.2.a 2007
1019 1A.2.e 1011
1020 1A.2.d 1010
1021 1A.2.c 1009
1022 1A.2.b 1008
1023 1A.2.a 1007
```
La sequenza prosegue con lo stesso principio:
```text
1A campata 1
2B campata 1
2B campata 2
1A campata 2
1A campata 3
2B campata 3
2B campata 4
1A campata 4
...
```
### 5.3 Movimento verticale nella campata
All'interno di ciascuna campata l'ordine verificato e':
```text
e -> d -> c -> b -> a
```
Il percorso procede quindi dal livello identificato con `e` verso il livello
`a`. Non viene prelevata una sola UDC per campata per poi ricominciare il giro.
Vengono considerate, in sequenza, tutte le celle richieste della campata
corrente prima di passare alla campata successiva.
Se una campata contiene piu' UDC richieste in livelli diversi, il barcode le
propone secondo `e, d, c, b, a`. Se alcuni livelli non contengono UDC della
picking list, vengono semplicemente saltati.
### 5.4 Alternanza tra 1A e 2B
Il sistema non esaurisce tutto `1A` prima di iniziare `2B`. Alterna blocchi di
campate tra le due corsie per seguire un tragitto a serpentina ed evitare
ritorni inutili.
Il comportamento predefinito storico e' quindi:
- completare le UDC richieste nella campata corrente;
- passare alla campata fisicamente successiva del percorso;
- alternare `1A` e `2B` secondo la serpentina configurata;
- non tornare all'inizio dopo ogni singola UDC.
### 5.5 Passaggio a 3C e 4D
Le corsie `3C` e `4D` hanno valori di ordinamento molto piu' alti. Nei dati
analizzati:
```text
1A: minimo 1001, massimo 1275
2B: minimo 1007, massimo 1251
3C: minimo 10019, massimo 10227
4D: valori nell'intervallo 10055 - 10233 circa
```
Di conseguenza il percorso storico esaurisce normalmente il blocco `1A/2B`
prima di passare al blocco `3C/4D`.
La presenza di famiglie numeriche differenti indica che l'ordinamento
dell'Area 5 e' stato costruito o modificato in piu' fasi storiche.
### 5.6 Significato dei numeri mancanti
La progressione contiene intervalli non utilizzati, per esempio `1005` seguito
da `1007`. Il numero mancante non indica necessariamente una cella eliminata o
un errore. Puo' essere stato lasciato come separatore tra campate o derivare
dalla procedura di rinumerazione.
Il software deve usare il confronto numerico e non deve presumere che tutti i
valori siano consecutivi.
## 6. Ordinamento dell'Area 6 / MDE6
### 6.1 Caratteristica generale
Nell'Area 6 il modello e' piu' semplice. La maggior parte delle celle e' stata
generata con `Ordinamento` uguale all'ID della cella.
Le famiglie principali sono:
```text
1M -> celle e ordinamenti 5001, 5002, 5003, ...
2N -> celle e ordinamenti 6001, 6002, 6003, ...
3O -> celle e ordinamenti 7001, 7002, 7003, ...
4P -> celle e ordinamenti 8001, 8002, 8003, ...
```
Le procedure `CreaNuoveCelleMDE6` e `CreaNuoveCelleMDE6_BIS` creano le celle
con cicli annidati e assegnano esplicitamente:
```sql
SET @Ordinamento = @ID;
```
### 6.2 Ordine degli scaffali
Poiche' le famiglie numeriche sono separate, l'ordine globale predefinito e':
```text
1M -> 2N -> 3O -> 4P
```
Senza una sequenza personalizzata vengono quindi considerate prima tutte le
UDC richieste in `1M`, poi quelle in `2N`, successivamente `3O` e infine `4P`.
### 6.3 Ordine interno dello scaffale
Durante la generazione delle celle, i cicli legacy incrementano prima la
campata e, all'interno della campata, il piano. L'ordine risultante e':
```text
1M.1.a -> 1M.1.b -> 1M.1.c -> 1M.1.d -> 1M.1.e
1M.2.a -> 1M.2.b -> 1M.2.c -> 1M.2.d -> 1M.2.e
...
2N.1.a -> 2N.1.b -> ...
```
Quindi l'Area 6 differisce dall'Area 5 in due aspetti principali:
- non presenta l'alternanza a serpentina tra due corsie adiacenti;
- dentro la campata procede da `a` verso `e`, mentre nell'Area 5 verificata
procede da `e` verso `a`.
### 6.4 Limiti della ricostruzione
Il comportamento descritto deriva dalla procedura di generazione e dai valori
correnti. Eventuali celle aggiunte manualmente in tempi successivi possono
avere eccezioni. L'applicazione deve sempre leggere il valore effettivo dal
database e non ricostruirlo aritmeticamente dall'ubicazione.
## 7. Celle virtuali
Nel sistema legacy esistono due ubicazioni convenzionali:
```text
ID 1000 -> 5E.1.1 -> Non scaff. -> Ordinamento 99999
ID 9999 -> 7G.1.1 -> Spedita -> Ordinamento 0
```
Questi valori non rappresentano un percorso fisico:
- `5E.1.1` identifica UDC presenti nel magazzino ma non allocate in uno
scaffale fisico;
- `7G.1.1` identifica UDC spedite.
Storicamente `Non scaff.` aveva ordinamento `99999`, quindi finiva in fondo
alla picking list. Il nuovo requisito operativo stabilisce invece che le UDC
non scaffalate devono essere proposte per prime.
La nuova vista Python non modifica `Celle.Ordinamento`: assegna a `Non scaff.`
una precedenza logica di gruppo pari a zero. La cella `Spedita` non entra nella
vista residuale e quindi non viene proposta dal barcode.
## 8. Nuovo ordinamento predefinito Python
In assenza di una configurazione specifica per il documento, il nuovo ordine
effettivo e':
1. tutte le UDC `Non scaff.` ancora appartenenti alla picking list;
2. tutte le UDC nelle celle fisiche secondo `Celle.Ordinamento`;
3. codice pallet come criterio stabile in caso di parita'.
In forma semplificata:
```sql
ORDER BY
OrdinePrelievoGruppo,
Ordinamento,
Pallet;
```
Per le celle fisiche, se non esiste una personalizzazione,
`OrdinePrelievoGruppo` conserva la progressione storica. Il percorso dell'Area
5 rimane quindi a serpentina e quello dell'Area 6 rimane progressivo.
## 9. Effetto della sequenza personalizzata
La sequenza personalizzata opera a livello di gruppo o scaffale, non a livello
di singola cella.
Esempio di configurazione:
```text
1. Non scaff.
2. 3C
3. 1A
4. 2B
5. 4D
```
In questo caso il sistema esaurisce prima il gruppo `Non scaff.`, poi tutte le
UDC di `3C`, quindi tutte quelle di `1A` e cosi' via.
All'interno di ciascun gruppo continua a usare `Celle.Ordinamento`. Per
esempio, se `1A` viene posizionata prima di `2B`, non viene piu' conservata
l'alternanza storica tra `1A` e `2B`: vengono esaurite prima tutte le UDC di
`1A`, nel loro ordine interno, e successivamente quelle di `2B`.
Questa differenza e' intenzionale:
- ordine predefinito: conserva il percorso storico globale;
- ordine personalizzato: impone la precedenza degli scaffali scelta
dall'operatore e conserva l'ordine storico soltanto dentro ogni scaffale.
Se la sequenza personalizzata non include tutti i gruppi, quelli mancanti
vengono accodati secondo il percorso predefinito. Nessuna UDC viene esclusa.
## 10. UDC multiple, lotti e parita' di ordine
Piu' righe della vista possono riferirsi alla stessa UDC quando contiene piu'
lotti o articoli. Questo non significa che il magazziniere debba movimentare
fisicamente la stessa UDC piu' volte: l'unita' di movimentazione rimane il
pallet/UDC.
Piu' UDC possono inoltre risultare associate alla stessa cella nel modello
legacy. In quel caso condividono lo stesso `Ordinamento`. Il nuovo codice usa
anche `Pallet` come criterio finale per rendere stabile la sequenza, ma il
percorso fisico resta quello della cella.
## 11. Considerazioni per la futura riprogettazione
Nel futuro FlyWMS Core e' consigliabile separare esplicitamente:
- ordine fisico della cella dentro lo scaffale;
- ordine predefinito degli scaffali;
- percorso o strategia di visita del magazzino;
- ordine personalizzato per documento;
- priorita' operativa della picking list;
- eventuale ottimizzazione dinamica del percorso.
Il campo legacy `Celle.Ordinamento` incorpora piu' significati e dipende da
decisioni storiche non completamente documentate. Non dovrebbe essere copiato
alla lettera nel nuovo modello dati senza scomporne la semantica.
Una possibile struttura futura potrebbe prevedere:
- `Location.SequenceWithinRack` per l'ordine interno;
- `Rack.DefaultSequence` per l'ordine tra scaffali;
- `Route` e `RouteStep` per percorsi configurabili;
- `PickingDocumentRoute` per la personalizzazione della singola lista.
## 12. Riferimenti tecnici nel progetto
- `script.sql`: definizioni di `spt_SaveCelle`, `CreaNuoveCelleMDE6`,
`CreaNuoveCelleMDE6_BIS` e `sp_OrdinaCelle`;
- `barcode_repository.py`: interrogazione della prossima UDC;
- `gestione_pickinglist.py`: visualizzazione del dettaglio ordinato;
- `pickinglist_sequence.py`: gestione della sequenza per documento;
- `apply_pickinglist_sequence_patch.sql`: tabella e vista Python dedicate;
- `specifica_sequenza_prelievo.md`: specifica funzionale della nuova
configurazione.
## 13. Conclusione
L'Area 5 utilizza un percorso storico a serpentina, costruito per alternare
corsie e campate secondo la disposizione fisica. L'Area 6 utilizza invece una
progressione piu' semplice, sostanzialmente coincidente con gli ID creati in
sequenza.
Il nuovo software conserva entrambi i comportamenti come default, anticipa le
UDC non scaffalate e permette di sostituire l'ordine globale degli scaffali per
una singola picking list senza modificare l'anagrafica delle celle.