# 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.