import 'dart:typed_data'; import 'package:hl_lieferservice/dto/set_article_amount_response.dart'; import 'package:hl_lieferservice/feature/delivery/service/tour_service.dart'; import 'package:hl_lieferservice/model/delivery.dart'; import 'package:hl_lieferservice/model/tour.dart'; import 'package:rxdart/rxdart.dart'; import '../../../../dto/discount_add_response.dart'; import '../../../../dto/discount_remove_response.dart'; import '../../../../dto/discount_update_response.dart'; import '../../../../model/article.dart'; import '../detail/repository/note_repository.dart'; import '../detail/service/notes_service.dart'; enum ScanResult { scanned, alreadyScanned, notFound } class TourNotFoundException implements Exception {} class TourRepository { TourService service; final _tourStream = BehaviorSubject(); final _paymentOptionsStream = BehaviorSubject>.seeded([]); Stream get tour => _tourStream.stream; Stream> get paymentOptions => _paymentOptionsStream.stream; TourRepository({required this.service}); Future loadTourOfToday(String userId) async { _tourStream.add(await service.getTourOfToday(userId)); } Future loadPaymentOptions() async { _paymentOptionsStream.add( (await service.getPaymentMethods()) .map((option) => Payment.fromDTO(option)) .toList(), ); } Future assignCar(String deliveryId, String carId) async { await service.assignCar(deliveryId, carId); final tour = _tourStream.value!; final index = tour.deliveries.indexWhere( (delivery) => delivery.id == deliveryId, ); tour.deliveries[index].carId = int.parse(carId); _tourStream.add(tour); } Future scanArticle( String deliveryId, String carId, String articleNumber, ) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } final tour = _tourStream.value!; if (tour.deliveries.any( (delivery) => delivery.articles.any( (article) => article.articleNumber == articleNumber, ), )) { var delivery = tour.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); var article = delivery.articles.firstWhere( (article) => article.articleNumber == articleNumber, ); await service.scanArticle(article.internalId.toString()); if (article.scannedAmount < article.amount) { article.scannedAmount += 1; _tourStream.add(tour); return ScanResult.scanned; } else { return ScanResult.alreadyScanned; } } else { return ScanResult.notFound; } } Future unscan( String deliveryId, String articleId, int newAmount, String reason, ) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } Tour tour = _tourStream.value!; String? noteId = await service.unscanArticle(articleId, newAmount, reason); Article article = tour.deliveries .firstWhere((delivery) => delivery.id == deliveryId) .articles .firstWhere((article) => article.internalId == int.parse(articleId)); article.removeNoteId = noteId; article.scannedRemovedAmount += newAmount; article.scannedAmount -= newAmount; _tourStream.add(tour); } Future resetScan(String articleId, String deliveryId) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } Tour tour = _tourStream.value!; await service.resetScannedArticleAmount(articleId); Article article = tour.deliveries .firstWhere((delivery) => delivery.id == deliveryId) .articles .firstWhere((article) => article.internalId == int.parse(articleId)); article.removeNoteId = null; article.scannedRemovedAmount = 0; article.scannedAmount = article.amount; _tourStream.add(tour); } Future uploadDriverSignature( String deliveryId, Uint8List signature, ) async { NoteRepository noteRepository = NoteRepository(service: NoteService()); await noteRepository.addNamedImage( deliveryId, signature, "delivery_${deliveryId}_signature_driver.jpg", ); } Future uploadCustomerSignature( String deliveryId, Uint8List signature, ) async { NoteRepository noteRepository = NoteRepository(service: NoteService()); await noteRepository.addNamedImage( deliveryId, signature, "delivery_${deliveryId}_signature_customer.jpg", ); } Future addDiscount(String deliveryId, String reason, int value) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } Tour tour = _tourStream.value!; DiscountAddResponseDTO response = await service.addDiscount( deliveryId, value, reason, ); Delivery delivery = tour.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); Article discountArticle = Article.fromDTO(response.values.article); delivery.totalNetValue = response.values.receipt.net; delivery.totalGrossValue = response.values.receipt.gross; delivery.discount = Discount( article: Article.fromDTO(response.values.article), note: response.values.note.noteDescription, noteId: response.values.note.rowId, ); delivery.articles = [ ...delivery.articles, discountArticle, ]; _tourStream.add(tour); } Future removeDiscount(String deliveryId) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } Tour tour = _tourStream.value!; DiscountRemoveResponseDTO response = await service.removeDiscount( deliveryId, ); Delivery delivery = tour.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); delivery.articles = delivery.articles .where( (article) => article.internalId != delivery.discount?.article.internalId, ) .toList(); delivery.discount = null; delivery.totalGrossValue = response.receipt.gross; delivery.totalNetValue = response.receipt.net; _tourStream.add(tour); } Future updateDiscount( String deliveryId, String? reason, int? value, ) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } Tour tour = _tourStream.value!; DiscountUpdateResponseDTO response = await service.updateDiscount( deliveryId, reason, value, ); Delivery delivery = tour.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); if (response.values?.receipt != null) { delivery.totalNetValue = response.values!.receipt.net; delivery.totalGrossValue = response.values!.receipt.gross; } String discountArticleNumber = delivery.discount!.article.articleNumber; delivery.discount = Discount( article: response.values?.article != null ? Article.fromDTO(response.values!.article) : delivery.discount!.article, note: response.values?.note != null ? response.values!.note.noteDescription : delivery.discount!.note, noteId: response.values?.note != null ? response.values!.note.rowId : delivery.discount!.noteId, ); delivery.articles = [ ...delivery.articles.where( (article) => article.articleNumber != discountArticleNumber, ), delivery.discount!.article, ]; _tourStream.add(tour); } Future reactivateDelivery(String deliveryId) async { await _changeState(deliveryId, DeliveryState.ongoing); } Future holdDelivery(String deliveryId) async { await _changeState(deliveryId, DeliveryState.onhold); } Future cancelDelivery(String deliveryId) async { await _changeState(deliveryId, DeliveryState.canceled); } Future finishDelivery(String deliveryId) async { await _changeState(deliveryId, DeliveryState.finished); Delivery delivery = _tourStream.value!.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); await _updateDelivery(delivery); await service.finishDelivery(deliveryId); } Future setArticleAmount( String deliveryId, String articleId, int amount, String? reason, ) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } try { SetArticleAmountResponseDTO dto = await service.setArticleAmount( deliveryId, articleId, amount, reason, ); Delivery delivery = _tourStream.value!.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); Article article = delivery.articles.firstWhere( (article) => article.internalId == int.parse(articleId), ); article.amount = amount; article.removeNoteId = dto.noteId; _tourStream.add(_tourStream.value); } catch (_) { rethrow; } } Future _changeState(String deliveryId, DeliveryState state) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } Tour tour = _tourStream.value!; Delivery delivery = tour.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); delivery.state = state; await _updateDelivery(delivery); _tourStream.add(tour); } Future _updateDelivery(Delivery newDelivery) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } await service.updateDelivery(newDelivery); } Future updatePayment(String deliveryId, Payment payment) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } Tour tour = _tourStream.value!; Delivery delivery = tour.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); delivery.payment = payment; await _updateDelivery(delivery); _tourStream.add(tour); } Future updateOption( String deliveryId, String key, dynamic value, ) async { if (!_tourStream.hasValue) { throw TourNotFoundException(); } Tour tour = _tourStream.value!; Delivery delivery = tour.deliveries.firstWhere( (delivery) => delivery.id == deliveryId, ); delivery.options = delivery.options.map((option) { if (option.key == key) { if (option.numerical) { return option.copyWith(value: value); } else { return option.copyWith(value: value == true ? "1" : "0"); } } return option; }).toList(); await _updateDelivery(delivery); _tourStream.add(tour); } }