Files
sendico/frontend/pweb/lib/controllers/payouts/multiple_payouts.dart
2026-03-04 17:43:18 +03:00

163 lines
4.9 KiB
Dart

import 'package:flutter/foundation.dart';
import 'package:pshared/controllers/payment/source.dart';
import 'package:pshared/models/money.dart';
import 'package:pshared/models/payment/payment.dart';
import 'package:pshared/models/payment/quote/status_type.dart';
import 'package:pshared/models/payment/wallet.dart';
import 'package:pweb/models/payment/multiple_payouts/csv_row.dart';
import 'package:pweb/models/payment/multiple_payouts/state.dart';
import 'package:pweb/providers/multiple_payouts.dart';
import 'package:pweb/services/payments/csv_input.dart';
class MultiplePayoutsController extends ChangeNotifier {
final CsvInputService _csvInput;
MultiplePayoutsProvider? _provider;
PaymentSourceController? _sourceController;
_PickState _pickState = _PickState.idle;
Exception? _uiError;
MultiplePayoutsController({required CsvInputService csvInput})
: _csvInput = csvInput;
void update(
MultiplePayoutsProvider provider,
PaymentSourceController sourceController,
) {
var shouldNotify = false;
if (!identical(_provider, provider)) {
_provider?.removeListener(_onProviderChanged);
_provider = provider;
_provider?.addListener(_onProviderChanged);
shouldNotify = true;
}
if (!identical(_sourceController, sourceController)) {
_sourceController?.removeListener(_onSourceChanged);
_sourceController = sourceController;
_sourceController?.addListener(_onSourceChanged);
shouldNotify = true;
}
if (shouldNotify) {
notifyListeners();
}
}
MultiplePayoutsState get state =>
_provider?.state ?? MultiplePayoutsState.idle;
String? get selectedFileName => _provider?.selectedFileName;
List<CsvPayoutRow> get rows => _provider?.rows ?? const <CsvPayoutRow>[];
int get sentCount => _provider?.sentCount ?? 0;
Exception? get error => _uiError ?? _provider?.error;
bool get isQuoting => _provider?.isQuoting ?? false;
bool get isSending => _provider?.isSending ?? false;
bool get isBusy => _provider?.isBusy ?? false;
bool get quoteIsLoading => _provider?.quoteIsLoading ?? false;
QuoteStatusType get quoteStatusType =>
_provider?.quoteStatusType ?? QuoteStatusType.missing;
Duration? get quoteTimeLeft => _provider?.quoteTimeLeft;
bool get canSend => (_provider?.canSend ?? false) && _selectedWallet != null;
Money? get aggregateDebitAmount =>
_provider?.aggregateDebitAmountFor(_selectedWallet);
Money? get requestedSentAmount => _provider?.requestedSentAmount;
Money? get aggregateSettlementAmount =>
_provider?.aggregateSettlementAmountFor(_selectedWallet);
Money? get aggregateFeeAmount =>
_provider?.aggregateFeeAmountFor(_selectedWallet);
double? get aggregateFeePercent =>
_provider?.aggregateFeePercentFor(_selectedWallet);
Future<void> pickAndQuote() async {
if (_pickState == _PickState.picking) return;
final provider = _provider;
if (provider == null) {
_setUiError(StateError('Multiple payouts provider is not ready'));
return;
}
_clearUiError();
_pickState = _PickState.picking;
try {
final picked = await _csvInput.pickCsv();
if (picked == null) return;
final wallet = _selectedWallet;
if (wallet == null) {
_setUiError(StateError('Select source wallet first'));
return;
}
await provider.quoteFromCsv(
fileName: picked.name,
content: picked.content,
sourceWallet: wallet,
);
} catch (e) {
_setUiError(e);
} finally {
_pickState = _PickState.idle;
}
}
Future<List<Payment>> send() async {
return _provider?.send() ?? const <Payment>[];
}
Future<MultiplePayoutSendOutcome> sendAndGetOutcome() async {
_clearUiError();
final provider = _provider;
if (provider == null) {
_setUiError(StateError('Multiple payouts provider is not ready'));
return MultiplePayoutSendOutcome.failure;
}
final payments = await provider.send();
final hasError = provider.error != null;
if (hasError || payments.isEmpty) {
return MultiplePayoutSendOutcome.failure;
}
return MultiplePayoutSendOutcome.success;
}
void removeUploadedFile() {
_provider?.removeUploadedFile();
_clearUiError(notify: false);
}
void _onProviderChanged() {
notifyListeners();
}
void _onSourceChanged() {
notifyListeners();
}
Wallet? get _selectedWallet => _sourceController?.selectedWallet;
void _setUiError(Object error) {
_uiError = error is Exception ? error : Exception(error.toString());
notifyListeners();
}
void _clearUiError({bool notify = true}) {
if (_uiError == null) return;
_uiError = null;
if (notify) {
notifyListeners();
}
}
@override
void dispose() {
_provider?.removeListener(_onProviderChanged);
_sourceController?.removeListener(_onSourceChanged);
super.dispose();
}
}
enum _PickState { idle, picking }
enum MultiplePayoutSendOutcome { success, failure }