Specifica Form Barcode WMS
Documento di lavoro aggiornato per replica Python del client barcode C# con miglioramenti di usabilita'.

1. Obiettivo operativo
La form barcode guida il magazziniere in movimenti WMS di due tipi:
- prelievo verso la cella virtuale 9000000
- versamento verso una cella reale di magazzino
Entrambe le operazioni usano lo stesso motore di movimento DB; cambia la destinazione operativa.

2. Code F1 / F2
Il comportamento reale ricostruito e confermato e' il seguente:
- F1 = coda ad alta priorita', cioe' picking list prenotata (IDStato = 1)
- F2 = coda a bassa priorita', cioe' coda non prenotata (IDStato = 0)
Dall'interfaccia backoffice si puo' prenotare una sola picking list per volta. La lista prenotata entra in F1; la seconda coda operativa viene proposta con F2.

3. File C# analizzati
- FSkMovimenti.cs
- FSkAccettazione.cs
- FRMagViewLayout.cs
- GridViewColumnButtonMenu.cs
- script.sql

4. Comandi principali della form C#
- F1 / H Priority: imposta iStatoPkPallet = 1 e carica la prossima riga da XMag_ViewPackingList con IDStato = 1
- F2 / L Priority: imposta iStatoPkPallet = 0 e carica la prossima riga da XMag_ViewPackingList con IDStato = 0
- Enter / Salva: esegue il movimento quando i campi sono completi
- F4 / Elimina: forza uno scarico verso 9000000

5. Significato reale dei campi nella form legacy
La UI C# e' poco intuitiva perche' i nomi dei campi non spiegano il flusso.
- txtDocRif
etichetta visibile: Pallet
significato reale: barcode del pallet letto o da confermare
- txtBarcode
etichetta visibile: Cella
significato reale: destinazione operativa; nel picking viene impostata a 9000000
- lblTesto1
e' il vero indicatore di stato; viene usato anche come barra colorata
- lblTesto2
Documento nella fase di proposta picking; riga informativa variabile nella fase di conferma
- lblTesto3
cliente / nazione nella fase di proposta picking; riga informativa variabile nella fase di conferma
- lblTesto4
pallet atteso nella fase di proposta picking; riga informativa variabile nella fase di conferma

6. Query principale F1 / F2
Metodo chiave nel C#: GetDatiPallet("", "", idStato)
Query:
SELECT TOP 1 * FROM XMag_ViewPackingList WHERE Ordinamento > 0 AND IDStato = idStato ORDER BY Ordinamento
Effetto reale:
1. viene scelta la prossima UDC della coda selezionata
2. vengono riempiti i label con ubicazione, documento, cliente e pallet atteso
3. il campo Cella viene impostato a 9000000
4. l'operatore legge il pallet nel campo Pallet
5. se il pallet coincide con quello atteso, viene eseguito il prelievo

7. Reset dei campi e barra rossa / verde
Ricostruzione aggiornata dal C#:
- non emerge un pulsante esplicito che entri formalmente in una "modalita' versamento"
- i reset vengono fatti in modo automatico dentro GetDatiPallet(...) e GetDatiPalletLotto(...)
- all'inizio di questi metodi il C# pulisce i label, azzera txtDocRif e imposta lblTesto1.BackColor = Red
- quando il dato viene trovato correttamente, lblTesto1 passa a LightGreen o GreenYellow
Quindi la "barra rossa / verde" ricordata dall'operatore coincide con lblTesto1, non con un controllo separato.

8. Validazione dello scan
Metodo chiave: SalvaOk()
- se txtBarcode = 9000000, il pallet letto in txtDocRif deve coincidere con lblTesto4
- se non coincide: errore Errata Lettura e blocco operazione
- se coincide: chiamata a Ricevi(...)
Questa e' la protezione che impedisce di scaricare il pallet sbagliato durante il picking.

9. Esecuzione del movimento
Metodi chiave nel C#:
- Ricevi(...)
- spt_SaveStoredProcedure(...)
Stored procedure usata:
sp_xMagGestioneMagazziniPallet
Parametri principali:
- IDOperatore
- BarcodeCella
- BarcodePallet
- NumeroCella
Dopo il movimento il C# richiama ancora GetDatiPallet(sBarcodePallet, sBarcodeCella, iStatoPkPallet).
I messaggi di conferma vengono quindi scritti a valle della transazione DB, non prima.

10. Convenzioni logistiche emerse dalla verifica sul campo
La verifica con il magazziniere ha chiarito il significato delle celle convenzionali usate dai fallback del sistema.
- 9000000 = destinazione logica di input usata dalla form per il prelievo
- 9999 = locazione convenzionale 7G.1.1
- 1000 = locazione convenzionale 5E1.1
Questo significa che:
- una UDC prelevata dalla picking list finisce logicamente verso 9000000, ma viene poi rappresentata operativamente come 7G.1.1
- una UDC non scaffalata nella picking list viene proposta con la locazione convenzionale 5E1.1
I fallback che sembravano "sporchi" nel codice sono quindi parte della semantica reale del magazzino.

11. Comportamento osservato nel prelievo picking list
Flusso operativo confermato:
1. il magazziniere preme F1 o F2
2. il barcode mostra la prossima UDC della coda scelta con la sua locazione
3. l'operatore legge il pallet atteso
4. il movimento parte verso la destinazione logica 9000000
5. alla conferma compare Ok Scarico nella prima label
6. compare 7G.1.1 come locazione convenzionale di spedito
7. dopo il tempo della logica lato server viene proposta la UDC successiva
Questo comportamento percepito dall'operatore e' compatibile con il fatto che le label vengano aggiornate dopo il ritorno della stored.

12. Caso UDC non scaffalata
Nella vista SQL la UDC non scaffalata usa un fallback tecnico, ma per l'operatore la locazione visibile e significativa e':
- 5E1.1
Quindi il client Python non deve mostrare soltanto la stringa tecnica `Non scaff.`, ma deve privilegiare la convenzione operativa 5E1.1 dove il legacy la rende significativa.

13. Legame con la prenotazione della picking list
La prenotazione backoffice chiama:
sp_xExePackingListPallet
Effetto DB:
- mette Celle.IDStato = 1 sulle celle del documento prenotato
- se richiamata di nuovo, riporta IDStato = 0
- scrive il documento in LogPackingList
Dopo ogni prelievo, sp_xMagGestioneMagazziniPallet richiama:
sp_ControllaPrenotazionePackingListPalletNew
Questa procedura ri-prenota automaticamente le celle residue della picking list attiva.
Quindi:
- F1 continua a scorrere la picking list prenotata residua
- F2 continua a scorrere la coda non prenotata

14. Tempi percepiti dall'operatore
Nel C# non emerge un vero timer di reset a 2 secondi. Il ritardo percepito dal magazziniere e' piu' coerente con:
- tempo di transazione DB
- tempo di riesecuzione della logica server
- tempo di riaggancio alla UDC successiva
Quindi il "reset" percepito e' in realta' la finestra temporale durante cui il terminale attende l'esito e poi aggiorna le label.

15. Allineamento richiesto nel client Python
Da mantenere uguale al C# e alla prassi operativa:
- una sola picking list prenotata per volta
- F1 legge IDStato = 1
- F2 legge IDStato = 0
- proposta UDC ordinata da DB
- movimento tramite la stessa stored legacy sp_xMagGestioneMagazziniPallet
- validazione del pallet atteso prima del prelievo verso 9000000
- visualizzazione di 7G.1.1 come locazione convenzionale di spedito
- visualizzazione di 5E1.1 per le UDC non scaffalate

16. Criticita' di usabilita' della form legacy
- etichette fuorvianti: Cella e Pallet non spiegano cosa va letto in quel momento
- il valore 9000000 compare senza contesto esplicito
- non e' chiaro visivamente se si sta lavorando in F1 o in F2
- la validazione contro il pallet atteso non e' evidente a schermo
- il flusso dipende da reset e colori impliciti, quindi richiede addestramento

17. Specifica proposta per il nuovo client Python barcode
Replica funzionale fedele, ma con UI piu' guidata.
- una sola finestra tkinter pura
- service layer separato dalla UI
- repository layer separato dall'accesso SQL
- focus sempre sul campo scansione corretto
- stato visivo chiaro: F1, F2, versamento, conferma
- messaggi espliciti per l'operatore: cosa leggere adesso
- barra stato grande con colori coerenti al legacy
- gestione esplicita delle locazioni convenzionali 5E1.1 e 7G.1.1

18. Conclusione
Il comportamento C# della form barcode e' abbastanza chiaro: e' piu' coerente di quanto sembri, ma e' esposto con una UI poco autoesplicativa. Il client Python deve quindi mantenere la semantica legacy lato DB e coda operativa, ma renderla finalmente leggibile e stabile per l'operatore.