import 'package:collection/collection.dart'; import 'package:pshared/data/mapper/payment/method.dart'; import 'package:pshared/models/describable.dart'; import 'package:pshared/models/organization/bound.dart'; import 'package:pshared/models/payment/methods/data.dart'; import 'package:pshared/models/payment/methods/type.dart'; import 'package:pshared/models/payment/type.dart'; import 'package:pshared/models/recipient/recipient.dart'; import 'package:pshared/models/permissions/bound.dart'; import 'package:pshared/models/storable.dart'; import 'package:pshared/provider/organizations.dart'; import 'package:pshared/provider/recipient/provider.dart'; import 'package:pshared/provider/template.dart'; import 'package:pshared/service/recipient/pmethods.dart'; class PaymentMethodsProvider extends GenericProvider { late OrganizationsProvider _organizations; PaymentMethodsProvider() : super(service: PaymentMethodService.basicService); List get methods => List.unmodifiable(items.toList()..sort((a, b) => a.storable.createdAt.compareTo(b.storable.createdAt))); List methodsForRecipient(Recipient? recipient) { if (recipient == null || !isReady) return []; return methods .where((method) => !method.isArchived && method.recipientRef == recipient.id) .toList(); } MethodMap availableTypesForRecipient(Recipient? recipient) => { for (final method in methodsForRecipient(recipient)) method.type: method.data, }; PaymentMethod? findMethodByType({ required PaymentType type, required Recipient? recipient, }) => methodsForRecipient(recipient).firstWhereOrNull((method) => method.type == type); void updateProviders(OrganizationsProvider organizations, RecipientsProvider recipients) { if (recipients.currentObject != null) loadMethods(organizations, recipients.currentObject?.id); } // TODO: current providers structure forces to use weird construction with in-place PaymentMethodsProviders // it would be better to load reipients together with their payment methods in RecipientsProvider Future loadMethods(OrganizationsProvider organizations, String? recipientRef) async { _organizations = organizations; if (_organizations.isOrganizationSet && (recipientRef != null)) { return load(_organizations.current.id, recipientRef); } } // void reorderMethods(int oldIndex, int newIndex) { // if (newIndex > oldIndex) newIndex--; // final item = _methods.removeAt(oldIndex); // _methods.insert(newIndex, item); // notifyListeners(); // } PaymentMethod? get main => methods.firstWhereOrNull((m) => m.isMain); Future updateMethod(PaymentMethod method) async => update(method.toDTO().toJson()); Future setArchivedMethod({ required PaymentMethod method, required bool newIsArchived, }) async => setArchived( organizationRef: _organizations.current.id, objectRef: method.id, newIsArchived: newIsArchived, cascade: true, ); Future create({ required String reacipientRef, required PaymentMethodData data, required String name, }) => createObject( _organizations.current.id, PaymentMethod( storable: newStorable(), permissionBound: newPermissionBound( organizationBound: newOrganizationBound(organizationRef: _organizations.current.id), ), recipientRef: reacipientRef, data: data, describable: newDescribable(name: name), ).toDTO().toJson(), ); Future makeMain(PaymentMethod method) { // TODO: create separate backend method to manage main payment method final updates = >[]; final currentMain = main; if (currentMain != null) { updates.add(updateMethod(currentMain.copyWith(isMain: false))); } updates.add(updateMethod(method.copyWith(isMain: true))); return Future.wait(updates).then((_) => null); } }