162 lines
4.4 KiB
Dart
162 lines
4.4 KiB
Dart
import 'package:pshared/models/money.dart';
|
|
import 'package:pshared/models/payment/fees/line.dart';
|
|
import 'package:pshared/models/payment/quote/quote.dart';
|
|
import 'package:pshared/utils/currency.dart';
|
|
import 'package:pshared/utils/money.dart';
|
|
|
|
|
|
Money? quoteFeeTotal(PaymentQuote? quote) {
|
|
final preferredCurrency =
|
|
quote?.amounts?.sourcePrincipal?.currency ??
|
|
quote?.amounts?.sourceDebitTotal?.currency;
|
|
return quoteFeeTotalFromLines(
|
|
quote?.fees?.lines,
|
|
preferredCurrency: preferredCurrency,
|
|
);
|
|
}
|
|
|
|
Money? quoteSourceDebitTotal(
|
|
PaymentQuote? quote, {
|
|
String? preferredSourceCurrency,
|
|
}) {
|
|
final sourceDebitTotal = quote?.amounts?.sourceDebitTotal;
|
|
final preferredCurrency = _normalizeCurrency(
|
|
preferredSourceCurrency ?? quote?.amounts?.sourcePrincipal?.currency,
|
|
);
|
|
|
|
if (sourceDebitTotal == null) {
|
|
return _rebuildSourceDebitTotal(
|
|
quote,
|
|
preferredSourceCurrency: preferredCurrency,
|
|
);
|
|
}
|
|
|
|
final debitCurrency = _normalizeCurrency(sourceDebitTotal.currency);
|
|
if (preferredCurrency == null ||
|
|
debitCurrency == null ||
|
|
debitCurrency == preferredCurrency) {
|
|
return sourceDebitTotal;
|
|
}
|
|
|
|
final rebuilt = _rebuildSourceDebitTotal(
|
|
quote,
|
|
preferredSourceCurrency: preferredCurrency,
|
|
);
|
|
return rebuilt ?? sourceDebitTotal;
|
|
}
|
|
|
|
Money? quoteFeeTotalFromLines(
|
|
List<FeeLine>? lines, {
|
|
String? preferredCurrency,
|
|
}) {
|
|
if (lines == null || lines.isEmpty) return null;
|
|
|
|
final normalizedPreferred = _normalizeCurrency(preferredCurrency);
|
|
final totalsByCurrency = <String, double>{};
|
|
|
|
for (final line in lines) {
|
|
final money = line.amount;
|
|
if (money == null) continue;
|
|
|
|
final currency = _normalizeCurrency(money.currency);
|
|
if (currency == null) continue;
|
|
|
|
final amount = parseMoneyAmount(money.amount, fallback: double.nan);
|
|
if (amount.isNaN) continue;
|
|
|
|
final sign = _lineSign(line.side);
|
|
final signedAmount = sign * amount.abs();
|
|
totalsByCurrency[currency] =
|
|
(totalsByCurrency[currency] ?? 0) + signedAmount;
|
|
}
|
|
|
|
if (totalsByCurrency.isEmpty) return null;
|
|
|
|
final selectedCurrency =
|
|
normalizedPreferred != null &&
|
|
totalsByCurrency.containsKey(normalizedPreferred)
|
|
? normalizedPreferred
|
|
: totalsByCurrency.keys.first;
|
|
final total = totalsByCurrency[selectedCurrency];
|
|
if (total == null) return null;
|
|
|
|
return Money(amount: amountToString(total), currency: selectedCurrency);
|
|
}
|
|
|
|
List<Money> aggregateMoneyByCurrency(Iterable<Money?> values) {
|
|
final totals = <String, double>{};
|
|
for (final value in values) {
|
|
if (value == null) continue;
|
|
|
|
final currency = _normalizeCurrency(value.currency);
|
|
if (currency == null) continue;
|
|
|
|
final amount = parseMoneyAmount(value.amount, fallback: double.nan);
|
|
if (amount.isNaN) continue;
|
|
|
|
totals[currency] = (totals[currency] ?? 0) + amount;
|
|
}
|
|
|
|
return totals.entries
|
|
.map(
|
|
(entry) =>
|
|
Money(amount: amountToString(entry.value), currency: entry.key),
|
|
)
|
|
.toList();
|
|
}
|
|
|
|
Money? _rebuildSourceDebitTotal(
|
|
PaymentQuote? quote, {
|
|
String? preferredSourceCurrency,
|
|
}) {
|
|
final sourcePrincipal = quote?.amounts?.sourcePrincipal;
|
|
if (sourcePrincipal == null) return null;
|
|
|
|
final principalCurrency = _normalizeCurrency(sourcePrincipal.currency);
|
|
if (principalCurrency == null) return null;
|
|
if (preferredSourceCurrency != null &&
|
|
principalCurrency != preferredSourceCurrency) {
|
|
return null;
|
|
}
|
|
|
|
final principalAmount = parseMoneyAmount(
|
|
sourcePrincipal.amount,
|
|
fallback: double.nan,
|
|
);
|
|
if (principalAmount.isNaN) return null;
|
|
|
|
double totalAmount = principalAmount;
|
|
final fee = quoteFeeTotalFromLines(
|
|
quote?.fees?.lines,
|
|
preferredCurrency: principalCurrency,
|
|
);
|
|
if (fee != null && _normalizeCurrency(fee.currency) == principalCurrency) {
|
|
final feeAmount = parseMoneyAmount(fee.amount, fallback: double.nan);
|
|
if (!feeAmount.isNaN) {
|
|
totalAmount += feeAmount;
|
|
}
|
|
}
|
|
|
|
return Money(
|
|
amount: amountToString(totalAmount),
|
|
currency: principalCurrency,
|
|
);
|
|
}
|
|
|
|
double _lineSign(String? side) {
|
|
final normalized = side?.trim().toLowerCase() ?? '';
|
|
switch (normalized) {
|
|
case 'entry_side_credit':
|
|
case 'credit':
|
|
return -1;
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
String? _normalizeCurrency(String? currency) {
|
|
final normalized = currency?.trim().toUpperCase();
|
|
if (normalized == null || normalized.isEmpty) return null;
|
|
return normalized;
|
|
}
|