+ quotation provider
This commit is contained in:
20
frontend/pshared/lib/api/requests/payment/base.dart
Normal file
20
frontend/pshared/lib/api/requests/payment/base.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
|
||||
part 'base.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PaymentBaseRequest {
|
||||
final String idempotencyKey;
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
const PaymentBaseRequest({
|
||||
required this.idempotencyKey,
|
||||
this.metadata,
|
||||
});
|
||||
|
||||
factory PaymentBaseRequest.fromJson(Map<String, dynamic> json) => _$PaymentBaseRequestFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PaymentBaseRequestToJson(this);
|
||||
|
||||
}
|
||||
24
frontend/pshared/lib/api/requests/payment/initiate.dart
Normal file
24
frontend/pshared/lib/api/requests/payment/initiate.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/api/requests/payment/base.dart';
|
||||
import 'package:pshared/data/dto/payment/intent/payment.dart';
|
||||
|
||||
part 'initiate.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class InitiatePaymentRequest extends PaymentBaseRequest {
|
||||
final PaymentIntentDTO? intent;
|
||||
final String? quoteRef;
|
||||
|
||||
const InitiatePaymentRequest({
|
||||
required super.idempotencyKey,
|
||||
super.metadata,
|
||||
this.intent,
|
||||
this.quoteRef,
|
||||
});
|
||||
|
||||
factory InitiatePaymentRequest.fromJson(Map<String, dynamic> json) => _$InitiatePaymentRequestFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$InitiatePaymentRequestToJson(this);
|
||||
}
|
||||
26
frontend/pshared/lib/api/requests/payment/quote.dart
Normal file
26
frontend/pshared/lib/api/requests/payment/quote.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
import 'package:pshared/api/requests/payment/base.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/intent/payment.dart';
|
||||
|
||||
part 'quote.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class QuotePaymentRequest extends PaymentBaseRequest {
|
||||
final PaymentIntentDTO intent;
|
||||
|
||||
@JsonKey(defaultValue: false)
|
||||
final bool previewOnly;
|
||||
|
||||
const QuotePaymentRequest({
|
||||
required super.idempotencyKey,
|
||||
super.metadata,
|
||||
required this.intent,
|
||||
this.previewOnly = false,
|
||||
});
|
||||
|
||||
factory QuotePaymentRequest.fromJson(Map<String, dynamic> json) => _$QuotePaymentRequestFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$QuotePaymentRequestToJson(this);
|
||||
}
|
||||
20
frontend/pshared/lib/api/responses/payment/quotation.dart
Normal file
20
frontend/pshared/lib/api/responses/payment/quotation.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
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_quote.dart';
|
||||
|
||||
part 'quotation.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable(explicitToJson: true)
|
||||
class PaymentQuoteResponse extends BaseAuthorizedResponse {
|
||||
|
||||
final PaymentQuoteDTO quote;
|
||||
|
||||
const PaymentQuoteResponse({required super.accessToken, required this.quote});
|
||||
|
||||
factory PaymentQuoteResponse.fromJson(Map<String, dynamic> json) => _$PaymentQuoteResponseFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$PaymentQuoteResponseToJson(this);
|
||||
}
|
||||
24
frontend/pshared/lib/data/dto/payment/asset.dart
Normal file
24
frontend/pshared/lib/data/dto/payment/asset.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'asset.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class AssetDTO {
|
||||
final String chain;
|
||||
|
||||
@JsonKey(name: 'token_symbol')
|
||||
final String tokenSymbol;
|
||||
|
||||
@JsonKey(name: 'contract_address')
|
||||
final String? contractAddress;
|
||||
|
||||
const AssetDTO({
|
||||
required this.chain,
|
||||
required this.tokenSymbol,
|
||||
this.contractAddress,
|
||||
});
|
||||
|
||||
factory AssetDTO.fromJson(Map<String, dynamic> json) => _$AssetDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$AssetDTOToJson(this);
|
||||
}
|
||||
@@ -4,17 +4,28 @@ part 'card.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class CardPaymentDataDTO {
|
||||
class CardEndpointDTO {
|
||||
final String pan;
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
|
||||
const CardPaymentDataDTO({
|
||||
@JsonKey(name: 'exp_month')
|
||||
final int? expMonth;
|
||||
|
||||
@JsonKey(name: 'exp_year')
|
||||
final int? expYear;
|
||||
|
||||
final String? country;
|
||||
|
||||
const CardEndpointDTO({
|
||||
required this.pan,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
required this.expMonth,
|
||||
required this.expYear,
|
||||
this.country,
|
||||
});
|
||||
|
||||
factory CardPaymentDataDTO.fromJson(Map<String, dynamic> json) => _$CardPaymentDataDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$CardPaymentDataDTOToJson(this);
|
||||
factory CardEndpointDTO.fromJson(Map<String, dynamic> json) => _$CardEndpointDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$CardEndpointDTOToJson(this);
|
||||
}
|
||||
|
||||
20
frontend/pshared/lib/data/dto/payment/card_token.dart
Normal file
20
frontend/pshared/lib/data/dto/payment/card_token.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'card_token.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class CardTokenEndpointDTO {
|
||||
final String token;
|
||||
|
||||
@JsonKey(name: 'masked_pan')
|
||||
final String maskedPan;
|
||||
|
||||
const CardTokenEndpointDTO({
|
||||
required this.maskedPan,
|
||||
required this.token,
|
||||
});
|
||||
|
||||
factory CardTokenEndpointDTO.fromJson(Map<String, dynamic> json) => _$CardTokenEndpointDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$CardTokenEndpointDTOToJson(this);
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'crypto_address.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class CryptoAddressPaymentDataDTO {
|
||||
final String address;
|
||||
final String network;
|
||||
final String? destinationTag;
|
||||
|
||||
const CryptoAddressPaymentDataDTO({
|
||||
required this.address,
|
||||
required this.network,
|
||||
this.destinationTag,
|
||||
});
|
||||
|
||||
factory CryptoAddressPaymentDataDTO.fromJson(Map<String, dynamic> json) => _$CryptoAddressPaymentDataDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$CryptoAddressPaymentDataDTOToJson(this);
|
||||
}
|
||||
18
frontend/pshared/lib/data/dto/payment/currency_pair.dart
Normal file
18
frontend/pshared/lib/data/dto/payment/currency_pair.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'currency_pair.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class CurrencyPairDTO {
|
||||
final String base;
|
||||
final String quote;
|
||||
|
||||
const CurrencyPairDTO({
|
||||
required this.base,
|
||||
required this.quote,
|
||||
});
|
||||
|
||||
factory CurrencyPairDTO.fromJson(Map<String, dynamic> json) => _$CurrencyPairDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$CurrencyPairDTOToJson(this);
|
||||
}
|
||||
20
frontend/pshared/lib/data/dto/payment/endpoint.dart
Normal file
20
frontend/pshared/lib/data/dto/payment/endpoint.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'endpoint.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PaymentEndpointDTO {
|
||||
final String type;
|
||||
final Map<String, dynamic> data;
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
const PaymentEndpointDTO({
|
||||
required this.type,
|
||||
required this.data,
|
||||
this.metadata,
|
||||
});
|
||||
|
||||
factory PaymentEndpointDTO.fromJson(Map<String, dynamic> json) => _$PaymentEndpointDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PaymentEndpointDTOToJson(this);
|
||||
}
|
||||
22
frontend/pshared/lib/data/dto/payment/external_chain.dart
Normal file
22
frontend/pshared/lib/data/dto/payment/external_chain.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/asset.dart';
|
||||
|
||||
part 'external_chain.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class ExternalChainEndpointDTO {
|
||||
final AssetDTO? asset;
|
||||
final String address;
|
||||
final String? memo;
|
||||
|
||||
const ExternalChainEndpointDTO({
|
||||
this.asset,
|
||||
required this.address,
|
||||
this.memo,
|
||||
});
|
||||
|
||||
factory ExternalChainEndpointDTO.fromJson(Map<String, dynamic> json) => _$ExternalChainEndpointDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ExternalChainEndpointDTOToJson(this);
|
||||
}
|
||||
26
frontend/pshared/lib/data/dto/payment/fee_line.dart
Normal file
26
frontend/pshared/lib/data/dto/payment/fee_line.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/money.dart';
|
||||
|
||||
part 'fee_line.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class FeeLineDTO {
|
||||
final String? ledgerAccountRef;
|
||||
final MoneyDTO? amount;
|
||||
final String? lineType;
|
||||
final String? side;
|
||||
final Map<String, String>? meta;
|
||||
|
||||
const FeeLineDTO({
|
||||
this.ledgerAccountRef,
|
||||
this.amount,
|
||||
this.lineType,
|
||||
this.side,
|
||||
this.meta,
|
||||
});
|
||||
|
||||
factory FeeLineDTO.fromJson(Map<String, dynamic> json) => _$FeeLineDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$FeeLineDTOToJson(this);
|
||||
}
|
||||
40
frontend/pshared/lib/data/dto/payment/fx_quote.dart
Normal file
40
frontend/pshared/lib/data/dto/payment/fx_quote.dart
Normal file
@@ -0,0 +1,40 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/money.dart';
|
||||
|
||||
part 'fx_quote.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class FxQuoteDTO {
|
||||
final String? quoteRef;
|
||||
final String? baseCurrency;
|
||||
final String? quoteCurrency;
|
||||
final String? side;
|
||||
final String? price;
|
||||
final MoneyDTO? baseAmount;
|
||||
final MoneyDTO? quoteAmount;
|
||||
final int? expiresAtUnixMs;
|
||||
final String? provider;
|
||||
final String? rateRef;
|
||||
|
||||
@JsonKey(defaultValue: false)
|
||||
final bool? firm;
|
||||
|
||||
const FxQuoteDTO({
|
||||
this.quoteRef,
|
||||
this.baseCurrency,
|
||||
this.quoteCurrency,
|
||||
this.side,
|
||||
this.price,
|
||||
this.baseAmount,
|
||||
this.quoteAmount,
|
||||
this.expiresAtUnixMs,
|
||||
this.provider,
|
||||
this.rateRef,
|
||||
this.firm = false,
|
||||
});
|
||||
|
||||
factory FxQuoteDTO.fromJson(Map<String, dynamic> json) => _$FxQuoteDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$FxQuoteDTOToJson(this);
|
||||
}
|
||||
34
frontend/pshared/lib/data/dto/payment/intent/fx.dart
Normal file
34
frontend/pshared/lib/data/dto/payment/intent/fx.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/currency_pair.dart';
|
||||
|
||||
part 'fx.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class FxIntentDTO {
|
||||
final CurrencyPairDTO? pair;
|
||||
final String? side;
|
||||
final bool firm;
|
||||
|
||||
@JsonKey(name: 'ttl_ms')
|
||||
final int? ttlMs;
|
||||
|
||||
@JsonKey(name: 'preferred_provider')
|
||||
final String? preferredProvider;
|
||||
|
||||
@JsonKey(name: 'max_age_ms')
|
||||
final int? maxAgeMs;
|
||||
|
||||
const FxIntentDTO({
|
||||
this.pair,
|
||||
this.side,
|
||||
this.firm = false,
|
||||
this.ttlMs,
|
||||
this.preferredProvider,
|
||||
this.maxAgeMs,
|
||||
});
|
||||
|
||||
factory FxIntentDTO.fromJson(Map<String, dynamic> json) => _$FxIntentDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$FxIntentDTOToJson(this);
|
||||
}
|
||||
36
frontend/pshared/lib/data/dto/payment/intent/payment.dart
Normal file
36
frontend/pshared/lib/data/dto/payment/intent/payment.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/endpoint.dart';
|
||||
import 'package:pshared/data/dto/payment/intent/fx.dart';
|
||||
import 'package:pshared/data/dto/payment/money.dart';
|
||||
|
||||
part 'payment.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PaymentIntentDTO {
|
||||
final String? kind;
|
||||
final PaymentEndpointDTO? source;
|
||||
final PaymentEndpointDTO? destination;
|
||||
final MoneyDTO? amount;
|
||||
|
||||
final FxIntentDTO? fx;
|
||||
|
||||
@JsonKey(name: 'settlement_mode')
|
||||
final String? settlementMode;
|
||||
|
||||
final Map<String, String>? attributes;
|
||||
|
||||
const PaymentIntentDTO({
|
||||
this.kind,
|
||||
this.source,
|
||||
this.destination,
|
||||
this.amount,
|
||||
this.fx,
|
||||
this.settlementMode,
|
||||
this.attributes,
|
||||
});
|
||||
|
||||
factory PaymentIntentDTO.fromJson(Map<String, dynamic> json) => _$PaymentIntentDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PaymentIntentDTOToJson(this);
|
||||
}
|
||||
21
frontend/pshared/lib/data/dto/payment/ledger.dart
Normal file
21
frontend/pshared/lib/data/dto/payment/ledger.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'ledger.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class LedgerEndpointDTO {
|
||||
@JsonKey(name: 'ledger_account_ref')
|
||||
final String ledgerAccountRef;
|
||||
|
||||
@JsonKey(name: 'contra_ledger_account_ref')
|
||||
final String? contraLedgerAccountRef;
|
||||
|
||||
const LedgerEndpointDTO({
|
||||
required this.ledgerAccountRef,
|
||||
this.contraLedgerAccountRef,
|
||||
});
|
||||
|
||||
factory LedgerEndpointDTO.fromJson(Map<String, dynamic> json) => _$LedgerEndpointDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$LedgerEndpointDTOToJson(this);
|
||||
}
|
||||
22
frontend/pshared/lib/data/dto/payment/managed_wallet.dart
Normal file
22
frontend/pshared/lib/data/dto/payment/managed_wallet.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/asset.dart';
|
||||
|
||||
part 'managed_wallet.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class ManagedWalletEndpointDTO {
|
||||
@JsonKey(name: 'managed_wallet_ref')
|
||||
final String managedWalletRef;
|
||||
|
||||
final AssetDTO? asset;
|
||||
|
||||
const ManagedWalletEndpointDTO({
|
||||
required this.managedWalletRef,
|
||||
this.asset,
|
||||
});
|
||||
|
||||
factory ManagedWalletEndpointDTO.fromJson(Map<String, dynamic> json) => _$ManagedWalletEndpointDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ManagedWalletEndpointDTOToJson(this);
|
||||
}
|
||||
18
frontend/pshared/lib/data/dto/payment/money.dart
Normal file
18
frontend/pshared/lib/data/dto/payment/money.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'money.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class MoneyDTO {
|
||||
final String amount;
|
||||
final String currency;
|
||||
|
||||
const MoneyDTO({
|
||||
required this.amount,
|
||||
required this.currency,
|
||||
});
|
||||
|
||||
factory MoneyDTO.fromJson(Map<String, dynamic> json) => _$MoneyDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$MoneyDTOToJson(this);
|
||||
}
|
||||
20
frontend/pshared/lib/data/dto/payment/network_fee.dart
Normal file
20
frontend/pshared/lib/data/dto/payment/network_fee.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/money.dart';
|
||||
|
||||
part 'network_fee.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class NetworkFeeDTO {
|
||||
final MoneyDTO? networkFee;
|
||||
final String? estimationContext;
|
||||
|
||||
const NetworkFeeDTO({
|
||||
this.networkFee,
|
||||
this.estimationContext,
|
||||
});
|
||||
|
||||
factory NetworkFeeDTO.fromJson(Map<String, dynamic> json) => _$NetworkFeeDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$NetworkFeeDTOToJson(this);
|
||||
}
|
||||
28
frontend/pshared/lib/data/dto/payment/payment.dart
Normal file
28
frontend/pshared/lib/data/dto/payment/payment.dart
Normal file
@@ -0,0 +1,28 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/payment_quote.dart';
|
||||
|
||||
part 'payment.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PaymentDTO {
|
||||
final String? paymentRef;
|
||||
final String? idempotencyKey;
|
||||
final String? state;
|
||||
final String? failureCode;
|
||||
final String? failureReason;
|
||||
final PaymentQuoteDTO? lastQuote;
|
||||
|
||||
const PaymentDTO({
|
||||
this.paymentRef,
|
||||
this.idempotencyKey,
|
||||
this.state,
|
||||
this.failureCode,
|
||||
this.failureReason,
|
||||
this.lastQuote,
|
||||
});
|
||||
|
||||
factory PaymentDTO.fromJson(Map<String, dynamic> json) => _$PaymentDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PaymentDTOToJson(this);
|
||||
}
|
||||
35
frontend/pshared/lib/data/dto/payment/payment_quote.dart
Normal file
35
frontend/pshared/lib/data/dto/payment/payment_quote.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
import 'package:pshared/data/dto/payment/fee_line.dart';
|
||||
import 'package:pshared/data/dto/payment/fx_quote.dart';
|
||||
import 'package:pshared/data/dto/payment/money.dart';
|
||||
import 'package:pshared/data/dto/payment/network_fee.dart';
|
||||
|
||||
part 'payment_quote.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class PaymentQuoteDTO {
|
||||
final String? quoteRef;
|
||||
final MoneyDTO? debitAmount;
|
||||
final MoneyDTO? expectedSettlementAmount;
|
||||
final MoneyDTO? expectedFeeTotal;
|
||||
final String? feeQuoteToken;
|
||||
final List<FeeLineDTO>? feeLines;
|
||||
final NetworkFeeDTO? networkFee;
|
||||
final FxQuoteDTO? fxQuote;
|
||||
|
||||
const PaymentQuoteDTO({
|
||||
this.quoteRef,
|
||||
this.debitAmount,
|
||||
this.expectedSettlementAmount,
|
||||
this.expectedFeeTotal,
|
||||
this.feeQuoteToken,
|
||||
this.feeLines,
|
||||
this.networkFee,
|
||||
this.fxQuote,
|
||||
});
|
||||
|
||||
factory PaymentQuoteDTO.fromJson(Map<String, dynamic> json) => _$PaymentQuoteDTOFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$PaymentQuoteDTOToJson(this);
|
||||
}
|
||||
20
frontend/pshared/lib/data/mapper/payment/asset.dart
Normal file
20
frontend/pshared/lib/data/mapper/payment/asset.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:pshared/data/dto/payment/asset.dart';
|
||||
import 'package:pshared/data/mapper/payment/enums.dart';
|
||||
import 'package:pshared/models/payment/asset.dart';
|
||||
|
||||
|
||||
extension PaymentAssetMapper on PaymentAsset {
|
||||
AssetDTO toDTO() => AssetDTO(
|
||||
chain: chainNetworkToValue(chain),
|
||||
tokenSymbol: tokenSymbol,
|
||||
contractAddress: contractAddress,
|
||||
);
|
||||
}
|
||||
|
||||
extension AssetDTOMapper on AssetDTO {
|
||||
PaymentAsset toDomain() => PaymentAsset(
|
||||
chain: chainNetworkFromValue(chain),
|
||||
tokenSymbol: tokenSymbol,
|
||||
contractAddress: contractAddress,
|
||||
);
|
||||
}
|
||||
@@ -3,17 +3,23 @@ import 'package:pshared/models/payment/methods/card.dart';
|
||||
|
||||
|
||||
extension CardPaymentMethodMapper on CardPaymentMethod {
|
||||
CardPaymentDataDTO toDTO() => CardPaymentDataDTO(
|
||||
CardEndpointDTO toDTO() => CardEndpointDTO(
|
||||
pan: pan,
|
||||
firstName: firstName,
|
||||
lastName: lastName,
|
||||
expMonth: expMonth,
|
||||
expYear: expYear,
|
||||
country: country,
|
||||
);
|
||||
}
|
||||
|
||||
extension CardPaymentDataDTOMapper on CardPaymentDataDTO {
|
||||
extension CardPaymentDataDTOMapper on CardEndpointDTO {
|
||||
CardPaymentMethod toDomain() => CardPaymentMethod(
|
||||
pan: pan,
|
||||
firstName: firstName,
|
||||
lastName: lastName,
|
||||
expMonth: expMonth,
|
||||
expYear: expYear,
|
||||
country: country,
|
||||
);
|
||||
}
|
||||
|
||||
17
frontend/pshared/lib/data/mapper/payment/card_token.dart
Normal file
17
frontend/pshared/lib/data/mapper/payment/card_token.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:pshared/data/dto/payment/card_token.dart';
|
||||
import 'package:pshared/models/payment/methods/card_token.dart';
|
||||
|
||||
|
||||
extension CardTokenPaymentMethodMapper on CardTokenPaymentMethod {
|
||||
CardTokenEndpointDTO toDTO() => CardTokenEndpointDTO(
|
||||
token: token,
|
||||
maskedPan: maskedPan,
|
||||
);
|
||||
}
|
||||
|
||||
extension CardTokenPaymentDataDTOMapper on CardTokenEndpointDTO {
|
||||
CardTokenPaymentMethod toDomain() => CardTokenPaymentMethod(
|
||||
token: token,
|
||||
maskedPan: maskedPan,
|
||||
);
|
||||
}
|
||||
@@ -1,19 +1,20 @@
|
||||
import 'package:pshared/data/dto/payment/crypto_address.dart';
|
||||
import 'package:pshared/data/dto/payment/external_chain.dart';
|
||||
import 'package:pshared/data/mapper/payment/asset.dart';
|
||||
import 'package:pshared/models/payment/methods/crypto_address.dart';
|
||||
|
||||
|
||||
extension CryptoAddressPaymentMethodMapper on CryptoAddressPaymentMethod {
|
||||
CryptoAddressPaymentDataDTO toDTO() => CryptoAddressPaymentDataDTO(
|
||||
ExternalChainEndpointDTO toDTO() => ExternalChainEndpointDTO(
|
||||
address: address,
|
||||
network: network,
|
||||
destinationTag: destinationTag,
|
||||
asset: asset?.toDTO(),
|
||||
memo: memo,
|
||||
);
|
||||
}
|
||||
|
||||
extension CryptoAddressPaymentDataDTOMapper on CryptoAddressPaymentDataDTO {
|
||||
extension CryptoAddressPaymentDataDTOMapper on ExternalChainEndpointDTO {
|
||||
CryptoAddressPaymentMethod toDomain() => CryptoAddressPaymentMethod(
|
||||
address: address,
|
||||
network: network,
|
||||
destinationTag: destinationTag,
|
||||
asset: asset?.toDomain(),
|
||||
memo: memo,
|
||||
);
|
||||
}
|
||||
|
||||
16
frontend/pshared/lib/data/mapper/payment/currency_pair.dart
Normal file
16
frontend/pshared/lib/data/mapper/payment/currency_pair.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:pshared/data/dto/payment/currency_pair.dart';
|
||||
import 'package:pshared/models/payment/currency_pair.dart';
|
||||
|
||||
extension CurrencyPairMapper on CurrencyPair {
|
||||
CurrencyPairDTO toDTO() => CurrencyPairDTO(
|
||||
base: base,
|
||||
quote: quote,
|
||||
);
|
||||
}
|
||||
|
||||
extension CurrencyPairDTOMapper on CurrencyPairDTO {
|
||||
CurrencyPair toDomain() => CurrencyPair(
|
||||
base: base,
|
||||
quote: quote,
|
||||
);
|
||||
}
|
||||
183
frontend/pshared/lib/data/mapper/payment/enums.dart
Normal file
183
frontend/pshared/lib/data/mapper/payment/enums.dart
Normal file
@@ -0,0 +1,183 @@
|
||||
import 'package:pshared/models/payment/chain_network.dart';
|
||||
import 'package:pshared/models/payment/fx/side.dart';
|
||||
import 'package:pshared/models/payment/insufficient_net_policy.dart';
|
||||
import 'package:pshared/models/payment/kind.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
import 'package:pshared/models/payment/settlement_mode.dart';
|
||||
|
||||
|
||||
PaymentKind paymentKindFromValue(String? value) {
|
||||
switch (value) {
|
||||
case 'payout':
|
||||
return PaymentKind.payout;
|
||||
case 'internal_transfer':
|
||||
return PaymentKind.internalTransfer;
|
||||
case 'fx_conversion':
|
||||
return PaymentKind.fxConversion;
|
||||
case 'unspecified':
|
||||
return PaymentKind.unspecified;
|
||||
default:
|
||||
throw ArgumentError('Unknown PaymentKind value: $value');
|
||||
}
|
||||
}
|
||||
|
||||
String paymentKindToValue(PaymentKind kind) {
|
||||
switch (kind) {
|
||||
case PaymentKind.payout:
|
||||
return 'payout';
|
||||
case PaymentKind.internalTransfer:
|
||||
return 'internal_transfer';
|
||||
case PaymentKind.fxConversion:
|
||||
return 'fx_conversion';
|
||||
case PaymentKind.unspecified:
|
||||
return 'unspecified';
|
||||
}
|
||||
}
|
||||
|
||||
SettlementMode settlementModeFromValue(String? value) {
|
||||
switch (value) {
|
||||
case 'fix_source':
|
||||
return SettlementMode.fixSource;
|
||||
case 'fix_received':
|
||||
return SettlementMode.fixReceived;
|
||||
case 'unspecified':
|
||||
return SettlementMode.unspecified;
|
||||
default:
|
||||
throw ArgumentError('Unknown SettlementMode value: $value');
|
||||
}
|
||||
}
|
||||
|
||||
String settlementModeToValue(SettlementMode mode) {
|
||||
switch (mode) {
|
||||
case SettlementMode.fixSource:
|
||||
return 'fix_source';
|
||||
case SettlementMode.fixReceived:
|
||||
return 'fix_received';
|
||||
case SettlementMode.unspecified:
|
||||
return 'unspecified';
|
||||
}
|
||||
}
|
||||
|
||||
FxSide fxSideFromValue(String? value) {
|
||||
switch (value) {
|
||||
case 'buy_base_sell_quote':
|
||||
return FxSide.buyBaseSellQuote;
|
||||
case 'sell_base_buy_quote':
|
||||
return FxSide.sellBaseBuyQuote;
|
||||
case 'unspecified':
|
||||
return FxSide.unspecified;
|
||||
default:
|
||||
throw ArgumentError('Unknown FxSide value: $value');
|
||||
}
|
||||
}
|
||||
|
||||
String fxSideToValue(FxSide side) {
|
||||
switch (side) {
|
||||
case FxSide.buyBaseSellQuote:
|
||||
return 'buy_base_sell_quote';
|
||||
case FxSide.sellBaseBuyQuote:
|
||||
return 'sell_base_buy_quote';
|
||||
case FxSide.unspecified:
|
||||
return 'unspecified';
|
||||
}
|
||||
}
|
||||
|
||||
ChainNetwork chainNetworkFromValue(String? value) {
|
||||
switch (value) {
|
||||
case 'ethereum_mainnet':
|
||||
return ChainNetwork.ethereumMainnet;
|
||||
case 'arbitrum_one':
|
||||
return ChainNetwork.arbitrumOne;
|
||||
case 'other_evm':
|
||||
return ChainNetwork.otherEvm;
|
||||
case 'unspecified':
|
||||
return ChainNetwork.unspecified;
|
||||
default:
|
||||
throw ArgumentError('Unknown ChainNetwork value: $value');
|
||||
}
|
||||
}
|
||||
|
||||
String chainNetworkToValue(ChainNetwork chain) {
|
||||
switch (chain) {
|
||||
case ChainNetwork.ethereumMainnet:
|
||||
return 'ethereum_mainnet';
|
||||
case ChainNetwork.arbitrumOne:
|
||||
return 'arbitrum_one';
|
||||
case ChainNetwork.otherEvm:
|
||||
return 'other_evm';
|
||||
case ChainNetwork.unspecified:
|
||||
return 'unspecified';
|
||||
}
|
||||
}
|
||||
|
||||
InsufficientNetPolicy insufficientNetPolicyFromValue(String? value) {
|
||||
switch (value) {
|
||||
case 'block_posting':
|
||||
return InsufficientNetPolicy.blockPosting;
|
||||
case 'sweep_org_cash':
|
||||
return InsufficientNetPolicy.sweepOrgCash;
|
||||
case 'invoice_later':
|
||||
return InsufficientNetPolicy.invoiceLater;
|
||||
case 'unspecified':
|
||||
return InsufficientNetPolicy.unspecified;
|
||||
default:
|
||||
throw ArgumentError('Unknown InsufficientNetPolicy value: $value');
|
||||
}
|
||||
}
|
||||
|
||||
String insufficientNetPolicyToValue(InsufficientNetPolicy policy) {
|
||||
switch (policy) {
|
||||
case InsufficientNetPolicy.blockPosting:
|
||||
return 'block_posting';
|
||||
case InsufficientNetPolicy.sweepOrgCash:
|
||||
return 'sweep_org_cash';
|
||||
case InsufficientNetPolicy.invoiceLater:
|
||||
return 'invoice_later';
|
||||
case InsufficientNetPolicy.unspecified:
|
||||
return 'unspecified';
|
||||
}
|
||||
}
|
||||
|
||||
PaymentType endpointTypeFromValue(String? value) {
|
||||
switch (value) {
|
||||
case 'managedWallet':
|
||||
return PaymentType.managedWallet;
|
||||
case 'externalChain':
|
||||
return PaymentType.externalChain;
|
||||
case 'card':
|
||||
return PaymentType.card;
|
||||
case 'cardToken':
|
||||
return PaymentType.cardToken;
|
||||
case 'ledger':
|
||||
return PaymentType.ledger;
|
||||
case 'bankAccount':
|
||||
return PaymentType.bankAccount;
|
||||
case 'iban':
|
||||
return PaymentType.iban;
|
||||
case 'wallet':
|
||||
return PaymentType.wallet;
|
||||
default:
|
||||
throw ArgumentError('Unknown PaymentType value: $value');
|
||||
}
|
||||
}
|
||||
|
||||
String endpointTypeToValue(PaymentType type) {
|
||||
switch (type) {
|
||||
case PaymentType.ledger:
|
||||
return 'ledger';
|
||||
case PaymentType.managedWallet:
|
||||
return 'managedWallet';
|
||||
case PaymentType.externalChain:
|
||||
return 'externalChain';
|
||||
case PaymentType.card:
|
||||
return 'card';
|
||||
case PaymentType.cardToken:
|
||||
return 'cardToken';
|
||||
case PaymentType.bankAccount:
|
||||
return 'bankAccount';
|
||||
case PaymentType.iban:
|
||||
return 'iban';
|
||||
case PaymentType.wallet:
|
||||
return 'wallet';
|
||||
}
|
||||
}
|
||||
24
frontend/pshared/lib/data/mapper/payment/fee_line.dart
Normal file
24
frontend/pshared/lib/data/mapper/payment/fee_line.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:pshared/data/dto/payment/fee_line.dart';
|
||||
import 'package:pshared/data/mapper/payment/money.dart';
|
||||
import 'package:pshared/models/payment/fees/line.dart';
|
||||
|
||||
|
||||
extension FeeLineDTOMapper on FeeLineDTO {
|
||||
FeeLine toDomain() => FeeLine(
|
||||
ledgerAccountRef: ledgerAccountRef,
|
||||
amount: amount?.toDomain(),
|
||||
lineType: lineType,
|
||||
side: side,
|
||||
meta: meta,
|
||||
);
|
||||
}
|
||||
|
||||
extension FeeLineMapper on FeeLine {
|
||||
FeeLineDTO toDTO() => FeeLineDTO(
|
||||
ledgerAccountRef: ledgerAccountRef,
|
||||
amount: amount?.toDTO(),
|
||||
lineType: lineType,
|
||||
side: side,
|
||||
meta: meta,
|
||||
);
|
||||
}
|
||||
36
frontend/pshared/lib/data/mapper/payment/fx_quote.dart
Normal file
36
frontend/pshared/lib/data/mapper/payment/fx_quote.dart
Normal file
@@ -0,0 +1,36 @@
|
||||
import 'package:pshared/data/dto/payment/fx_quote.dart';
|
||||
import 'package:pshared/data/mapper/payment/money.dart';
|
||||
import 'package:pshared/models/payment/fx/quote.dart';
|
||||
|
||||
|
||||
extension FxQuoteDTOMapper on FxQuoteDTO {
|
||||
FxQuote toDomain() => FxQuote(
|
||||
quoteRef: quoteRef,
|
||||
baseCurrency: baseCurrency,
|
||||
quoteCurrency: quoteCurrency,
|
||||
side: side,
|
||||
price: price,
|
||||
baseAmount: baseAmount?.toDomain(),
|
||||
quoteAmount: quoteAmount?.toDomain(),
|
||||
expiresAtUnixMs: expiresAtUnixMs,
|
||||
provider: provider,
|
||||
rateRef: rateRef,
|
||||
firm: firm ?? false,
|
||||
);
|
||||
}
|
||||
|
||||
extension FxQuoteMapper on FxQuote {
|
||||
FxQuoteDTO toDTO() => FxQuoteDTO(
|
||||
quoteRef: quoteRef,
|
||||
baseCurrency: baseCurrency,
|
||||
quoteCurrency: quoteCurrency,
|
||||
side: side,
|
||||
price: price,
|
||||
baseAmount: baseAmount?.toDTO(),
|
||||
quoteAmount: quoteAmount?.toDTO(),
|
||||
expiresAtUnixMs: expiresAtUnixMs,
|
||||
provider: provider,
|
||||
rateRef: rateRef,
|
||||
firm: firm,
|
||||
);
|
||||
}
|
||||
27
frontend/pshared/lib/data/mapper/payment/intent/fx.dart
Normal file
27
frontend/pshared/lib/data/mapper/payment/intent/fx.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:pshared/data/dto/payment/intent/fx.dart';
|
||||
import 'package:pshared/data/mapper/payment/currency_pair.dart';
|
||||
import 'package:pshared/data/mapper/payment/enums.dart';
|
||||
import 'package:pshared/models/payment/fx/intent.dart';
|
||||
|
||||
|
||||
extension FxIntentMapper on FxIntent {
|
||||
FxIntentDTO toDTO() => FxIntentDTO(
|
||||
pair: pair?.toDTO(),
|
||||
side: fxSideToValue(side),
|
||||
firm: firm,
|
||||
ttlMs: ttlMs,
|
||||
preferredProvider: preferredProvider,
|
||||
maxAgeMs: maxAgeMs,
|
||||
);
|
||||
}
|
||||
|
||||
extension FxIntentDTOMapper on FxIntentDTO {
|
||||
FxIntent toDomain() => FxIntent(
|
||||
pair: pair?.toDomain(),
|
||||
side: fxSideFromValue(side),
|
||||
firm: firm,
|
||||
ttlMs: ttlMs,
|
||||
preferredProvider: preferredProvider,
|
||||
maxAgeMs: maxAgeMs,
|
||||
);
|
||||
}
|
||||
30
frontend/pshared/lib/data/mapper/payment/intent/payment.dart
Normal file
30
frontend/pshared/lib/data/mapper/payment/intent/payment.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:pshared/data/dto/payment/intent/payment.dart';
|
||||
import 'package:pshared/data/mapper/payment/payment.dart';
|
||||
import 'package:pshared/data/mapper/payment/enums.dart';
|
||||
import 'package:pshared/data/mapper/payment/intent/fx.dart';
|
||||
import 'package:pshared/data/mapper/payment/money.dart';
|
||||
import 'package:pshared/models/payment/intent.dart';
|
||||
|
||||
extension PaymentIntentMapper on PaymentIntent {
|
||||
PaymentIntentDTO toDTO() => PaymentIntentDTO(
|
||||
kind: paymentKindToValue(kind),
|
||||
source: source?.toDTO(),
|
||||
destination: destination?.toDTO(),
|
||||
amount: amount?.toDTO(),
|
||||
fx: fx?.toDTO(),
|
||||
settlementMode: settlementModeToValue(settlementMode),
|
||||
attributes: attributes,
|
||||
);
|
||||
}
|
||||
|
||||
extension PaymentIntentDTOMapper on PaymentIntentDTO {
|
||||
PaymentIntent toDomain() => PaymentIntent(
|
||||
kind: paymentKindFromValue(kind),
|
||||
source: source?.toDomain(),
|
||||
destination: destination?.toDomain(),
|
||||
amount: amount?.toDomain(),
|
||||
fx: fx?.toDomain(),
|
||||
settlementMode: settlementModeFromValue(settlementMode),
|
||||
attributes: attributes,
|
||||
);
|
||||
}
|
||||
17
frontend/pshared/lib/data/mapper/payment/ledger.dart
Normal file
17
frontend/pshared/lib/data/mapper/payment/ledger.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:pshared/data/dto/payment/ledger.dart';
|
||||
import 'package:pshared/models/payment/methods/ledger.dart';
|
||||
|
||||
|
||||
extension LedgerPaymentMethodMapper on LedgerPaymentMethod {
|
||||
LedgerEndpointDTO toDTO() => LedgerEndpointDTO(
|
||||
ledgerAccountRef: ledgerAccountRef,
|
||||
contraLedgerAccountRef: contraLedgerAccountRef,
|
||||
);
|
||||
}
|
||||
|
||||
extension LedgerPaymentDataDTOMapper on LedgerEndpointDTO {
|
||||
LedgerPaymentMethod toDomain() => LedgerPaymentMethod(
|
||||
ledgerAccountRef: ledgerAccountRef,
|
||||
contraLedgerAccountRef: contraLedgerAccountRef,
|
||||
);
|
||||
}
|
||||
18
frontend/pshared/lib/data/mapper/payment/managed_wallet.dart
Normal file
18
frontend/pshared/lib/data/mapper/payment/managed_wallet.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:pshared/data/dto/payment/managed_wallet.dart';
|
||||
import 'package:pshared/data/mapper/payment/asset.dart';
|
||||
import 'package:pshared/models/payment/methods/managed_wallet.dart';
|
||||
|
||||
|
||||
extension ManagedWalletPaymentMethodMapper on ManagedWalletPaymentMethod {
|
||||
ManagedWalletEndpointDTO toDTO() => ManagedWalletEndpointDTO(
|
||||
managedWalletRef: managedWalletRef,
|
||||
asset: asset?.toDTO(),
|
||||
);
|
||||
}
|
||||
|
||||
extension ManagedWalletDataDTOMapper on ManagedWalletEndpointDTO {
|
||||
ManagedWalletPaymentMethod toDomain() => ManagedWalletPaymentMethod(
|
||||
managedWalletRef: managedWalletRef,
|
||||
asset: asset?.toDomain(),
|
||||
);
|
||||
}
|
||||
@@ -1,21 +1,30 @@
|
||||
import 'package:pshared/data/dto/payment/card.dart';
|
||||
import 'package:pshared/data/dto/payment/crypto_address.dart';
|
||||
import 'package:pshared/data/dto/payment/card_token.dart';
|
||||
import 'package:pshared/data/dto/payment/external_chain.dart';
|
||||
import 'package:pshared/data/dto/payment/iban.dart';
|
||||
import 'package:pshared/data/dto/payment/ledger.dart';
|
||||
import 'package:pshared/data/dto/payment/managed_wallet.dart';
|
||||
import 'package:pshared/data/dto/payment/method.dart';
|
||||
import 'package:pshared/data/dto/payment/russian_bank.dart';
|
||||
import 'package:pshared/data/dto/payment/wallet.dart';
|
||||
import 'package:pshared/data/mapper/payment/card_token.dart';
|
||||
import 'package:pshared/data/mapper/payment/crypto_address.dart';
|
||||
import 'package:pshared/data/mapper/payment/card.dart';
|
||||
import 'package:pshared/data/mapper/payment/iban.dart';
|
||||
import 'package:pshared/data/mapper/payment/ledger.dart';
|
||||
import 'package:pshared/data/mapper/payment/managed_wallet.dart';
|
||||
import 'package:pshared/data/mapper/payment/russian_bank.dart';
|
||||
import 'package:pshared/data/mapper/payment/type.dart';
|
||||
import 'package:pshared/data/mapper/payment/wallet.dart';
|
||||
import 'package:pshared/models/describable.dart';
|
||||
import 'package:pshared/models/organization/bound.dart';
|
||||
import 'package:pshared/models/payment/methods/card.dart';
|
||||
import 'package:pshared/models/payment/methods/card_token.dart';
|
||||
import 'package:pshared/models/payment/methods/crypto_address.dart';
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/methods/iban.dart';
|
||||
import 'package:pshared/models/payment/methods/ledger.dart';
|
||||
import 'package:pshared/models/payment/methods/managed_wallet.dart';
|
||||
import 'package:pshared/models/payment/methods/russian_bank.dart';
|
||||
import 'package:pshared/models/payment/methods/type.dart';
|
||||
import 'package:pshared/models/payment/methods/wallet.dart';
|
||||
@@ -40,20 +49,17 @@ extension PaymentMethodMapper on PaymentMethod {
|
||||
isMain: isMain,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _dataToJson(PaymentMethodData data) {
|
||||
switch (data.type) {
|
||||
case PaymentType.card:
|
||||
return (data as CardPaymentMethod).toDTO().toJson();
|
||||
case PaymentType.iban:
|
||||
return (data as IbanPaymentMethod).toDTO().toJson();
|
||||
case PaymentType.bankAccount:
|
||||
return (data as RussianBankAccountPaymentMethod).toDTO().toJson();
|
||||
case PaymentType.wallet:
|
||||
return (data as WalletPaymentMethod).toDTO().toJson();
|
||||
case PaymentType.cryptoAddress:
|
||||
return (data as CryptoAddressPaymentMethod).toDTO().toJson();
|
||||
}
|
||||
}
|
||||
Map<String, dynamic> _dataToJson(PaymentMethodData data) => switch (data) {
|
||||
CardPaymentMethod card => card.toDTO().toJson(),
|
||||
CardTokenPaymentMethod cardToken => cardToken.toDTO().toJson(),
|
||||
IbanPaymentMethod iban => iban.toDTO().toJson(),
|
||||
RussianBankAccountPaymentMethod bankAccount => bankAccount.toDTO().toJson(),
|
||||
WalletPaymentMethod wallet => wallet.toDTO().toJson(),
|
||||
CryptoAddressPaymentMethod crypto => crypto.toDTO().toJson(),
|
||||
LedgerPaymentMethod ledger => ledger.toDTO().toJson(),
|
||||
ManagedWalletPaymentMethod managedWallet => managedWallet.toDTO().toJson(),
|
||||
_ => throw UnsupportedError('Unsupported payment method data: ${data.runtimeType}'),
|
||||
};
|
||||
}
|
||||
|
||||
extension PaymentMethodDTOMapper on PaymentMethodDTO {
|
||||
@@ -73,15 +79,21 @@ extension PaymentMethodDTOMapper on PaymentMethodDTO {
|
||||
PaymentMethodData _dataToDomain(PaymentType paymentType, Map<String, dynamic> payload) {
|
||||
switch (paymentType) {
|
||||
case PaymentType.card:
|
||||
return CardPaymentDataDTO.fromJson(payload).toDomain();
|
||||
return CardEndpointDTO.fromJson(payload).toDomain();
|
||||
case PaymentType.cardToken:
|
||||
return CardTokenEndpointDTO.fromJson(payload).toDomain();
|
||||
case PaymentType.iban:
|
||||
return IbanPaymentDataDTO.fromJson(payload).toDomain();
|
||||
case PaymentType.bankAccount:
|
||||
return RussianBankAccountPaymentDataDTO.fromJson(payload).toDomain();
|
||||
case PaymentType.wallet:
|
||||
return WalletPaymentDataDTO.fromJson(payload).toDomain();
|
||||
case PaymentType.cryptoAddress:
|
||||
return CryptoAddressPaymentDataDTO.fromJson(payload).toDomain();
|
||||
case PaymentType.externalChain:
|
||||
return ExternalChainEndpointDTO.fromJson(payload).toDomain();
|
||||
case PaymentType.ledger:
|
||||
return LedgerEndpointDTO.fromJson(payload).toDomain();
|
||||
case PaymentType.managedWallet:
|
||||
return ManagedWalletEndpointDTO.fromJson(payload).toDomain();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
frontend/pshared/lib/data/mapper/payment/money.dart
Normal file
16
frontend/pshared/lib/data/mapper/payment/money.dart
Normal file
@@ -0,0 +1,16 @@
|
||||
import 'package:pshared/data/dto/payment/money.dart';
|
||||
import 'package:pshared/models/payment/money.dart';
|
||||
|
||||
extension MoneyMapper on Money {
|
||||
MoneyDTO toDTO() => MoneyDTO(
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
);
|
||||
}
|
||||
|
||||
extension MoneyDTOMapper on MoneyDTO {
|
||||
Money toDomain() => Money(
|
||||
amount: amount,
|
||||
currency: currency,
|
||||
);
|
||||
}
|
||||
18
frontend/pshared/lib/data/mapper/payment/network_fee.dart
Normal file
18
frontend/pshared/lib/data/mapper/payment/network_fee.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:pshared/data/dto/payment/network_fee.dart';
|
||||
import 'package:pshared/data/mapper/payment/money.dart';
|
||||
import 'package:pshared/models/payment/fees/network.dart';
|
||||
|
||||
|
||||
extension NetworkFeeDTOMapper on NetworkFeeDTO {
|
||||
NetworkFee toDomain() => NetworkFee(
|
||||
networkFee: networkFee?.toDomain(),
|
||||
estimationContext: estimationContext,
|
||||
);
|
||||
}
|
||||
|
||||
extension NetworkFeeMapper on NetworkFee {
|
||||
NetworkFeeDTO toDTO() => NetworkFeeDTO(
|
||||
networkFee: networkFee?.toDTO(),
|
||||
estimationContext: estimationContext,
|
||||
);
|
||||
}
|
||||
133
frontend/pshared/lib/data/mapper/payment/payment.dart
Normal file
133
frontend/pshared/lib/data/mapper/payment/payment.dart
Normal file
@@ -0,0 +1,133 @@
|
||||
import 'package:pshared/data/dto/payment/card.dart';
|
||||
import 'package:pshared/data/dto/payment/card_token.dart';
|
||||
import 'package:pshared/data/dto/payment/endpoint.dart';
|
||||
import 'package:pshared/data/dto/payment/external_chain.dart';
|
||||
import 'package:pshared/data/dto/payment/ledger.dart';
|
||||
import 'package:pshared/data/dto/payment/managed_wallet.dart';
|
||||
import 'package:pshared/data/mapper/payment/asset.dart';
|
||||
import 'package:pshared/data/mapper/payment/type.dart';
|
||||
import 'package:pshared/models/payment/methods/card.dart';
|
||||
import 'package:pshared/models/payment/methods/card_token.dart';
|
||||
import 'package:pshared/models/payment/methods/crypto_address.dart';
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/methods/ledger.dart';
|
||||
import 'package:pshared/models/payment/methods/managed_wallet.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
extension PaymentMethodDataEndpointMapper on PaymentMethodData {
|
||||
PaymentEndpointDTO toDTO() {
|
||||
final metadata = this.metadata;
|
||||
|
||||
switch (type) {
|
||||
case PaymentType.ledger:
|
||||
final payload = this as LedgerPaymentMethod;
|
||||
return PaymentEndpointDTO(
|
||||
type: paymentTypeToValue(type),
|
||||
data: LedgerEndpointDTO(
|
||||
ledgerAccountRef: payload.ledgerAccountRef,
|
||||
contraLedgerAccountRef: payload.contraLedgerAccountRef,
|
||||
).toJson(),
|
||||
metadata: metadata,
|
||||
);
|
||||
case PaymentType.managedWallet:
|
||||
final payload = this as ManagedWalletPaymentMethod;
|
||||
return PaymentEndpointDTO(
|
||||
type: paymentTypeToValue(type),
|
||||
data: ManagedWalletEndpointDTO(
|
||||
managedWalletRef: payload.managedWalletRef,
|
||||
asset: payload.asset?.toDTO(),
|
||||
).toJson(),
|
||||
metadata: metadata,
|
||||
);
|
||||
case PaymentType.externalChain:
|
||||
final payload = this as CryptoAddressPaymentMethod;
|
||||
return PaymentEndpointDTO(
|
||||
type: paymentTypeToValue(type),
|
||||
data: ExternalChainEndpointDTO(
|
||||
asset: payload.asset?.toDTO(),
|
||||
address: payload.address,
|
||||
memo: payload.memo,
|
||||
).toJson(),
|
||||
metadata: metadata,
|
||||
);
|
||||
case PaymentType.card:
|
||||
final payload = this as CardPaymentMethod;
|
||||
return PaymentEndpointDTO(
|
||||
type: paymentTypeToValue(type),
|
||||
data: CardEndpointDTO(
|
||||
pan: payload.pan,
|
||||
expMonth: payload.expMonth,
|
||||
expYear: payload.expYear,
|
||||
country: payload.country,
|
||||
firstName: payload.firstName,
|
||||
lastName: payload.lastName,
|
||||
).toJson(),
|
||||
metadata: metadata,
|
||||
);
|
||||
case PaymentType.cardToken:
|
||||
final payload = this as CardTokenPaymentMethod;
|
||||
return PaymentEndpointDTO(
|
||||
type: paymentTypeToValue(type),
|
||||
data: CardTokenEndpointDTO(
|
||||
token: payload.token,
|
||||
maskedPan: payload.maskedPan,
|
||||
).toJson(),
|
||||
metadata: metadata,
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError('Unsupported payment endpoint type: $type');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PaymentEndpointDTOMapper on PaymentEndpointDTO {
|
||||
PaymentMethodData toDomain() {
|
||||
final metadata = this.metadata;
|
||||
|
||||
switch (paymentTypeFromValue(type)) {
|
||||
case PaymentType.ledger:
|
||||
final payload = LedgerEndpointDTO.fromJson(data);
|
||||
return LedgerPaymentMethod(
|
||||
ledgerAccountRef: payload.ledgerAccountRef,
|
||||
contraLedgerAccountRef: payload.contraLedgerAccountRef,
|
||||
metadata: metadata,
|
||||
);
|
||||
case PaymentType.managedWallet:
|
||||
final payload = ManagedWalletEndpointDTO.fromJson(data);
|
||||
return ManagedWalletPaymentMethod(
|
||||
managedWalletRef: payload.managedWalletRef,
|
||||
asset: payload.asset?.toDomain(),
|
||||
metadata: metadata,
|
||||
);
|
||||
case PaymentType.externalChain:
|
||||
final payload = ExternalChainEndpointDTO.fromJson(data);
|
||||
return CryptoAddressPaymentMethod(
|
||||
asset: payload.asset?.toDomain(),
|
||||
address: payload.address,
|
||||
memo: payload.memo,
|
||||
metadata: metadata,
|
||||
);
|
||||
case PaymentType.card:
|
||||
final payload = CardEndpointDTO.fromJson(data);
|
||||
return CardPaymentMethod(
|
||||
pan: payload.pan,
|
||||
firstName: payload.firstName,
|
||||
lastName: payload.lastName,
|
||||
expMonth: payload.expMonth,
|
||||
expYear: payload.expYear,
|
||||
country: payload.country,
|
||||
metadata: metadata,
|
||||
);
|
||||
case PaymentType.cardToken:
|
||||
final payload = CardTokenEndpointDTO.fromJson(data);
|
||||
return CardTokenPaymentMethod(
|
||||
token: payload.token,
|
||||
maskedPan: payload.maskedPan,
|
||||
metadata: metadata,
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError('Unsupported payment endpoint type: ${paymentTypeFromValue(type)}');
|
||||
}
|
||||
}
|
||||
}
|
||||
33
frontend/pshared/lib/data/mapper/payment/payment_quote.dart
Normal file
33
frontend/pshared/lib/data/mapper/payment/payment_quote.dart
Normal file
@@ -0,0 +1,33 @@
|
||||
import 'package:pshared/data/dto/payment/payment_quote.dart';
|
||||
import 'package:pshared/data/mapper/payment/fee_line.dart';
|
||||
import 'package:pshared/data/mapper/payment/fx_quote.dart';
|
||||
import 'package:pshared/data/mapper/payment/money.dart';
|
||||
import 'package:pshared/data/mapper/payment/network_fee.dart';
|
||||
import 'package:pshared/models/payment/quote.dart';
|
||||
|
||||
|
||||
extension PaymentQuoteDTOMapper on PaymentQuoteDTO {
|
||||
PaymentQuote toDomain() => PaymentQuote(
|
||||
quoteRef: quoteRef,
|
||||
debitAmount: debitAmount?.toDomain(),
|
||||
expectedSettlementAmount: expectedSettlementAmount?.toDomain(),
|
||||
expectedFeeTotal: expectedFeeTotal?.toDomain(),
|
||||
feeQuoteToken: feeQuoteToken,
|
||||
feeLines: feeLines?.map((line) => line.toDomain()).toList(),
|
||||
networkFee: networkFee?.toDomain(),
|
||||
fxQuote: fxQuote?.toDomain(),
|
||||
);
|
||||
}
|
||||
|
||||
extension PaymentQuoteMapper on PaymentQuote {
|
||||
PaymentQuoteDTO toDTO() => PaymentQuoteDTO(
|
||||
quoteRef: quoteRef,
|
||||
debitAmount: debitAmount?.toDTO(),
|
||||
expectedSettlementAmount: expectedSettlementAmount?.toDTO(),
|
||||
expectedFeeTotal: expectedFeeTotal?.toDTO(),
|
||||
feeQuoteToken: feeQuoteToken,
|
||||
feeLines: feeLines?.map((line) => line.toDTO()).toList(),
|
||||
networkFee: networkFee?.toDTO(),
|
||||
fxQuote: fxQuote?.toDTO(),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:pshared/data/dto/payment/payment.dart';
|
||||
import 'package:pshared/data/mapper/payment/payment_quote.dart';
|
||||
import 'package:pshared/models/payment/payment.dart';
|
||||
|
||||
|
||||
extension PaymentDTOMapper on PaymentDTO {
|
||||
Payment toDomain() => Payment(
|
||||
paymentRef: paymentRef,
|
||||
idempotencyKey: idempotencyKey,
|
||||
state: state,
|
||||
failureCode: failureCode,
|
||||
failureReason: failureReason,
|
||||
lastQuote: lastQuote?.toDomain(),
|
||||
);
|
||||
}
|
||||
|
||||
extension PaymentMapper on Payment {
|
||||
PaymentDTO toDTO() => PaymentDTO(
|
||||
paymentRef: paymentRef,
|
||||
idempotencyKey: idempotencyKey,
|
||||
state: state,
|
||||
failureCode: failureCode,
|
||||
failureReason: failureReason,
|
||||
lastQuote: lastQuote?.toDTO(),
|
||||
);
|
||||
}
|
||||
@@ -7,12 +7,18 @@ PaymentType paymentTypeFromValue(String value) {
|
||||
return PaymentType.iban;
|
||||
case 'card':
|
||||
return PaymentType.card;
|
||||
case 'cardToken':
|
||||
return PaymentType.cardToken;
|
||||
case 'bankAccount':
|
||||
return PaymentType.bankAccount;
|
||||
case 'ledger':
|
||||
return PaymentType.ledger;
|
||||
case 'wallet':
|
||||
return PaymentType.wallet;
|
||||
case 'managedWallet':
|
||||
return PaymentType.managedWallet;
|
||||
case 'cryptoAddress':
|
||||
return PaymentType.cryptoAddress;
|
||||
return PaymentType.externalChain;
|
||||
default:
|
||||
return PaymentType.iban;
|
||||
}
|
||||
@@ -24,11 +30,17 @@ String paymentTypeToValue(PaymentType type) {
|
||||
return 'iban';
|
||||
case PaymentType.card:
|
||||
return 'card';
|
||||
case PaymentType.cardToken:
|
||||
return 'cardToken';
|
||||
case PaymentType.ledger:
|
||||
return 'ledger';
|
||||
case PaymentType.bankAccount:
|
||||
return 'bankAccount';
|
||||
case PaymentType.wallet:
|
||||
return 'wallet';
|
||||
case PaymentType.cryptoAddress:
|
||||
case PaymentType.managedWallet:
|
||||
return 'managedWallet';
|
||||
case PaymentType.externalChain:
|
||||
return 'cryptoAddress';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,25 @@
|
||||
"resourceEmpty": "Empty data",
|
||||
"@resourceEmpty": {
|
||||
"description": "Default message shown when no data is available"
|
||||
},
|
||||
|
||||
"chainNetworkUnspecified": "Unspecified network",
|
||||
"@chainNetworkUnspecified": {
|
||||
"description": "Fallback label when the chain network is not known"
|
||||
},
|
||||
|
||||
"chainNetworkEthereumMainnet": "Ethereum Mainnet",
|
||||
"@chainNetworkEthereumMainnet": {
|
||||
"description": "Label for the Ethereum mainnet network"
|
||||
},
|
||||
|
||||
"chainNetworkArbitrumOne": "Arbitrum One",
|
||||
"@chainNetworkArbitrumOne": {
|
||||
"description": "Label for the Arbitrum One network"
|
||||
},
|
||||
|
||||
"chainNetworkOtherEvm": "Other EVM chain",
|
||||
"@chainNetworkOtherEvm": {
|
||||
"description": "Label for any other EVM-compatible network"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,5 +29,25 @@
|
||||
"resourceEmpty": "Нет данных",
|
||||
"@resourceEmpty": {
|
||||
"description": "Default message shown when no data is available"
|
||||
},
|
||||
|
||||
"chainNetworkUnspecified": "Сеть не указана",
|
||||
"@chainNetworkUnspecified": {
|
||||
"description": "Fallback label when the chain network is not known"
|
||||
},
|
||||
|
||||
"chainNetworkEthereumMainnet": "Ethereum Mainnet",
|
||||
"@chainNetworkEthereumMainnet": {
|
||||
"description": "Label for the Ethereum mainnet network"
|
||||
},
|
||||
|
||||
"chainNetworkArbitrumOne": "Arbitrum One",
|
||||
"@chainNetworkArbitrumOne": {
|
||||
"description": "Label for the Arbitrum One network"
|
||||
},
|
||||
|
||||
"chainNetworkOtherEvm": "Другая EVM сеть",
|
||||
"@chainNetworkOtherEvm": {
|
||||
"description": "Label for any other EVM-compatible network"
|
||||
}
|
||||
}
|
||||
|
||||
14
frontend/pshared/lib/models/payment/asset.dart
Normal file
14
frontend/pshared/lib/models/payment/asset.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:pshared/models/payment/chain_network.dart';
|
||||
|
||||
|
||||
class PaymentAsset {
|
||||
final ChainNetwork chain;
|
||||
final String tokenSymbol;
|
||||
final String? contractAddress;
|
||||
|
||||
const PaymentAsset({
|
||||
this.chain = ChainNetwork.unspecified,
|
||||
required this.tokenSymbol,
|
||||
this.contractAddress,
|
||||
});
|
||||
}
|
||||
1
frontend/pshared/lib/models/payment/chain_network.dart
Normal file
1
frontend/pshared/lib/models/payment/chain_network.dart
Normal file
@@ -0,0 +1 @@
|
||||
enum ChainNetwork { unspecified, ethereumMainnet, arbitrumOne, otherEvm }
|
||||
9
frontend/pshared/lib/models/payment/currency_pair.dart
Normal file
9
frontend/pshared/lib/models/payment/currency_pair.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
class CurrencyPair {
|
||||
final String base;
|
||||
final String quote;
|
||||
|
||||
const CurrencyPair({
|
||||
required this.base,
|
||||
required this.quote,
|
||||
});
|
||||
}
|
||||
18
frontend/pshared/lib/models/payment/fees/line.dart
Normal file
18
frontend/pshared/lib/models/payment/fees/line.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:pshared/models/payment/money.dart';
|
||||
|
||||
|
||||
class FeeLine {
|
||||
final String? ledgerAccountRef;
|
||||
final Money? amount;
|
||||
final String? lineType;
|
||||
final String? side;
|
||||
final Map<String, String>? meta;
|
||||
|
||||
const FeeLine({
|
||||
required this.ledgerAccountRef,
|
||||
required this.amount,
|
||||
required this.lineType,
|
||||
required this.side,
|
||||
required this.meta,
|
||||
});
|
||||
}
|
||||
12
frontend/pshared/lib/models/payment/fees/network.dart
Normal file
12
frontend/pshared/lib/models/payment/fees/network.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
import 'package:pshared/models/payment/money.dart';
|
||||
|
||||
|
||||
class NetworkFee {
|
||||
final Money? networkFee;
|
||||
final String? estimationContext;
|
||||
|
||||
const NetworkFee({
|
||||
required this.networkFee,
|
||||
required this.estimationContext,
|
||||
});
|
||||
}
|
||||
21
frontend/pshared/lib/models/payment/fx/intent.dart
Normal file
21
frontend/pshared/lib/models/payment/fx/intent.dart
Normal file
@@ -0,0 +1,21 @@
|
||||
import 'package:pshared/models/payment/currency_pair.dart';
|
||||
import 'package:pshared/models/payment/fx/side.dart';
|
||||
|
||||
|
||||
class FxIntent {
|
||||
final CurrencyPair? pair;
|
||||
final FxSide side;
|
||||
final bool firm;
|
||||
final int? ttlMs;
|
||||
final String? preferredProvider;
|
||||
final int? maxAgeMs;
|
||||
|
||||
const FxIntent({
|
||||
this.pair,
|
||||
this.side = FxSide.unspecified,
|
||||
this.firm = false,
|
||||
this.ttlMs,
|
||||
this.preferredProvider,
|
||||
this.maxAgeMs,
|
||||
});
|
||||
}
|
||||
30
frontend/pshared/lib/models/payment/fx/quote.dart
Normal file
30
frontend/pshared/lib/models/payment/fx/quote.dart
Normal file
@@ -0,0 +1,30 @@
|
||||
import 'package:pshared/models/payment/money.dart';
|
||||
|
||||
|
||||
class FxQuote {
|
||||
final String? quoteRef;
|
||||
final String? baseCurrency;
|
||||
final String? quoteCurrency;
|
||||
final String? side;
|
||||
final String? price;
|
||||
final Money? baseAmount;
|
||||
final Money? quoteAmount;
|
||||
final int? expiresAtUnixMs;
|
||||
final String? provider;
|
||||
final String? rateRef;
|
||||
final bool firm;
|
||||
|
||||
const FxQuote({
|
||||
required this.quoteRef,
|
||||
required this.baseCurrency,
|
||||
required this.quoteCurrency,
|
||||
required this.side,
|
||||
required this.price,
|
||||
required this.baseAmount,
|
||||
required this.quoteAmount,
|
||||
required this.expiresAtUnixMs,
|
||||
required this.provider,
|
||||
required this.rateRef,
|
||||
this.firm = false,
|
||||
});
|
||||
}
|
||||
1
frontend/pshared/lib/models/payment/fx/side.dart
Normal file
1
frontend/pshared/lib/models/payment/fx/side.dart
Normal file
@@ -0,0 +1 @@
|
||||
enum FxSide { unspecified, buyBaseSellQuote, sellBaseBuyQuote }
|
||||
@@ -0,0 +1,6 @@
|
||||
enum InsufficientNetPolicy {
|
||||
unspecified,
|
||||
blockPosting,
|
||||
sweepOrgCash,
|
||||
invoiceLater
|
||||
}
|
||||
26
frontend/pshared/lib/models/payment/intent.dart
Normal file
26
frontend/pshared/lib/models/payment/intent.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:pshared/models/payment/fx/intent.dart';
|
||||
import 'package:pshared/models/payment/kind.dart';
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/money.dart';
|
||||
import 'package:pshared/models/payment/settlement_mode.dart';
|
||||
|
||||
|
||||
class PaymentIntent {
|
||||
final PaymentKind kind;
|
||||
final PaymentMethodData? source;
|
||||
final PaymentMethodData? destination;
|
||||
final Money? amount;
|
||||
final FxIntent? fx;
|
||||
final SettlementMode settlementMode;
|
||||
final Map<String, String>? attributes;
|
||||
|
||||
const PaymentIntent({
|
||||
this.kind = PaymentKind.unspecified,
|
||||
this.source,
|
||||
this.destination,
|
||||
this.amount,
|
||||
this.fx,
|
||||
this.settlementMode = SettlementMode.unspecified,
|
||||
this.attributes,
|
||||
});
|
||||
}
|
||||
1
frontend/pshared/lib/models/payment/kind.dart
Normal file
1
frontend/pshared/lib/models/payment/kind.dart
Normal file
@@ -0,0 +1 @@
|
||||
enum PaymentKind { unspecified, payout, internalTransfer, fxConversion }
|
||||
@@ -2,17 +2,25 @@ import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class CardPaymentMethod extends PaymentMethodData {
|
||||
class CardPaymentMethod implements PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.card;
|
||||
|
||||
final String pan;
|
||||
final String firstName;
|
||||
final String lastName;
|
||||
final int? expMonth;
|
||||
final int? expYear;
|
||||
final String? country;
|
||||
@override
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
CardPaymentMethod({
|
||||
const CardPaymentMethod({
|
||||
required this.pan,
|
||||
this.expMonth,
|
||||
this.expYear,
|
||||
required this.firstName,
|
||||
required this.lastName,
|
||||
this.country,
|
||||
this.metadata,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
18
frontend/pshared/lib/models/payment/methods/card_token.dart
Normal file
18
frontend/pshared/lib/models/payment/methods/card_token.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class CardTokenPaymentMethod implements PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.cardToken;
|
||||
final String token;
|
||||
final String maskedPan;
|
||||
@override
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
const CardTokenPaymentMethod({
|
||||
required this.token,
|
||||
required this.maskedPan,
|
||||
this.metadata,
|
||||
});
|
||||
}
|
||||
@@ -1,18 +1,21 @@
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/asset.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class CryptoAddressPaymentMethod extends PaymentMethodData {
|
||||
class CryptoAddressPaymentMethod implements PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.cryptoAddress;
|
||||
|
||||
final PaymentType type = PaymentType.externalChain;
|
||||
final PaymentAsset? asset;
|
||||
final String address;
|
||||
final String network;
|
||||
final String? destinationTag;
|
||||
final String? memo;
|
||||
@override
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
CryptoAddressPaymentMethod({
|
||||
const CryptoAddressPaymentMethod({
|
||||
this.asset,
|
||||
required this.address,
|
||||
required this.network,
|
||||
this.destinationTag,
|
||||
this.memo,
|
||||
this.metadata,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
abstract class PaymentMethodData {
|
||||
PaymentType get type;
|
||||
Map<String, String>? get metadata;
|
||||
}
|
||||
|
||||
typedef MethodMap = Map<PaymentType, PaymentMethodData?>;
|
||||
@@ -2,7 +2,7 @@ import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class IbanPaymentMethod extends PaymentMethodData {
|
||||
class IbanPaymentMethod implements PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.iban;
|
||||
|
||||
@@ -10,11 +10,14 @@ class IbanPaymentMethod extends PaymentMethodData {
|
||||
final String accountHolder; // Full name of the recipient
|
||||
final String? bic; // Optional: for cross-border transfers
|
||||
final String? bankName; // Optional: for UI clarity
|
||||
@override
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
IbanPaymentMethod({
|
||||
const IbanPaymentMethod({
|
||||
required this.iban,
|
||||
required this.accountHolder,
|
||||
this.bic,
|
||||
this.bankName,
|
||||
this.metadata,
|
||||
});
|
||||
}
|
||||
|
||||
18
frontend/pshared/lib/models/payment/methods/ledger.dart
Normal file
18
frontend/pshared/lib/models/payment/methods/ledger.dart
Normal file
@@ -0,0 +1,18 @@
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class LedgerPaymentMethod implements PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.ledger;
|
||||
final String ledgerAccountRef;
|
||||
final String? contraLedgerAccountRef;
|
||||
@override
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
const LedgerPaymentMethod({
|
||||
required this.ledgerAccountRef,
|
||||
this.contraLedgerAccountRef,
|
||||
this.metadata,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/asset.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class ManagedWalletPaymentMethod implements PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.managedWallet;
|
||||
final String managedWalletRef;
|
||||
final PaymentAsset? asset;
|
||||
@override
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
const ManagedWalletPaymentMethod({
|
||||
required this.managedWalletRef,
|
||||
this.asset,
|
||||
this.metadata,
|
||||
});
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class RussianBankAccountPaymentMethod extends PaymentMethodData {
|
||||
class RussianBankAccountPaymentMethod implements PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.bankAccount;
|
||||
|
||||
@@ -13,8 +13,10 @@ class RussianBankAccountPaymentMethod extends PaymentMethodData {
|
||||
final String bik;
|
||||
final String accountNumber;
|
||||
final String correspondentAccount;
|
||||
@override
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
RussianBankAccountPaymentMethod({
|
||||
const RussianBankAccountPaymentMethod({
|
||||
required this.recipientName,
|
||||
required this.inn,
|
||||
required this.kpp,
|
||||
@@ -22,5 +24,6 @@ class RussianBankAccountPaymentMethod extends PaymentMethodData {
|
||||
required this.bik,
|
||||
required this.accountNumber,
|
||||
required this.correspondentAccount,
|
||||
this.metadata,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,11 +2,14 @@ import 'package:pshared/models/payment/methods/data.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
|
||||
class WalletPaymentMethod extends PaymentMethodData {
|
||||
class WalletPaymentMethod implements PaymentMethodData {
|
||||
@override
|
||||
final PaymentType type = PaymentType.wallet;
|
||||
|
||||
final String walletId;
|
||||
|
||||
WalletPaymentMethod({required this.walletId});
|
||||
@override
|
||||
final Map<String, String>? metadata;
|
||||
|
||||
WalletPaymentMethod({required this.walletId, this.metadata});
|
||||
}
|
||||
|
||||
9
frontend/pshared/lib/models/payment/money.dart
Normal file
9
frontend/pshared/lib/models/payment/money.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
class Money {
|
||||
final String amount;
|
||||
final String currency;
|
||||
|
||||
const Money({
|
||||
required this.amount,
|
||||
required this.currency,
|
||||
});
|
||||
}
|
||||
20
frontend/pshared/lib/models/payment/payment.dart
Normal file
20
frontend/pshared/lib/models/payment/payment.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:pshared/models/payment/quote.dart';
|
||||
|
||||
|
||||
class Payment {
|
||||
final String? paymentRef;
|
||||
final String? idempotencyKey;
|
||||
final String? state;
|
||||
final String? failureCode;
|
||||
final String? failureReason;
|
||||
final PaymentQuote? lastQuote;
|
||||
|
||||
const Payment({
|
||||
required this.paymentRef,
|
||||
required this.idempotencyKey,
|
||||
required this.state,
|
||||
required this.failureCode,
|
||||
required this.failureReason,
|
||||
required this.lastQuote,
|
||||
});
|
||||
}
|
||||
27
frontend/pshared/lib/models/payment/quote.dart
Normal file
27
frontend/pshared/lib/models/payment/quote.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:pshared/models/payment/fees/line.dart';
|
||||
import 'package:pshared/models/payment/fx/quote.dart';
|
||||
import 'package:pshared/models/payment/money.dart';
|
||||
import 'package:pshared/models/payment/fees/network.dart';
|
||||
|
||||
|
||||
class PaymentQuote {
|
||||
final String? quoteRef;
|
||||
final Money? debitAmount;
|
||||
final Money? expectedSettlementAmount;
|
||||
final Money? expectedFeeTotal;
|
||||
final String? feeQuoteToken;
|
||||
final List<FeeLine>? feeLines;
|
||||
final NetworkFee? networkFee;
|
||||
final FxQuote? fxQuote;
|
||||
|
||||
const PaymentQuote({
|
||||
required this.quoteRef,
|
||||
required this.debitAmount,
|
||||
required this.expectedSettlementAmount,
|
||||
required this.expectedFeeTotal,
|
||||
required this.feeQuoteToken,
|
||||
required this.feeLines,
|
||||
required this.networkFee,
|
||||
required this.fxQuote,
|
||||
});
|
||||
}
|
||||
1
frontend/pshared/lib/models/payment/settlement_mode.dart
Normal file
1
frontend/pshared/lib/models/payment/settlement_mode.dart
Normal file
@@ -0,0 +1 @@
|
||||
enum SettlementMode { unspecified, fixSource, fixReceived }
|
||||
@@ -1,7 +1,10 @@
|
||||
enum PaymentType {
|
||||
ledger,
|
||||
managedWallet,
|
||||
externalChain,
|
||||
bankAccount,
|
||||
iban,
|
||||
wallet,
|
||||
card,
|
||||
cryptoAddress,
|
||||
cardToken,
|
||||
}
|
||||
|
||||
54
frontend/pshared/lib/provider/payment/quotation.dart
Normal file
54
frontend/pshared/lib/provider/payment/quotation.dart
Normal file
@@ -0,0 +1,54 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/api/requests/payment/quote.dart';
|
||||
import 'package:pshared/data/mapper/payment/intent/payment.dart';
|
||||
import 'package:pshared/models/payment/intent.dart';
|
||||
import 'package:pshared/models/payment/quote.dart';
|
||||
import 'package:pshared/provider/organizations.dart';
|
||||
import 'package:pshared/provider/resource.dart';
|
||||
import 'package:pshared/service/payment/quotation.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
|
||||
class QuotationProvider extends ChangeNotifier {
|
||||
Resource<PaymentQuote> _quotation = Resource(data: null, isLoading: false, error: null);
|
||||
late OrganizationsProvider _organizations;
|
||||
bool _isLoaded = false;
|
||||
|
||||
void update(OrganizationsProvider venue) {
|
||||
_organizations = venue;
|
||||
}
|
||||
|
||||
PaymentQuote? get quotation => _quotation.data;
|
||||
|
||||
bool get isReady => _isLoaded && !_quotation.isLoading && _quotation.error == null;
|
||||
|
||||
Future<PaymentQuote?> getQuotation(PaymentIntent intent) async {
|
||||
if (!_organizations.isOrganizationSet) throw StateError('Organization is not set');
|
||||
try {
|
||||
_quotation = _quotation.copyWith(isLoading: true, error: null);
|
||||
final response = await QuotationService.getQuotation(
|
||||
_organizations.current.id,
|
||||
QuotePaymentRequest(
|
||||
idempotencyKey: Uuid().v4(),
|
||||
intent: intent.toDTO(),
|
||||
),
|
||||
);
|
||||
_isLoaded = true;
|
||||
_quotation = _quotation.copyWith(data: response, isLoading: false);
|
||||
} catch (e) {
|
||||
_quotation = _quotation.copyWith(
|
||||
error: e is Exception ? e : Exception(e.toString()),
|
||||
isLoading: false,
|
||||
);
|
||||
}
|
||||
notifyListeners();
|
||||
return _quotation.data;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
_quotation = Resource(data: null, isLoading: false, error: null);
|
||||
_isLoaded = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
20
frontend/pshared/lib/service/payment/quotation.dart
Normal file
20
frontend/pshared/lib/service/payment/quotation.dart
Normal file
@@ -0,0 +1,20 @@
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/api/requests/payment/quote.dart';
|
||||
import 'package:pshared/api/responses/payment/quotation.dart';
|
||||
import 'package:pshared/data/mapper/payment/payment_quote.dart';
|
||||
import 'package:pshared/models/payment/quote.dart';
|
||||
import 'package:pshared/service/services.dart';
|
||||
import 'package:pshared/utils/http/requests.dart';
|
||||
|
||||
|
||||
class QuotationService {
|
||||
static final _logger = Logger('service.payment.quotation');
|
||||
static const String _objectType = Services.payments;
|
||||
|
||||
static Future<PaymentQuote> getQuotation(String organizationRef, QuotePaymentRequest request) async {
|
||||
_logger.fine('Quoting payment for organization $organizationRef');
|
||||
final response = await getPOSTResponse(_objectType, '/quote/$organizationRef', request.toJson());
|
||||
return PaymentQuoteResponse.fromJson(response).quote.toDomain();
|
||||
}
|
||||
}
|
||||
@@ -11,8 +11,8 @@ class Services {
|
||||
|
||||
static const String recipients = 'recipients';
|
||||
static const String paymentMethods = 'payment_methods';
|
||||
static const String payments = 'payments';
|
||||
|
||||
static const String amplitude = 'amplitude';
|
||||
static const String clients = 'clients';
|
||||
static const String logo = 'logo';
|
||||
static const String notifications = 'notifications';
|
||||
|
||||
22
frontend/pshared/lib/utils/l10n/chain.dart
Normal file
22
frontend/pshared/lib/utils/l10n/chain.dart
Normal file
@@ -0,0 +1,22 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:pshared/generated/i18n/ps_localizations.dart';
|
||||
import 'package:pshared/models/payment/chain_network.dart';
|
||||
|
||||
/// Localized labels for [ChainNetwork] values.
|
||||
extension ChainNetworkL10n on ChainNetwork {
|
||||
/// Returns a human-readable, localized name for the chain.
|
||||
String localizedName(BuildContext context) {
|
||||
final l10n = PSLocalizations.of(context)!;
|
||||
switch (this) {
|
||||
case ChainNetwork.ethereumMainnet:
|
||||
return l10n.chainNetworkEthereumMainnet;
|
||||
case ChainNetwork.arbitrumOne:
|
||||
return l10n.chainNetworkArbitrumOne;
|
||||
case ChainNetwork.otherEvm:
|
||||
return l10n.chainNetworkOtherEvm;
|
||||
case ChainNetwork.unspecified:
|
||||
return l10n.chainNetworkUnspecified;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
import 'package:pweb/widgets/sidebar/destinations.dart';
|
||||
@@ -92,8 +94,6 @@ class PayoutRoutes {
|
||||
return PayoutDestination.recipients;
|
||||
case addRecipient:
|
||||
return PayoutDestination.addrecipient;
|
||||
case payment:
|
||||
return PayoutDestination.payment;
|
||||
case settings:
|
||||
return PayoutDestination.settings;
|
||||
case reports:
|
||||
|
||||
@@ -312,6 +312,16 @@
|
||||
"paymentTypeIban": "IBAN",
|
||||
"paymentTypeWallet": "Wallet",
|
||||
"paymentTypeCryptoAddress": "Crypto address",
|
||||
"paymentTypeLedger": "Ledger account",
|
||||
"paymentTypeManagedWallet": "Managed wallet",
|
||||
"paymentTypeCardToken": "Card token",
|
||||
|
||||
"cryptoAddressLabel": "Crypto address",
|
||||
"enterCryptoAddress": "Enter a crypto address",
|
||||
"tokenSymbolLabel": "Token symbol",
|
||||
"tokenSymbolRequiredWhenNetwork": "Token symbol is required when a network or contract address is specified",
|
||||
"contractAddressLabel": "Contract address (optional)",
|
||||
"memoLabel": "Destination tag / memo (optional)",
|
||||
|
||||
"cardNumber": "Card Number",
|
||||
"enterCardNumber": "Enter the card number",
|
||||
|
||||
@@ -312,6 +312,16 @@
|
||||
"paymentTypeIban": "IBAN",
|
||||
"paymentTypeWallet": "Кошелек",
|
||||
"paymentTypeCryptoAddress": "Крипто-адрес",
|
||||
"paymentTypeLedger": "Леджер счет",
|
||||
"paymentTypeManagedWallet": "Управляемый кошелек",
|
||||
"paymentTypeCardToken": "Токен карты",
|
||||
|
||||
"cryptoAddressLabel": "Крипто-адрес",
|
||||
"enterCryptoAddress": "Введите крипто-адрес",
|
||||
"tokenSymbolLabel": "Символ токена",
|
||||
"tokenSymbolRequiredWhenNetwork": "Укажите символ токена, если выбрана сеть или указан адрес контракта",
|
||||
"contractAddressLabel": "Адрес контракта (необязательно)",
|
||||
"memoLabel": "Destination tag / memo (необязательно)",
|
||||
|
||||
"cardNumber": "Номер карты",
|
||||
"enterCardNumber": "Введите номер карты",
|
||||
|
||||
@@ -12,6 +12,7 @@ import 'package:pshared/provider/locale.dart';
|
||||
import 'package:pshared/provider/permissions.dart';
|
||||
import 'package:pshared/provider/account.dart';
|
||||
import 'package:pshared/provider/organizations.dart';
|
||||
import 'package:pshared/provider/payment/quotation.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
import 'package:pshared/provider/recipient/pmethods.dart';
|
||||
|
||||
@@ -24,7 +25,6 @@ import 'package:pweb/providers/two_factor.dart';
|
||||
import 'package:pweb/providers/upload_history.dart';
|
||||
import 'package:pweb/providers/wallets.dart';
|
||||
import 'package:pweb/providers/wallet_transactions.dart';
|
||||
// import 'package:pweb/services/amplitude.dart';
|
||||
import 'package:pweb/services/operations.dart';
|
||||
import 'package:pweb/services/payments/history.dart';
|
||||
import 'package:pweb/services/wallet_transactions.dart';
|
||||
@@ -70,7 +70,6 @@ void main() async {
|
||||
update: (context, orgnization, provider) => provider!..update(orgnization),
|
||||
),
|
||||
ChangeNotifierProvider(create: (_) => CarouselIndexProvider()),
|
||||
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => UploadHistoryProvider(service: MockUploadHistoryService())..load(),
|
||||
),
|
||||
@@ -92,10 +91,13 @@ void main() async {
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => MockPaymentProvider(),
|
||||
),
|
||||
|
||||
ChangeNotifierProvider(
|
||||
create: (_) => OperationProvider(OperationService())..loadOperations(),
|
||||
),
|
||||
ChangeNotifierProxyProvider<OrganizationsProvider, QuotationProvider>(
|
||||
create: (_) => QuotationProvider(),
|
||||
update: (context, orgnization, provider) => provider!..update(orgnization),
|
||||
),
|
||||
],
|
||||
child: const PayApp(),
|
||||
),
|
||||
|
||||
@@ -14,7 +14,6 @@ import 'package:pshared/provider/recipient/pmethods.dart';
|
||||
import 'package:pshared/provider/recipient/provider.dart';
|
||||
|
||||
import 'package:pweb/pages/address_book/form/view.dart';
|
||||
// import 'package:pweb/services/amplitude.dart';
|
||||
import 'package:pweb/utils/error/snackbar.dart';
|
||||
import 'package:pweb/utils/payment/label.dart';
|
||||
import 'package:pweb/utils/snackbar.dart';
|
||||
@@ -54,7 +53,9 @@ class _AdressBookRecipientFormState extends State<AdressBookRecipientForm> {
|
||||
PaymentType.iban => m.ibanData,
|
||||
PaymentType.wallet => m.walletData,
|
||||
PaymentType.bankAccount => m.bankAccountData,
|
||||
PaymentType.cryptoAddress => m.cryptoAddressData,
|
||||
PaymentType.externalChain => m.cryptoAddressData,
|
||||
//TODO: support new payment methods
|
||||
_ => throw UnimplementedError('Payment method ${m.type} is not supported yet'),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/asset.dart';
|
||||
import 'package:pshared/models/payment/chain_network.dart';
|
||||
import 'package:pshared/models/payment/methods/crypto_address.dart';
|
||||
import 'package:pshared/utils/l10n/chain.dart';
|
||||
|
||||
import 'package:pweb/utils/text_field_styles.dart';
|
||||
|
||||
import 'package:pweb/generated/i18n/app_localizations.dart';
|
||||
|
||||
|
||||
class CryptoAddressForm extends StatefulWidget {
|
||||
final void Function(CryptoAddressPaymentMethod) onChanged;
|
||||
@@ -22,28 +27,67 @@ class CryptoAddressForm extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CryptoAddressFormState extends State<CryptoAddressForm> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
late TextEditingController _addressCtrl;
|
||||
late TextEditingController _networkCtrl;
|
||||
late TextEditingController _destinationTagCtrl;
|
||||
late TextEditingController _tokenCtrl;
|
||||
late TextEditingController _contractCtrl;
|
||||
late TextEditingController _memoCtrl;
|
||||
late ChainNetwork _chain;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_addressCtrl = TextEditingController(text: widget.initialData?.address);
|
||||
_networkCtrl = TextEditingController(text: widget.initialData?.network);
|
||||
_destinationTagCtrl = TextEditingController(text: widget.initialData?.destinationTag);
|
||||
final initial = widget.initialData;
|
||||
_chain = initial?.asset?.chain ?? ChainNetwork.unspecified;
|
||||
_addressCtrl = TextEditingController(text: initial?.address ?? '');
|
||||
_tokenCtrl = TextEditingController(text: initial?.asset?.tokenSymbol ?? '');
|
||||
_contractCtrl = TextEditingController(text: initial?.asset?.contractAddress ?? '');
|
||||
_memoCtrl = TextEditingController(text: initial?.memo ?? '');
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||
}
|
||||
|
||||
void _emit() {
|
||||
if (_addressCtrl.text.isNotEmpty && _networkCtrl.text.isNotEmpty) {
|
||||
widget.onChanged(
|
||||
CryptoAddressPaymentMethod(
|
||||
address: _addressCtrl.text,
|
||||
network: _networkCtrl.text,
|
||||
destinationTag: _destinationTagCtrl.text.isNotEmpty ? _destinationTagCtrl.text : null,
|
||||
),
|
||||
);
|
||||
bool get _hasChainSelection => _chain != ChainNetwork.unspecified;
|
||||
|
||||
String? _validateAddress(AppLocalizations l10n, String? value) {
|
||||
if (value == null || value.trim().isEmpty) return l10n.enterCryptoAddress;
|
||||
return null;
|
||||
}
|
||||
|
||||
String? _validateToken(AppLocalizations l10n) {
|
||||
final token = _tokenCtrl.text.trim();
|
||||
final contract = _contractCtrl.text.trim();
|
||||
if ((_hasChainSelection || contract.isNotEmpty) && token.isEmpty) {
|
||||
return l10n.tokenSymbolRequiredWhenNetwork;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
PaymentAsset? _buildAsset() {
|
||||
final token = _tokenCtrl.text.trim();
|
||||
final contract = _contractCtrl.text.trim();
|
||||
|
||||
if (token.isEmpty && contract.isEmpty && !_hasChainSelection) return null;
|
||||
if (token.isEmpty) return null;
|
||||
|
||||
return PaymentAsset(
|
||||
chain: _chain,
|
||||
tokenSymbol: token,
|
||||
contractAddress: contract.isNotEmpty ? contract : null,
|
||||
);
|
||||
}
|
||||
|
||||
void _emitIfValid() {
|
||||
if (!(_formKey.currentState?.validate() ?? false)) return;
|
||||
|
||||
widget.onChanged(
|
||||
CryptoAddressPaymentMethod(
|
||||
asset: _buildAsset(),
|
||||
address: _addressCtrl.text.trim(),
|
||||
memo: _memoCtrl.text.trim().isNotEmpty ? _memoCtrl.text.trim() : null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -54,48 +98,88 @@ class _CryptoAddressFormState extends State<CryptoAddressForm> {
|
||||
|
||||
if (newData == null && oldData != null) {
|
||||
_addressCtrl.clear();
|
||||
_networkCtrl.clear();
|
||||
_destinationTagCtrl.clear();
|
||||
_tokenCtrl.clear();
|
||||
_contractCtrl.clear();
|
||||
_memoCtrl.clear();
|
||||
_chain = ChainNetwork.unspecified;
|
||||
return;
|
||||
}
|
||||
|
||||
if (newData != null && newData != oldData) {
|
||||
_addressCtrl.text = newData.address;
|
||||
_networkCtrl.text = newData.network;
|
||||
_destinationTagCtrl.text = newData.destinationTag ?? '';
|
||||
_tokenCtrl.text = newData.asset?.tokenSymbol ?? '';
|
||||
_contractCtrl.text = newData.asset?.contractAddress ?? '';
|
||||
_memoCtrl.text = newData.memo ?? '';
|
||||
_chain = newData.asset?.chain ?? ChainNetwork.unspecified;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _emitIfValid());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _addressCtrl,
|
||||
decoration: getInputDecoration(context, 'Crypto address', widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
onChanged: (_) => _emit(),
|
||||
validator: (val) => (val?.isEmpty ?? true) ? 'Enter crypto address' : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _networkCtrl,
|
||||
decoration: getInputDecoration(context, 'Network', widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
onChanged: (_) => _emit(),
|
||||
validator: (val) => (val?.isEmpty ?? true) ? 'Enter network' : null,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _destinationTagCtrl,
|
||||
decoration: getInputDecoration(context, 'Destination tag / memo (optional)', widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
onChanged: (_) => _emit(),
|
||||
),
|
||||
],
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
|
||||
return Form(
|
||||
key: _formKey,
|
||||
onChanged: _emitIfValid,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
spacing: 12.0,
|
||||
children: [
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _addressCtrl,
|
||||
decoration: getInputDecoration(context, l10n.cryptoAddressLabel, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (val) => _validateAddress(l10n, val),
|
||||
),
|
||||
DropdownButtonFormField<ChainNetwork>(
|
||||
initialValue: _chain,
|
||||
decoration: getInputDecoration(context, l10n.walletTopUpNetworkLabel, widget.isEditable),
|
||||
items: ChainNetwork.values
|
||||
.map((chain) => DropdownMenuItem(
|
||||
value: chain,
|
||||
child: Text(chain.localizedName(context)),
|
||||
))
|
||||
.toList(),
|
||||
onChanged: widget.isEditable
|
||||
? (value) {
|
||||
if (value == null) return;
|
||||
setState(() => _chain = value);
|
||||
_emitIfValid();
|
||||
}
|
||||
: null,
|
||||
),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _tokenCtrl,
|
||||
decoration: getInputDecoration(context, l10n.tokenSymbolLabel, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
validator: (_) => _validateToken(l10n),
|
||||
),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _contractCtrl,
|
||||
decoration: getInputDecoration(context, l10n.contractAddressLabel, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
),
|
||||
TextFormField(
|
||||
readOnly: !widget.isEditable,
|
||||
controller: _memoCtrl,
|
||||
decoration: getInputDecoration(context, l10n.memoLabel, widget.isEditable),
|
||||
style: getTextFieldStyle(context, widget.isEditable),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_addressCtrl.dispose();
|
||||
_tokenCtrl.dispose();
|
||||
_contractCtrl.dispose();
|
||||
_memoCtrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ class PaymentMethodForm extends StatelessWidget {
|
||||
initialData: initialData as RussianBankAccountPaymentMethod?,
|
||||
isEditable: isEditable,
|
||||
),
|
||||
PaymentType.cryptoAddress => CryptoAddressForm(
|
||||
PaymentType.externalChain => CryptoAddressForm(
|
||||
onChanged: onChanged,
|
||||
initialData: initialData as CryptoAddressPaymentMethod?,
|
||||
isEditable: isEditable,
|
||||
|
||||
@@ -13,7 +13,10 @@ IconData iconForPaymentType(PaymentType type) {
|
||||
return Icons.account_balance_wallet;
|
||||
case PaymentType.card:
|
||||
return Icons.credit_card;
|
||||
case PaymentType.cryptoAddress:
|
||||
case PaymentType.externalChain:
|
||||
return Icons.currency_bitcoin;
|
||||
//TODO: define new payment methods
|
||||
default:
|
||||
return Icons.question_mark;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'package:pshared/models/payment/methods/card_token.dart';
|
||||
import 'package:pshared/models/payment/methods/ledger.dart';
|
||||
import 'package:pshared/models/payment/methods/managed_wallet.dart';
|
||||
import 'package:pshared/models/payment/methods/type.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
|
||||
@@ -12,21 +15,31 @@ String getPaymentTypeLabel(BuildContext context, PaymentType type) {
|
||||
final l10n = AppLocalizations.of(context)!;
|
||||
return switch (type) {
|
||||
PaymentType.card => l10n.paymentTypeCard,
|
||||
PaymentType.cardToken => l10n.paymentTypeCardToken,
|
||||
PaymentType.bankAccount => l10n.paymentTypeBankAccount,
|
||||
PaymentType.iban => l10n.paymentTypeIban,
|
||||
PaymentType.wallet => l10n.paymentTypeWallet,
|
||||
PaymentType.cryptoAddress => l10n.paymentTypeCryptoAddress,
|
||||
PaymentType.managedWallet => l10n.paymentTypeManagedWallet,
|
||||
PaymentType.externalChain => l10n.paymentTypeCryptoAddress,
|
||||
PaymentType.ledger => l10n.paymentTypeLedger,
|
||||
};
|
||||
}
|
||||
|
||||
String? _displayString(PaymentMethod m) => switch (m.type) {
|
||||
PaymentType.card => maskCardNumber(m.cardData?.pan),
|
||||
PaymentType.cardToken => m.dataAsOrNull<CardTokenPaymentMethod>()?.maskedPan,
|
||||
PaymentType.bankAccount => m.bankAccountData?.accountNumber,
|
||||
PaymentType.iban => m.ibanData?.iban,
|
||||
PaymentType.wallet => m.walletData?.walletId,
|
||||
PaymentType.cryptoAddress => m.cryptoAddressData?.address,
|
||||
PaymentType.managedWallet => () {
|
||||
final data = m.dataAsOrNull<ManagedWalletPaymentMethod>();
|
||||
if (data == null) return null;
|
||||
return data.asset?.tokenSymbol ?? data.managedWalletRef;
|
||||
}(),
|
||||
PaymentType.externalChain => m.cryptoAddressData?.address,
|
||||
PaymentType.ledger => m.dataAsOrNull<LedgerPaymentMethod>()?.ledgerAccountRef,
|
||||
};
|
||||
|
||||
String getPaymentTypeDescription(BuildContext context, PaymentMethod m) {
|
||||
return _displayString(m) ?? AppLocalizations.of(context)!.notSet;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user