UI-Restructuring: - TabBar in scan_page durch dedizierte Phasen ersetzt: Sortieren / Beladen / Ausliefern - PhaseBloc + PhaseService leiten Phase aus Tour-/Item-States ab - DeliverySelectionPage (ab 2 Autos) und DeliverySortPage als eigene Flows - LoadingOverviewPage / LoadingCustomerPage für die Beladephase - PhaseStepper-Widget im Home für Phasen-Anzeige - Lager-Differenzierung (Standardlager 0 vs. Außenlager) via WarehouseBadge Process-Stubs: - ProcessRepository für Hold/Cancel/Sort/Assign-Flows (stub, bereit für Backend-Anbindung) Doku: - docs/BACKEND_MIGRATION.md: Phasenplan für Umstellung auf das neue Rust-Backend (OpenAPI-Generator, Keycloak OIDC, Clean-Arch-Layering)
718 lines
22 KiB
Dart
718 lines
22 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
import 'package:hl_lieferservice/feature/delivery/bloc/tour_event.dart';
|
|
import 'package:hl_lieferservice/feature/delivery/bloc/tour_state.dart';
|
|
import 'package:hl_lieferservice/feature/delivery/repository/process_repository.dart';
|
|
import 'package:hl_lieferservice/feature/delivery/repository/tour_repository.dart';
|
|
import 'package:hl_lieferservice/feature/delivery/overview/service/distance_service.dart';
|
|
import 'package:hl_lieferservice/feature/delivery/overview/service/reorder_service.dart';
|
|
import 'package:hl_lieferservice/feature/delivery/util.dart';
|
|
import 'package:hl_lieferservice/model/tour.dart';
|
|
import 'package:hl_lieferservice/feature/authentication/bloc/auth_bloc.dart';
|
|
import 'package:hl_lieferservice/feature/authentication/bloc/auth_event.dart';
|
|
import 'package:hl_lieferservice/feature/authentication/exceptions.dart';
|
|
import 'package:hl_lieferservice/widget/operations/bloc/operation_bloc.dart';
|
|
import 'package:hl_lieferservice/widget/operations/bloc/operation_event.dart';
|
|
import 'package:rxdart/rxdart.dart';
|
|
|
|
class TourBloc extends Bloc<TourEvent, TourState> {
|
|
OperationBloc opBloc;
|
|
AuthBloc authBloc;
|
|
TourRepository tourRepository;
|
|
ProcessRepository processRepository;
|
|
StreamSubscription? _combinedSubscription;
|
|
|
|
TourBloc({
|
|
required this.opBloc,
|
|
required this.authBloc,
|
|
required this.tourRepository,
|
|
ProcessRepository? processRepository,
|
|
}) : processRepository = processRepository ?? ProcessRepository(),
|
|
super(TourInitial()) {
|
|
_combinedSubscription = CombineLatestStream.combine2(
|
|
tourRepository.tour,
|
|
tourRepository.paymentOptions,
|
|
(tour, payments) => {'tour': tour, 'payments': payments},
|
|
).listen((combined) {
|
|
final tour = combined['tour'] as Tour?;
|
|
final payments = combined['payments'] as List<Payment>;
|
|
|
|
if (tour == null) {
|
|
return;
|
|
}
|
|
|
|
add(TourUpdated(tour: tour, payments: payments));
|
|
});
|
|
|
|
on<LoadTour>(_load);
|
|
on<AssignCarEvent>(_assignCar);
|
|
on<UnassignDeliveryEvent>(_unassignDelivery);
|
|
on<IncrementArticleScanAmount>(_increment);
|
|
on<ScanArticleEvent>(_scan);
|
|
on<ScanComponentEvent>(_scanComponent);
|
|
on<HoldDeliveryEvent>(_holdDelivery);
|
|
on<CancelDeliveryEvent>(_cancelDelivery);
|
|
on<ReactivateDeliveryEvent>(_reactivateDelivery);
|
|
on<UnscanArticleEvent>(_unscan);
|
|
on<ResetScanAmountEvent>(_resetAmount);
|
|
on<AddDiscountEvent>(_addDiscount);
|
|
on<RemoveDiscountEvent>(_removeDiscount);
|
|
on<UpdateDiscountEvent>(_updateDiscount);
|
|
on<UpdateDeliveryOptionEvent>(_updateDeliveryOptions);
|
|
on<UpdateSelectedPaymentMethodEvent>(_updatePayment);
|
|
on<FinishDeliveryEvent>(_finishDelivery);
|
|
on<TourUpdated>(_updated);
|
|
on<RequestDeliveryDistanceEvent>(_calculateDistances);
|
|
on<RequestSortingInformationEvent>(_requestSortingInformation);
|
|
on<ReorderDeliveryEvent>(_reorderDelivery);
|
|
on<ReplaceSortingEvent>(_replaceSorting);
|
|
on<ConfirmSortingEvent>(_confirmSorting);
|
|
on<EnsureSortingForCarEvent>(_ensureSortingForCar);
|
|
on<CarsLoadedEvent>(_carsLoaded);
|
|
on<SetArticleAmountEvent>(_setArticleAmount);
|
|
}
|
|
|
|
@override
|
|
Future<void> close() {
|
|
_combinedSubscription?.cancel();
|
|
return super.close();
|
|
}
|
|
|
|
void _handleError(Object e, String fallbackMessage) {
|
|
if (e is UserUnauthorized) {
|
|
authBloc.add(SessionExpiredEvent());
|
|
} else {
|
|
opBloc.add(FailOperation(message: fallbackMessage));
|
|
}
|
|
}
|
|
|
|
void _setArticleAmount(
|
|
SetArticleAmountEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.setArticleAmount(
|
|
event.deliveryId,
|
|
event.articleId,
|
|
event.amount,
|
|
event.reason,
|
|
);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Ändern der Menge des Artikels");
|
|
}
|
|
}
|
|
}
|
|
|
|
void _carsLoaded(CarsLoadedEvent event, Emitter<TourState> emit) {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
currentState.tour.driver.cars = event.cars;
|
|
emit(currentState.copyWith());
|
|
}
|
|
}
|
|
|
|
void _reorderDelivery(
|
|
ReorderDeliveryEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
Map<String, List<String>> container = {...currentState.sortingInformation};
|
|
|
|
List<String> reorderedList = reorderList(
|
|
container[event.carId.toString()] ?? [],
|
|
event.oldPosition,
|
|
event.newPosition,
|
|
);
|
|
|
|
container[event.carId.toString()] = reorderedList;
|
|
await ReorderService().saveSortingInformation(container);
|
|
|
|
emit(currentState.copyWith(sortingInformation: container));
|
|
}
|
|
}
|
|
|
|
Future<void> _ensureSortingForCar(
|
|
EnsureSortingForCarEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is! TourLoaded) return;
|
|
|
|
// Ein-Auto-Teams: alle Tour-Lieferungen sind die eigenen — die
|
|
// Zuordnung erfolgt erst beim Scannen.
|
|
// Mehr-Auto-Teams: nach dem Auswahl-Schritt sind die Lieferungen
|
|
// bereits per `assignCar` mit der eigenen carId verknüpft; wir
|
|
// sortieren dann ausschließlich die eigenen.
|
|
final cars = currentState.tour.driver.cars;
|
|
final allTourIds = cars.length >= 2
|
|
? currentState.tour.deliveries
|
|
.where((d) => d.carId?.toString() == event.carId)
|
|
.map((d) => d.id)
|
|
.toList(growable: false)
|
|
: currentState.tour.deliveries
|
|
.map((d) => d.id)
|
|
.toList(growable: false);
|
|
final existing =
|
|
currentState.sortingInformation[event.carId] ?? const <String>[];
|
|
|
|
// Bestehende Reihenfolge beibehalten (nur Einträge, die noch in der Tour
|
|
// sind), dann fehlende Tour-Lieferungen hinten anhängen.
|
|
final allIdsSet = allTourIds.toSet();
|
|
final seen = <String>{};
|
|
final merged = <String>[];
|
|
for (final id in existing) {
|
|
if (allIdsSet.contains(id) && seen.add(id)) merged.add(id);
|
|
}
|
|
for (final id in allTourIds) {
|
|
if (seen.add(id)) merged.add(id);
|
|
}
|
|
|
|
if (merged.length == existing.length &&
|
|
_listEquals(merged, existing.toList())) {
|
|
// Nichts zu tun — Bucket ist bereits konsistent.
|
|
return;
|
|
}
|
|
|
|
final container = {...currentState.sortingInformation};
|
|
container[event.carId] = merged;
|
|
|
|
await ReorderService().saveSortingInformation(container);
|
|
emit(currentState.copyWith(sortingInformation: container));
|
|
}
|
|
|
|
bool _listEquals(List<String> a, List<String> b) {
|
|
if (a.length != b.length) return false;
|
|
for (int i = 0; i < a.length; i++) {
|
|
if (a[i] != b[i]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
Future<void> _replaceSorting(
|
|
ReplaceSortingEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
await ReorderService().saveSortingInformation(
|
|
event.newSortingInformation,
|
|
);
|
|
emit(
|
|
currentState.copyWith(
|
|
sortingInformation: event.newSortingInformation,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<void> _confirmSorting(
|
|
ConfirmSortingEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is! TourLoaded) return;
|
|
|
|
emit(
|
|
currentState.copyWith(
|
|
isPersistingSorting: true,
|
|
clearSortingPersistError: true,
|
|
),
|
|
);
|
|
|
|
final orderedIds =
|
|
currentState.sortingInformation[event.carId] ?? const <String>[];
|
|
|
|
try {
|
|
await processRepository.persistDeliveryOrder(
|
|
carId: event.carId,
|
|
orderedDeliveryIds: orderedIds,
|
|
);
|
|
|
|
// Hinweis: Der eigentliche Phasen-Wechsel auf `beladen` läuft über
|
|
// den [PhaseBloc], angestoßen vom UI-Listener in DeliverySortPage.
|
|
// So bleibt der Phasen-State zentral und der TourBloc unabhängig.
|
|
|
|
// Re-read the latest state — earlier emits or upstream tour updates
|
|
// may have replaced it while the await was in flight.
|
|
final latest = state;
|
|
if (latest is TourLoaded) {
|
|
emit(latest.copyWith(isPersistingSorting: false));
|
|
}
|
|
} catch (e, st) {
|
|
debugPrint("Fehler beim Persistieren der Sortierung: $e $st");
|
|
final latest = state;
|
|
if (latest is TourLoaded) {
|
|
emit(
|
|
latest.copyWith(
|
|
isPersistingSorting: false,
|
|
sortingPersistError:
|
|
"Reihenfolge konnte nicht gespeichert werden. Bitte erneut versuchen.",
|
|
),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _calculateDistances(
|
|
RequestDeliveryDistanceEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
Map<String, double> distances = {};
|
|
|
|
for (final delivery in event.tour.deliveries) {
|
|
try {
|
|
distances[delivery.id] = await DistanceService.getDistanceByRoad(
|
|
delivery.customer.address.toString(),
|
|
);
|
|
} catch (e, st) {
|
|
debugPrint("Fehler beim Laden der Distanz: $e");
|
|
debugPrint("$st");
|
|
distances[delivery.id] = double.nan;
|
|
}
|
|
}
|
|
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
emit(currentState.copyWith(distances: distances));
|
|
}
|
|
}
|
|
|
|
void _requestSortingInformation(
|
|
RequestSortingInformationEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
Map<String, List<String>> container = {};
|
|
|
|
try {
|
|
ReorderService service = ReorderService();
|
|
|
|
// Create empty default value if it does not exist yet
|
|
if (!service.orderInformationExist()) {
|
|
await service.initializeTour(event.tour);
|
|
}
|
|
|
|
// Populate the container with information. If the file did not exist then it
|
|
// now contains the standard values.
|
|
container = await service.loadSortingInformation();
|
|
|
|
bool inconsistent = false;
|
|
for (final delivery in event.tour.deliveries) {
|
|
int info = container[delivery.carId.toString()]!.indexWhere(
|
|
(id) => id == delivery.id,
|
|
);
|
|
|
|
// not found, so add it to the list
|
|
if (info == -1) {
|
|
inconsistent = true;
|
|
container[delivery.carId.toString()]!.add(delivery.id);
|
|
}
|
|
}
|
|
|
|
// if new deliveries were added then save the information with the newly
|
|
// populated container
|
|
if (inconsistent) {
|
|
await service.saveSortingInformation(container);
|
|
}
|
|
} catch (e, st) {
|
|
debugPrint("Fehler beim Lesen der Datei: $e");
|
|
debugPrint("$st");
|
|
|
|
opBloc.add(
|
|
FailOperation(
|
|
message:
|
|
"Fehler beim Laden der Sortierung. Es wird ohne Sortierung fortgefahren",
|
|
),
|
|
);
|
|
|
|
// fill the container without sorting information
|
|
for (final delivery in event.tour.deliveries) {
|
|
container[delivery.carId.toString()]!.add(delivery.id);
|
|
}
|
|
}
|
|
|
|
emit(
|
|
TourLoaded(
|
|
tour: event.tour,
|
|
paymentOptions: event.payments,
|
|
sortingInformation: container,
|
|
),
|
|
);
|
|
|
|
add(RequestDeliveryDistanceEvent(tour: event.tour));
|
|
}
|
|
|
|
void _updated(TourUpdated event, Emitter<TourState> emit) {
|
|
final currentState = state;
|
|
final tour = event.tour.copyWith();
|
|
final payments =
|
|
event.payments.map((payment) => payment.copyWith()).toList();
|
|
|
|
if (currentState is TourLoaded) {
|
|
emit(
|
|
TourLoaded(
|
|
tour: tour,
|
|
paymentOptions: payments,
|
|
distances: Map<String, double>.from(currentState.distances ?? {}),
|
|
sortingInformation: currentState.sortingInformation,
|
|
pendingScanRequests: currentState.pendingScanRequests,
|
|
isPersistingSorting: currentState.isPersistingSorting,
|
|
sortingPersistError: currentState.sortingPersistError,
|
|
),
|
|
);
|
|
}
|
|
|
|
if (currentState is TourLoading) {
|
|
add(
|
|
RequestSortingInformationEvent(tour: tour.copyWith(), payments: payments),
|
|
);
|
|
}
|
|
}
|
|
|
|
void _reactivateDelivery(
|
|
ReactivateDeliveryEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.reactivateDelivery(event.deliveryId);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Zurückstellen der Lieferung");
|
|
}
|
|
}
|
|
}
|
|
|
|
void _holdDelivery(HoldDeliveryEvent event, Emitter<TourState> emit) async {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.holdDelivery(event.deliveryId);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Zurückstellen der Lieferung");
|
|
}
|
|
}
|
|
}
|
|
|
|
void _cancelDelivery(
|
|
CancelDeliveryEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.cancelDelivery(event.deliveryId);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Stornieren der Lieferung");
|
|
}
|
|
}
|
|
}
|
|
|
|
void _bumpPendingScans(Emitter<TourState> emit, int delta) {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
final next = (currentState.pendingScanRequests + delta).clamp(0, 1 << 30);
|
|
emit(currentState.copyWith(pendingScanRequests: next));
|
|
}
|
|
}
|
|
|
|
void _scanComponent(
|
|
ScanComponentEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
|
|
if (currentState is TourLoaded) {
|
|
_bumpPendingScans(emit, 1);
|
|
try {
|
|
switch (await tourRepository.scanComponent(
|
|
event.deliveryId,
|
|
event.carId,
|
|
event.componentArticleNumber,
|
|
)) {
|
|
case ScanResult.scanned:
|
|
opBloc.add(FinishOperation(message: 'Komponente gescannt'));
|
|
break;
|
|
case ScanResult.alreadyScanned:
|
|
opBloc.add(
|
|
FailOperation(message: 'Komponente wurde bereits gescannt'),
|
|
);
|
|
break;
|
|
case ScanResult.notFound:
|
|
opBloc.add(
|
|
FailOperation(
|
|
message: 'Komponente ist für keine Lieferung vorgesehen',
|
|
),
|
|
);
|
|
break;
|
|
}
|
|
} catch (e, st) {
|
|
debugPrint("FEHLER beim Scannen einer Komponente: $e $st");
|
|
_handleError(e, "Fehler beim Scannen der Komponente");
|
|
} finally {
|
|
_bumpPendingScans(emit, -1);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _scan(ScanArticleEvent event, Emitter<TourState> emit) async {
|
|
final currentState = state;
|
|
|
|
if (currentState is TourLoaded) {
|
|
_bumpPendingScans(emit, 1);
|
|
try {
|
|
switch (await tourRepository.scanArticle(
|
|
event.deliveryId,
|
|
event.carId,
|
|
event.articleNumber,
|
|
)) {
|
|
case ScanResult.scanned:
|
|
opBloc.add(FinishOperation(message: 'Artikel gescannt'));
|
|
break;
|
|
case ScanResult.alreadyScanned:
|
|
opBloc.add(
|
|
FailOperation(message: 'Artikel wurde bereits gescannt'),
|
|
);
|
|
break;
|
|
case ScanResult.notFound:
|
|
opBloc.add(
|
|
FailOperation(
|
|
message: 'Artikel ist für keine Lieferung vorgesehen',
|
|
),
|
|
);
|
|
break;
|
|
}
|
|
} catch (e, st) {
|
|
debugPrint("FEHLER beim Scannen eines Artikels: $e $st");
|
|
_handleError(e, "Fehler beim Scannen des Artikels");
|
|
} finally {
|
|
_bumpPendingScans(emit, -1);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _increment(
|
|
IncrementArticleScanAmount event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
|
|
if (currentState is TourLoaded) {
|
|
_bumpPendingScans(emit, 1);
|
|
try {
|
|
await tourRepository.scanArticle(
|
|
event.deliveryId,
|
|
event.carId,
|
|
event.internalArticleId,
|
|
);
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Scannen des Artikels");
|
|
} finally {
|
|
_bumpPendingScans(emit, -1);
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _assignCar(AssignCarEvent event, Emitter<TourState> emit) async {
|
|
final currentState = state;
|
|
if (currentState is TourLoaded) {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.assignCar(event.deliveryId, event.carId);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Zuweisen des Fahrzeugs");
|
|
}
|
|
}
|
|
}
|
|
|
|
Future<void> _unassignDelivery(
|
|
UnassignDeliveryEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
if (currentState is! TourLoaded) return;
|
|
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
// Stub-Aufruf — solange kein echter Endpoint existiert, gibt es
|
|
// hier kein Tour-Update; das lokale Modell behält den alten carId-
|
|
// Wert. Mit dem echten Endpoint wird die Tour anschließend über
|
|
// den tourRepository-Stream aktualisiert (analog zu assignCar).
|
|
await processRepository.unassignDeliveryFromCar(
|
|
deliveryId: event.deliveryId,
|
|
);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Freigeben der Lieferung");
|
|
}
|
|
}
|
|
|
|
Future<void> _load(LoadTour event, Emitter<TourState> emit) async {
|
|
try {
|
|
emit(TourLoading());
|
|
await tourRepository.loadTourOfToday(event.teamId);
|
|
await tourRepository.loadPaymentOptions();
|
|
} catch (e) {
|
|
if (e is UserUnauthorized) {
|
|
authBloc.add(SessionExpiredEvent());
|
|
return;
|
|
}
|
|
emit(TourLoadingFailed());
|
|
opBloc.add(FailOperation(message: "Fehler beim Laden der heutigen Fahrten"));
|
|
}
|
|
}
|
|
|
|
void _finishDelivery(
|
|
FinishDeliveryEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
final currentState = state;
|
|
|
|
if (currentState is TourLoaded) {
|
|
opBloc.add(StartOperation(message: "Lieferung wird abgeschlossen…"));
|
|
try {
|
|
await tourRepository.uploadDriverSignature(
|
|
event.deliveryId,
|
|
event.driverSignature,
|
|
);
|
|
await tourRepository.uploadCustomerSignature(
|
|
event.deliveryId,
|
|
event.customerSignature,
|
|
);
|
|
|
|
await tourRepository.finishDelivery(event.deliveryId);
|
|
opBloc.add(FinishOperation(message: "Lieferung abgeschlossen"));
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Abschließen der Lieferung");
|
|
}
|
|
}
|
|
}
|
|
|
|
void _updatePayment(
|
|
UpdateSelectedPaymentMethodEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.updatePayment(event.deliveryId, event.payment);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Aktualisieren des Betrags");
|
|
}
|
|
}
|
|
|
|
void _updateDeliveryOptions(
|
|
UpdateDeliveryOptionEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.updateOption(
|
|
event.deliveryId,
|
|
event.key,
|
|
event.value,
|
|
);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("$e $st");
|
|
_handleError(e, "Fehler beim Aktualisieren der Optionen");
|
|
}
|
|
}
|
|
|
|
void _updateDiscount(
|
|
UpdateDiscountEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.updateDiscount(
|
|
event.deliveryId,
|
|
event.reason,
|
|
event.value,
|
|
);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("Fehler beim Aktualisieren des Discounts: $e $st");
|
|
_handleError(e, "Fehler beim Aktualisieren des Discounts");
|
|
}
|
|
}
|
|
|
|
void _removeDiscount(
|
|
RemoveDiscountEvent event,
|
|
Emitter<TourState> emit,
|
|
) async {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.removeDiscount(event.deliveryId);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("Fehler beim Löschen des Discounts: $e $st");
|
|
_handleError(e, "Fehler beim Löschen des Discounts");
|
|
}
|
|
}
|
|
|
|
void _addDiscount(AddDiscountEvent event, Emitter<TourState> emit) async {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.addDiscount(
|
|
event.deliveryId,
|
|
event.reason,
|
|
event.value,
|
|
);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("Fehler beim Hinzufügen des Discounts: $e $st");
|
|
_handleError(e, "Fehler beim Hinzufügen des Discounts");
|
|
}
|
|
}
|
|
|
|
void _unscan(UnscanArticleEvent event, Emitter<TourState> emit) async {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.unscan(
|
|
event.deliveryId,
|
|
event.articleId,
|
|
event.newAmount,
|
|
event.reason,
|
|
);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("Fehler beim Unscan des Artikels ${event.articleId}: $e $st");
|
|
_handleError(e, "Fehler beim Unscan des Artikels");
|
|
}
|
|
}
|
|
|
|
void _resetAmount(ResetScanAmountEvent event, Emitter<TourState> emit) async {
|
|
opBloc.add(StartOperation());
|
|
try {
|
|
await tourRepository.resetScan(event.articleId, event.deliveryId);
|
|
opBloc.add(FinishOperation());
|
|
} catch (e, st) {
|
|
debugPrint("Fehler beim Zurücksetzen Artikel ${event.articleId}: $e $st");
|
|
_handleError(e, "Fehler beim Zurücksetzen");
|
|
}
|
|
}
|
|
}
|