added wallet source to quotation preparation
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import 'package:pshared/data/dto/wallet/asset.dart';
|
||||
import 'package:pshared/data/mapper/payment/enums.dart';
|
||||
import 'package:pshared/models/wallet/wallet.dart';
|
||||
import 'package:pshared/models/wallet/asset.dart';
|
||||
|
||||
|
||||
extension WalletAssetDTOMapper on WalletAssetDTO {
|
||||
|
||||
26
frontend/pshared/lib/data/mapper/wallet/ui.dart
Normal file
26
frontend/pshared/lib/data/mapper/wallet/ui.dart
Normal file
@@ -0,0 +1,26 @@
|
||||
import 'package:pshared/models/currency.dart';
|
||||
import 'package:pshared/models/wallet/wallet.dart' as domain;
|
||||
import 'package:pshared/models/payment/wallet.dart';
|
||||
import 'package:pshared/utils/currency.dart';
|
||||
|
||||
|
||||
extension WalletUiMapper on domain.WalletModel {
|
||||
Wallet toUi() {
|
||||
final amountStr = availableMoney?.amount ?? balance?.available?.amount ?? '0';
|
||||
final parsedAmount = double.tryParse(amountStr) ?? 0;
|
||||
final currency = currencyStringToCode(asset.tokenSymbol);
|
||||
return Wallet(
|
||||
id: walletRef,
|
||||
walletUserID: walletRef,
|
||||
balance: parsedAmount,
|
||||
currency: currency,
|
||||
isHidden: true,
|
||||
calculatedAt: balance?.calculatedAt ?? DateTime.now(),
|
||||
depositAddress: depositAddress,
|
||||
network: asset.chain,
|
||||
tokenSymbol: asset.tokenSymbol,
|
||||
contractAddress: asset.contractAddress,
|
||||
describable: describable,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import 'package:pshared/models/payment/methods/card.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/managed_wallet.dart';
|
||||
import 'package:pshared/models/payment/methods/russian_bank.dart';
|
||||
import 'package:pshared/models/payment/methods/wallet.dart';
|
||||
import 'package:pshared/models/payment/type.dart';
|
||||
@@ -43,6 +44,7 @@ class PaymentMethod implements PermissionBoundStorable, Describable {
|
||||
IbanPaymentMethod? get ibanData => dataAsOrNull<IbanPaymentMethod>();
|
||||
RussianBankAccountPaymentMethod? get bankAccountData => dataAsOrNull<RussianBankAccountPaymentMethod>();
|
||||
WalletPaymentMethod? get walletData => dataAsOrNull<WalletPaymentMethod>();
|
||||
ManagedWalletPaymentMethod? get managedWalletData => dataAsOrNull<ManagedWalletPaymentMethod>();
|
||||
CryptoAddressPaymentMethod? get cryptoAddressData => dataAsOrNull<CryptoAddressPaymentMethod>();
|
||||
|
||||
@override
|
||||
|
||||
68
frontend/pshared/lib/models/payment/wallet.dart
Normal file
68
frontend/pshared/lib/models/payment/wallet.dart
Normal file
@@ -0,0 +1,68 @@
|
||||
import 'package:pshared/models/currency.dart';
|
||||
import 'package:pshared/models/describable.dart';
|
||||
import 'package:pshared/models/payment/chain_network.dart';
|
||||
|
||||
|
||||
class Wallet implements Describable {
|
||||
final String id;
|
||||
final String walletUserID; // ID or number that we show the user
|
||||
final double balance;
|
||||
final Currency currency;
|
||||
final bool isHidden;
|
||||
final DateTime calculatedAt;
|
||||
final String? depositAddress;
|
||||
final ChainNetwork? network;
|
||||
final String? tokenSymbol;
|
||||
final String? contractAddress;
|
||||
final Describable describable;
|
||||
|
||||
@override
|
||||
String get name => describable.name;
|
||||
|
||||
@override
|
||||
String? get description => describable.description;
|
||||
|
||||
Wallet({
|
||||
required this.id,
|
||||
required this.walletUserID,
|
||||
required this.balance,
|
||||
required this.currency,
|
||||
required this.calculatedAt,
|
||||
required this.describable,
|
||||
this.isHidden = true,
|
||||
this.depositAddress,
|
||||
this.network,
|
||||
this.tokenSymbol,
|
||||
this.contractAddress,
|
||||
});
|
||||
|
||||
Wallet copyWith({
|
||||
String? id,
|
||||
double? balance,
|
||||
Currency? currency,
|
||||
String? walletUserID,
|
||||
bool? isHidden,
|
||||
String? depositAddress,
|
||||
ChainNetwork? network,
|
||||
String? tokenSymbol,
|
||||
String? contractAddress,
|
||||
Describable? describable,
|
||||
String? name,
|
||||
String? Function()? description,
|
||||
}) => Wallet(
|
||||
id: id ?? this.id,
|
||||
balance: balance ?? this.balance,
|
||||
currency: currency ?? this.currency,
|
||||
walletUserID: walletUserID ?? this.walletUserID,
|
||||
isHidden: isHidden ?? this.isHidden,
|
||||
calculatedAt: calculatedAt,
|
||||
depositAddress: depositAddress ?? this.depositAddress,
|
||||
network: network ?? this.network,
|
||||
tokenSymbol: tokenSymbol ?? this.tokenSymbol,
|
||||
contractAddress: contractAddress ?? this.contractAddress,
|
||||
describable: describable
|
||||
?? (name != null || description != null
|
||||
? this.describable.copyWith(name: name, description: description)
|
||||
: this.describable),
|
||||
);
|
||||
}
|
||||
14
frontend/pshared/lib/models/wallet/asset.dart
Normal file
14
frontend/pshared/lib/models/wallet/asset.dart
Normal file
@@ -0,0 +1,14 @@
|
||||
import 'package:pshared/models/payment/chain_network.dart';
|
||||
|
||||
|
||||
class WalletAsset {
|
||||
final ChainNetwork chain;
|
||||
final String tokenSymbol;
|
||||
final String contractAddress;
|
||||
|
||||
const WalletAsset({
|
||||
required this.chain,
|
||||
required this.tokenSymbol,
|
||||
required this.contractAddress,
|
||||
});
|
||||
}
|
||||
@@ -1,21 +1,9 @@
|
||||
import 'package:pshared/models/describable.dart';
|
||||
import 'package:pshared/models/payment/chain_network.dart';
|
||||
import 'package:pshared/models/wallet/asset.dart';
|
||||
import 'package:pshared/models/wallet/balance.dart';
|
||||
import 'package:pshared/models/wallet/money.dart';
|
||||
|
||||
|
||||
class WalletAsset {
|
||||
final ChainNetwork chain;
|
||||
final String tokenSymbol;
|
||||
final String contractAddress;
|
||||
|
||||
const WalletAsset({
|
||||
required this.chain,
|
||||
required this.tokenSymbol,
|
||||
required this.contractAddress,
|
||||
});
|
||||
}
|
||||
|
||||
class WalletModel implements Describable {
|
||||
final String walletRef;
|
||||
final String organizationRef;
|
||||
@@ -55,20 +43,18 @@ class WalletModel implements Describable {
|
||||
WalletBalance? balance,
|
||||
WalletMoney? availableMoney,
|
||||
Describable? describable,
|
||||
}) {
|
||||
return WalletModel(
|
||||
walletRef: walletRef,
|
||||
organizationRef: organizationRef,
|
||||
ownerRef: ownerRef,
|
||||
asset: asset,
|
||||
depositAddress: depositAddress,
|
||||
status: status,
|
||||
metadata: metadata,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
balance: balance ?? this.balance,
|
||||
availableMoney: availableMoney ?? this.availableMoney,
|
||||
describable: describable ?? this.describable,
|
||||
);
|
||||
}
|
||||
}) => WalletModel(
|
||||
walletRef: walletRef,
|
||||
organizationRef: organizationRef,
|
||||
ownerRef: ownerRef,
|
||||
asset: asset,
|
||||
depositAddress: depositAddress,
|
||||
status: status,
|
||||
metadata: metadata,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
balance: balance ?? this.balance,
|
||||
availableMoney: availableMoney ?? this.availableMoney,
|
||||
describable: describable ?? this.describable,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:pshared/models/asset.dart';
|
||||
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'package:pshared/api/requests/payment/quote.dart';
|
||||
import 'package:pshared/data/mapper/payment/intent/payment.dart';
|
||||
import 'package:pshared/models/asset.dart';
|
||||
import 'package:pshared/models/payment/currency_pair.dart';
|
||||
import 'package:pshared/models/payment/fx/intent.dart';
|
||||
import 'package:pshared/models/payment/fx/side.dart';
|
||||
@@ -11,14 +13,14 @@ import 'package:pshared/models/payment/methods/card.dart';
|
||||
import 'package:pshared/models/payment/methods/managed_wallet.dart';
|
||||
import 'package:pshared/models/payment/money.dart';
|
||||
import 'package:pshared/models/payment/settlement_mode.dart';
|
||||
import 'package:pshared/provider/payment/amount.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/payment/amount.dart';
|
||||
import 'package:pshared/provider/payment/wallets.dart';
|
||||
import 'package:pshared/provider/resource.dart';
|
||||
import 'package:pshared/service/payment/quotation.dart';
|
||||
import 'package:pshared/utils/currency.dart';
|
||||
|
||||
|
||||
class QuotationProvider extends ChangeNotifier {
|
||||
@@ -26,31 +28,38 @@ class QuotationProvider extends ChangeNotifier {
|
||||
late OrganizationsProvider _organizations;
|
||||
bool _isLoaded = false;
|
||||
|
||||
void update(OrganizationsProvider venue, PaymentAmountProvider payment) {
|
||||
void update(
|
||||
OrganizationsProvider venue,
|
||||
PaymentAmountProvider payment,
|
||||
WalletsProvider wallets,
|
||||
) {
|
||||
_organizations = venue;
|
||||
getQuotation(PaymentIntent(
|
||||
kind: PaymentKind.payout,
|
||||
amount: Money(
|
||||
amount: payment.amount.toString(),
|
||||
currency: 'USDT',
|
||||
),
|
||||
destination: CardPaymentMethod(
|
||||
pan: '4000000000000077',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
),
|
||||
source: ManagedWalletPaymentMethod(
|
||||
managedWalletRef: '',
|
||||
),
|
||||
fx: FxIntent(
|
||||
pair: CurrencyPair(
|
||||
base: 'USDT',
|
||||
quote: 'RUB',
|
||||
if (wallets.selectedWallet != null) {
|
||||
getQuotation(PaymentIntent(
|
||||
kind: PaymentKind.payout,
|
||||
amount: Money(
|
||||
amount: payment.amount.toString(),
|
||||
// TODO: adapt to possible other sources
|
||||
currency: currencyCodeToString(wallets.selectedWallet!.currency),
|
||||
),
|
||||
side: FxSide.sellBaseBuyQuote,
|
||||
),
|
||||
settlementMode: payment.payerCoversFee ? SettlementMode.fixReceived : SettlementMode.fixSource,
|
||||
));
|
||||
destination: CardPaymentMethod(
|
||||
pan: '4000000000000077',
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
),
|
||||
source: ManagedWalletPaymentMethod(
|
||||
managedWalletRef: wallets.selectedWallet!.id,
|
||||
),
|
||||
fx: FxIntent(
|
||||
pair: CurrencyPair(
|
||||
base: currencyCodeToString(wallets.selectedWallet!.currency),
|
||||
quote: 'RUB',
|
||||
),
|
||||
side: FxSide.sellBaseBuyQuote,
|
||||
),
|
||||
settlementMode: payment.payerCoversFee ? SettlementMode.fixReceived : SettlementMode.fixSource,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
PaymentQuote? get quotation => _quotation.data;
|
||||
|
||||
103
frontend/pshared/lib/provider/payment/wallets.dart
Normal file
103
frontend/pshared/lib/provider/payment/wallets.dart
Normal file
@@ -0,0 +1,103 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:pshared/models/payment/wallet.dart';
|
||||
import 'package:pshared/provider/organizations.dart';
|
||||
import 'package:pshared/provider/resource.dart';
|
||||
import 'package:pshared/service/payment/wallets.dart';
|
||||
import 'package:pshared/utils/exception.dart';
|
||||
|
||||
|
||||
|
||||
class WalletsProvider with ChangeNotifier {
|
||||
final WalletsService _service;
|
||||
late OrganizationsProvider _organizations;
|
||||
|
||||
WalletsProvider(this._service);
|
||||
|
||||
Resource<List<Wallet>> _resource = Resource(data: []);
|
||||
Resource<List<Wallet>> get resource => _resource;
|
||||
|
||||
List<Wallet> get wallets => _resource.data ?? [];
|
||||
bool get isLoading => _resource.isLoading;
|
||||
Exception? get error => _resource.error;
|
||||
|
||||
Wallet? _selectedWallet;
|
||||
Wallet? get selectedWallet => _selectedWallet;
|
||||
final bool _isHidden = true;
|
||||
bool get isHidden => _isHidden;
|
||||
|
||||
bool _isRefreshingBalances = false;
|
||||
bool get isRefreshingBalances => _isRefreshingBalances;
|
||||
|
||||
void update(OrganizationsProvider organizations) {
|
||||
_organizations = organizations;
|
||||
if (_organizations.isOrganizationSet) loadWalletsWithBalances();
|
||||
}
|
||||
|
||||
Future<Wallet> updateWallet(Wallet newWallet) {
|
||||
throw Exception('update wallet is not implemented');
|
||||
}
|
||||
|
||||
void selectWallet(Wallet wallet) {
|
||||
_selectedWallet = wallet;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Future<void> loadWalletsWithBalances() async {
|
||||
_setResource(_resource.copyWith(isLoading: true, error: null));
|
||||
try {
|
||||
final base = await _service.getWallets(_organizations.current.id);
|
||||
final withBalances = <Wallet>[];
|
||||
for (final wallet in base) {
|
||||
try {
|
||||
final balance = await _service.getBalance(_organizations.current.id, wallet.id);
|
||||
withBalances.add(wallet.copyWith(balance: balance));
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(error: toException(e)));
|
||||
withBalances.add(wallet);
|
||||
}
|
||||
}
|
||||
_setResource(Resource(data: withBalances, isLoading: false, error: _resource.error));
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> refreshBalances() async {
|
||||
if (wallets.isEmpty) return;
|
||||
_isRefreshingBalances = true;
|
||||
notifyListeners();
|
||||
|
||||
try {
|
||||
final updated = <Wallet>[];
|
||||
for (final wallet in wallets) {
|
||||
final balance = await _service.getBalance(_organizations.current.id, wallet.id);
|
||||
updated.add(wallet.copyWith(balance: balance));
|
||||
}
|
||||
_setResource(_resource.copyWith(data: updated));
|
||||
} catch (e) {
|
||||
_setResource(_resource.copyWith(error: toException(e)));
|
||||
} finally {
|
||||
_isRefreshingBalances = false;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void toggleVisibility(String walletId) {
|
||||
final index = wallets.indexWhere((w) => w.id == walletId);
|
||||
if (index < 0) return;
|
||||
final wallet = wallets[index];
|
||||
final updated = wallet.copyWith(isHidden: !wallet.isHidden);
|
||||
final next = List<Wallet>.from(wallets);
|
||||
next[index] = updated;
|
||||
_setResource(_resource.copyWith(data: next));
|
||||
if (_selectedWallet?.id == walletId) {
|
||||
_selectedWallet = updated;
|
||||
}
|
||||
}
|
||||
|
||||
void _setResource(Resource<List<Wallet>> newResource) {
|
||||
_resource = newResource;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
27
frontend/pshared/lib/service/payment/wallets.dart
Normal file
27
frontend/pshared/lib/service/payment/wallets.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:pshared/data/mapper/wallet/ui.dart';
|
||||
import 'package:pshared/models/payment/wallet.dart';
|
||||
import 'package:pshared/service/wallet.dart' as shared_wallet_service;
|
||||
|
||||
|
||||
abstract class WalletsService {
|
||||
Future<List<Wallet>> getWallets(String organizationRef);
|
||||
Future<double> getBalance(String organizationRef, String walletRef);
|
||||
}
|
||||
|
||||
class ApiWalletsService implements WalletsService {
|
||||
@override
|
||||
Future<List<Wallet>> getWallets(String organizationRef) async {
|
||||
final models = await shared_wallet_service.WalletService.list(organizationRef);
|
||||
return models.map((m) => m.toUi()).toList();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<double> getBalance(String organizationRef, String walletRef) async {
|
||||
final balance = await shared_wallet_service.WalletService.getBalance(
|
||||
organizationRef: organizationRef,
|
||||
walletRef: walletRef,
|
||||
);
|
||||
final amount = balance.available?.amount;
|
||||
return amount == null ? 0 : double.tryParse(amount) ?? 0;
|
||||
}
|
||||
}
|
||||
@@ -48,6 +48,21 @@ Currency currencyStringToCode(String currencyCode) {
|
||||
}
|
||||
}
|
||||
|
||||
String currencyCodeToString(Currency currencyCode) {
|
||||
switch (currencyCode) {
|
||||
case Currency.usd:
|
||||
return 'USD';
|
||||
case Currency.usdt:
|
||||
return 'USDT';
|
||||
case Currency.usdc:
|
||||
return 'USDC';
|
||||
case Currency.rub:
|
||||
return 'RUB';
|
||||
case Currency.eur:
|
||||
return 'EUR';
|
||||
}
|
||||
}
|
||||
|
||||
IconData iconForCurrencyType(Currency currencyCode) {
|
||||
switch (currencyCode) {
|
||||
case Currency.usd:
|
||||
|
||||
Reference in New Issue
Block a user