Fixed search field in payment page and cleaned up payment flow
This commit is contained in:
@@ -1,20 +0,0 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/responses/base.dart';
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
import 'package:pshared/data/dto/payment/payment.dart';
|
||||
|
||||
part 'payment.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class PaymentResponse extends BaseAuthorizedResponse {
|
||||
|
||||
final PaymentDTO payment;
|
||||
|
||||
const PaymentResponse({required super.accessToken, required this.payment});
|
||||
|
||||
factory PaymentResponse.fromJson(Map<String, dynamic> json) => _$PaymentResponseFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$PaymentResponseToJson(this);
|
||||
}
|
||||
@@ -3,11 +3,14 @@ import 'package:flutter/foundation.dart';
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
import 'package:pshared/models/recipient/recipient.dart';
|
||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||
|
||||
|
||||
class PaymentFlowProvider extends ChangeNotifier {
|
||||
PaymentType _selectedType;
|
||||
PaymentMethodData? _manualPaymentData;
|
||||
MethodMap _availableTypes = {};
|
||||
Recipient? _recipient;
|
||||
|
||||
PaymentFlowProvider({
|
||||
required PaymentType initialType,
|
||||
@@ -15,57 +18,40 @@ class PaymentFlowProvider extends ChangeNotifier {
|
||||
|
||||
PaymentType get selectedType => _selectedType;
|
||||
PaymentMethodData? get manualPaymentData => _manualPaymentData;
|
||||
Recipient? get recipient => _recipient;
|
||||
|
||||
void sync({
|
||||
bool get hasRecipient => _recipient != null;
|
||||
|
||||
MethodMap get availableTypes => hasRecipient
|
||||
? _availableTypes
|
||||
: {for (final type in PaymentType.values) type: null};
|
||||
|
||||
PaymentMethodData? get selectedPaymentData =>
|
||||
hasRecipient ? _availableTypes[_selectedType] : _manualPaymentData;
|
||||
|
||||
void syncWith({
|
||||
required Recipient? recipient,
|
||||
required MethodMap availableTypes,
|
||||
required PaymentMethodsProvider methodsProvider,
|
||||
PaymentType? preferredType,
|
||||
}) {
|
||||
final resolvedType = _resolveSelectedType(
|
||||
recipient: recipient,
|
||||
availableTypes: availableTypes,
|
||||
preferredType: preferredType,
|
||||
);
|
||||
|
||||
var hasChanges = false;
|
||||
if (resolvedType != _selectedType) {
|
||||
_selectedType = resolvedType;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (recipient != null && _manualPaymentData != null) {
|
||||
_manualPaymentData = null;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (hasChanges) notifyListeners();
|
||||
}
|
||||
}) =>
|
||||
_applyState(
|
||||
recipient: recipient,
|
||||
availableTypes: methodsProvider.availableTypesForRecipient(recipient),
|
||||
preferredType: preferredType,
|
||||
forceResetManualData: false,
|
||||
);
|
||||
|
||||
void reset({
|
||||
required Recipient? recipient,
|
||||
required MethodMap availableTypes,
|
||||
required PaymentMethodsProvider methodsProvider,
|
||||
PaymentType? preferredType,
|
||||
}) {
|
||||
final resolvedType = _resolveSelectedType(
|
||||
recipient: recipient,
|
||||
availableTypes: availableTypes,
|
||||
preferredType: preferredType,
|
||||
);
|
||||
|
||||
var hasChanges = false;
|
||||
|
||||
if (resolvedType != _selectedType) {
|
||||
_selectedType = resolvedType;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (_manualPaymentData != null) {
|
||||
_manualPaymentData = null;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (hasChanges) notifyListeners();
|
||||
}
|
||||
}) =>
|
||||
_applyState(
|
||||
recipient: recipient,
|
||||
availableTypes: methodsProvider.availableTypesForRecipient(recipient),
|
||||
preferredType: preferredType,
|
||||
forceResetManualData: true,
|
||||
);
|
||||
|
||||
void selectType(PaymentType type, {bool resetManualData = false}) {
|
||||
if (_selectedType == type && (!resetManualData || _manualPaymentData == null)) {
|
||||
@@ -107,4 +93,41 @@ class PaymentFlowProvider extends ChangeNotifier {
|
||||
|
||||
return availableTypes.keys.first;
|
||||
}
|
||||
|
||||
void _applyState({
|
||||
required Recipient? recipient,
|
||||
required MethodMap availableTypes,
|
||||
required PaymentType? preferredType,
|
||||
required bool forceResetManualData,
|
||||
}) {
|
||||
final resolvedType = _resolveSelectedType(
|
||||
recipient: recipient,
|
||||
availableTypes: availableTypes,
|
||||
preferredType: preferredType,
|
||||
);
|
||||
|
||||
var hasChanges = false;
|
||||
|
||||
if (_recipient != recipient) {
|
||||
_recipient = recipient;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (!mapEquals(_availableTypes, availableTypes)) {
|
||||
_availableTypes = availableTypes;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (resolvedType != _selectedType) {
|
||||
_selectedType = resolvedType;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if ((recipient != null || forceResetManualData) && _manualPaymentData != null) {
|
||||
_manualPaymentData = null;
|
||||
hasChanges = true;
|
||||
}
|
||||
|
||||
if (hasChanges) notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'package:pshared/models/payment/payment.dart';
|
||||
import 'package:pshared/provider/organizations.dart';
|
||||
import 'package:pshared/provider/payment/quotation.dart';
|
||||
import 'package:pshared/provider/resource.dart';
|
||||
import 'package:pshared/service/payment/service.dart';
|
||||
|
||||
|
||||
class PaymentProvider extends ChangeNotifier {
|
||||
late OrganizationsProvider _organization;
|
||||
late QuotationProvider _quotation;
|
||||
|
||||
Resource<Payment> _payment = Resource(data: null, isLoading: false, error: null);
|
||||
bool _isLoaded = false;
|
||||
|
||||
void update(OrganizationsProvider organization, QuotationProvider quotation) {
|
||||
_quotation = quotation;
|
||||
_organization = organization;
|
||||
}
|
||||
|
||||
Payment? get payment => _payment.data;
|
||||
bool get isLoading => _payment.isLoading;
|
||||
Exception? get error => _payment.error;
|
||||
bool get isReady => _isLoaded && !_payment.isLoading && _payment.error == null;
|
||||
|
||||
void _setResource(Resource<Payment> payment) {
|
||||
_payment = payment;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<Payment?> pay({String? idempotencyKey, Map<String, String>? metadata}) async {
|
||||
if (!_organization.isOrganizationSet) throw StateError('Organization is not set');
|
||||
if (!_quotation.isReady) throw StateError('Quotation is not ready');
|
||||
final quoteRef = _quotation.quotation?.quoteRef;
|
||||
if (quoteRef == null || quoteRef.isEmpty) {
|
||||
throw StateError('Quotation reference is not set');
|
||||
}
|
||||
|
||||
_setResource(_payment.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
final response = await PaymentService.pay(
|
||||
_organization.current.id,
|
||||
quoteRef,
|
||||
idempotencyKey: idempotencyKey,
|
||||
metadata: metadata,
|
||||
);
|
||||
_isLoaded = true;
|
||||
_setResource(_payment.copyWith(data: response, isLoading: false, error: null));
|
||||
} catch (e) {
|
||||
_setResource(_payment.copyWith(
|
||||
data: null,
|
||||
error: e is Exception ? e : Exception(e.toString()),
|
||||
isLoading: false,
|
||||
));
|
||||
}
|
||||
return _payment.data;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_setResource(Resource(data: null, isLoading: false, error: null));
|
||||
_isLoaded = false;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'package:pshared/api/requests/payment/quote.dart';
|
||||
@@ -20,7 +18,6 @@ import 'package:pshared/provider/organizations.dart';
|
||||
import 'package:pshared/provider/payment/amount.dart';
|
||||
import 'package:pshared/provider/payment/flow.dart';
|
||||
import 'package:pshared/provider/payment/wallets.dart';
|
||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||
import 'package:pshared/provider/resource.dart';
|
||||
import 'package:pshared/service/payment/quotation.dart';
|
||||
import 'package:pshared/utils/currency.dart';
|
||||
@@ -36,12 +33,10 @@ class QuotationProvider extends ChangeNotifier {
|
||||
PaymentAmountProvider payment,
|
||||
WalletsProvider wallets,
|
||||
PaymentFlowProvider flow,
|
||||
PaymentMethodsProvider methods,
|
||||
) {
|
||||
_organizations = venue;
|
||||
final t = flow.selectedType;
|
||||
final method = methods.methods.firstWhereOrNull((m) => m.type == t);
|
||||
if ((wallets.selectedWallet != null) && (method != null)) {
|
||||
final destination = flow.selectedPaymentData;
|
||||
if ((wallets.selectedWallet != null) && (destination != null)) {
|
||||
getQuotation(PaymentIntent(
|
||||
kind: PaymentKind.payout,
|
||||
amount: Money(
|
||||
@@ -49,7 +44,7 @@ class QuotationProvider extends ChangeNotifier {
|
||||
// TODO: adapt to possible other sources
|
||||
currency: currencyCodeToString(wallets.selectedWallet!.currency),
|
||||
),
|
||||
destination: method.data,
|
||||
destination: destination,
|
||||
source: ManagedWalletPaymentMethod(
|
||||
managedWalletRef: wallets.selectedWallet!.id,
|
||||
),
|
||||
|
||||
@@ -5,6 +5,8 @@ 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';
|
||||
@@ -20,6 +22,24 @@ class PaymentMethodsProvider extends GenericProvider<PaymentMethod> {
|
||||
|
||||
List<PaymentMethod> get methods => List<PaymentMethod>.unmodifiable(items.toList()..sort((a, b) => a.storable.createdAt.compareTo(b.storable.createdAt)));
|
||||
|
||||
List<PaymentMethod> 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);
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ class RecipientsProvider extends GenericProvider<Recipient> {
|
||||
|
||||
RecipientFilter _selectedFilter = RecipientFilter.all;
|
||||
String _query = '';
|
||||
String? _previousRecipientRef;
|
||||
|
||||
RecipientFilter get selectedFilter => _selectedFilter;
|
||||
String get query => _query;
|
||||
@@ -22,6 +23,10 @@ class RecipientsProvider extends GenericProvider<Recipient> {
|
||||
|
||||
RecipientsProvider() : super(service: RecipientService.basicService);
|
||||
|
||||
Recipient? get previousRecipient => _previousRecipientRef == null
|
||||
? null
|
||||
: getItemByRef(_previousRecipientRef!);
|
||||
|
||||
List<Recipient> get filteredRecipients {
|
||||
List<Recipient> filtered = recipients.where((r) {
|
||||
switch (_selectedFilter) {
|
||||
@@ -53,6 +58,24 @@ class RecipientsProvider extends GenericProvider<Recipient> {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
@override
|
||||
bool setCurrentObject(String? objectRef) {
|
||||
final currentRef = currentObject?.id;
|
||||
final didUpdate = super.setCurrentObject(objectRef);
|
||||
|
||||
if (didUpdate && currentRef != null && currentRef != objectRef) {
|
||||
_previousRecipientRef = currentRef;
|
||||
}
|
||||
|
||||
return didUpdate;
|
||||
}
|
||||
|
||||
void restorePreviousRecipient() {
|
||||
if (_previousRecipientRef != null) {
|
||||
setCurrentObject(_previousRecipientRef);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Recipient> create({
|
||||
required String name,
|
||||
required String email,
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'package:pshared/api/requests/payment/initiate.dart';
|
||||
import 'package:pshared/api/responses/payment/payment.dart';
|
||||
import 'package:pshared/data/mapper/payment/payment_response.dart';
|
||||
import 'package:pshared/models/payment/payment.dart';
|
||||
import 'package:pshared/service/authorization/service.dart';
|
||||
import 'package:pshared/service/services.dart';
|
||||
|
||||
|
||||
class PaymentService {
|
||||
static final _logger = Logger('service.payment');
|
||||
static const String _objectType = Services.payments;
|
||||
|
||||
static Future<Payment> pay(
|
||||
String organizationRef,
|
||||
String quotationRef, {
|
||||
String? idempotencyKey,
|
||||
Map<String, String>? metadata,
|
||||
}) async {
|
||||
_logger.fine('Executing payment for quotation $quotationRef in $organizationRef');
|
||||
final request = InitiatePaymentRequest(
|
||||
idempotencyKey: idempotencyKey ?? Uuid().v4(),
|
||||
quoteRef: quotationRef,
|
||||
metadata: metadata,
|
||||
);
|
||||
final response = await AuthorizationService.getPOSTResponse(
|
||||
_objectType,
|
||||
'/by-quote/$organizationRef',
|
||||
request.toJson(),
|
||||
);
|
||||
return PaymentResponse.fromJson(response).payment.toDomain();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user