cancellationItemsForTip function

List<CancellationItem>? cancellationItemsForTip(
  1. KasseneckReceipt receipt,
  2. List<CancellationItem>? items, {
  3. required bool refundTip,
  4. int? nowMs,
})

Die Positionen, die nach der Antwort auf „Trinkgeld auch zurueckgeben?" hinausgehen – dieselbe Regel wie im Backend. items null = ganzer Beleg. Ja: zum Teilstorno kommt das offene Trinkgeld dazu, der ganze Beleg bleibt null. Nein: ohne das Mitarbeiter-Trinkgeld; der ganze Beleg wird zur Liste aller Restmengen ausser dem Trinkgeld (leer = nichts mehr zu stornieren). Ist kein Mitarbeiter-Trinkgeld mehr offen (keines oder schon storniert), bleibt der Wunsch, wie er ist – „Nein" wirkt dann wie keine Wahl (R61).

Implementation

List<CancellationItem>? cancellationItemsForTip(
  KasseneckReceipt receipt,
  List<CancellationItem>? items, {
  required bool refundTip,
  int? nowMs,
}) {
  final trinkgeld = {for (final (i, item) in receipt.items.indexed) if (_mitarbeiterTrinkgeld(item)) i};
  if (trinkgeld.isEmpty) return items == null ? null : [...items];
  if (refundTip) {
    if (items == null) return null;
    final genannt = {for (final p in items) p.index};
    return [...items, ..._offenesTrinkgeld(receipt, nowMs).where((p) => !genannt.contains(p.index))];
  }
  if (items != null) return [for (final p in items) if (!trinkgeld.contains(p.index)) p];
  if (_offenesTrinkgeld(receipt, nowMs).isEmpty) return null;
  final rest = remainingQuantities(receipt, nowMs: nowMs);
  return [
    for (final (i, menge) in rest.indexed)
      if (menge > 0 && !trinkgeld.contains(i)) (index: i, quantity: menge),
  ];
}