Evita articoli persi o doppi con griglia e scanner insieme

Nella scheda, scegliendo alcuni articoli dalla griglia e sparandone altri,
non tutti i barcode arrivavano al salvataggio.

- La selezione dalla griglia modificava Scheda.Articoli da un thread del
  pool, mentre le scansioni lo fanno sul thread della UI: le due modifiche
  potevano sovrapporsi e far perdere articoli. Ora passa da InvokeAsync.
- La griglia non scartava i barcode gia' sparati, e lo scanner controllava
  solo il codice letto, non quello restituito dal server (che puo' essere
  il barcode principale, lo stesso della griglia). Un doppione rompe il
  @key della lista e il salvataggio locale (indice unico SchedaId+Barcode).
  Ora entrambi i percorsi aggiungono solo barcode non ancora presenti.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MarcoEandClaude Opus 5.5 committed 2026-10-29 15:40:20 +01:00
1 parent ed7c28feac
commit 495f335b72
1 file changed
+27 -17
@@ -896,29 +896,32 @@
var modal = await WithChildDialog(() => Dialog.OpenSelectArt(articoli)); var modal = await WithChildDialog(() => Dialog.OpenSelectArt(articoli));
// Gli articoli si aggiungono sul thread della UI, come fanno le scansioni:
// toccare Scheda.Articoli da qui mentre arriva una lettura (o mentre la
// lista viene disegnata) puo' far perdere articoli.
await InvokeAsync(() => await InvokeAsync(() =>
{ {
OnLoading = false; OnLoading = false;
TextLoading = null; TextLoading = null;
if (modal is { Canceled: false, Data: List<ArticoliInGrigliaDto> articoliSelezionati })
{
// Quelli gia' sparati non si aggiungono di nuovo.
Scheda.Articoli.InsertRange(0, articoliSelezionati
.DistinctBy(x => x.Barcode)
.Where(x => !ContainsBarcode(x.Barcode))
.Select(x => new SchedaArticolo
{
Barcode = x.Barcode,
Descrizione = x.Descrizione
})
);
RecalcDirty();
}
StateHasChanged(); StateHasChanged();
}); });
if (modal is { Canceled: false, Data: List<ArticoliInGrigliaDto> articoliSelezionati })
{
Scheda.Articoli.InsertRange(0, articoliSelezionati.ConvertAll(x => new SchedaArticolo
{
Barcode = x.Barcode,
Descrizione = x.Descrizione
})
);
await InvokeAsync(() =>
{
RecalcDirty();
StateHasChanged();
});
}
}); });
} }
@@ -984,7 +987,7 @@
try try
{ {
if (value is null) return; if (value is null) return;
if (Scheda.Articoli.Any(x => x.Barcode.Equals(value))) return; if (ContainsBarcode(value)) return;
await InvokeAsync(() => await InvokeAsync(() =>
{ {
@@ -999,6 +1002,11 @@
OnLoading = false; OnLoading = false;
StateHasChanged(); StateHasChanged();
// Il controllo va ripetuto sul barcode restituito: il server puo' rispondere
// con un barcode diverso da quello letto (lo stesso gia' scelto dalla griglia),
// e due letture ravvicinate superano entrambe il controllo iniziale.
if (art != null && ContainsBarcode(art.Barcode)) return;
if (art != null) if (art != null)
{ {
Scheda.Articoli.Insert(0, new SchedaArticolo Scheda.Articoli.Insert(0, new SchedaArticolo
@@ -1032,6 +1040,8 @@
private void OnErrorScan(string? value) => OnError(new Exception(value), value); private void OnErrorScan(string? value) => OnError(new Exception(value), value);
private bool ContainsBarcode(string barcode) => Scheda.Articoli.Any(x => x.Barcode.Equals(barcode));
#endregion #endregion
private void OnError(Exception? e, string? errorMessage) private void OnError(Exception? e, string? errorMessage)