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));
// 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(() =>
{
OnLoading = false;
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();
});
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
{
if (value is null) return;
if (Scheda.Articoli.Any(x => x.Barcode.Equals(value))) return;
if (ContainsBarcode(value)) return;
await InvokeAsync(() =>
{
@@ -999,6 +1002,11 @@
OnLoading = false;
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)
{
Scheda.Articoli.Insert(0, new SchedaArticolo
@@ -1032,6 +1040,8 @@
private void OnErrorScan(string? value) => OnError(new Exception(value), value);
private bool ContainsBarcode(string barcode) => Scheda.Articoli.Any(x => x.Barcode.Equals(barcode));
#endregion
private void OnError(Exception? e, string? errorMessage)