131 lines
3.5 KiB
Dart
131 lines
3.5 KiB
Dart
import 'package:money2/money2.dart';
|
|
|
|
import 'package:pshared/models/payment/fees/line.dart';
|
|
import 'package:pshared/models/payment/quote/quote.dart';
|
|
import 'package:pshared/utils/currency.dart';
|
|
|
|
|
|
Money? quoteFeeTotal(PaymentQuote? quote) {
|
|
return quoteFeeTotalFromLines(
|
|
quote?.fees?.lines,
|
|
preferredCurrency:
|
|
quote?.amounts?.sourcePrincipal?.currency.isoCode ??
|
|
quote?.amounts?.sourceDebitTotal?.currency.isoCode,
|
|
);
|
|
}
|
|
|
|
Money? quoteSourceDebitTotal(
|
|
PaymentQuote? quote, {
|
|
String? preferredSourceCurrency,
|
|
}) {
|
|
final sourceDebitTotal = quote?.amounts?.sourceDebitTotal;
|
|
final preferredCurrency = _normalizeCurrency(
|
|
preferredSourceCurrency ??
|
|
quote?.amounts?.sourcePrincipal?.currency.isoCode,
|
|
);
|
|
|
|
if (sourceDebitTotal == null) {
|
|
return _rebuildSourceDebitTotal(
|
|
quote,
|
|
preferredSourceCurrency: preferredCurrency,
|
|
);
|
|
}
|
|
|
|
if (preferredCurrency == null ||
|
|
_normalizeCurrency(sourceDebitTotal.currency.isoCode) ==
|
|
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, Money>{};
|
|
|
|
for (final line in lines) {
|
|
final parsedAmount = line.amount;
|
|
if (parsedAmount == null) continue;
|
|
|
|
final currencyCode = parsedAmount.currency.isoCode;
|
|
final signedAmount = _isCreditLine(line.side) ? -parsedAmount : parsedAmount;
|
|
final current = totalsByCurrency[currencyCode];
|
|
totalsByCurrency[currencyCode] = current == null
|
|
? signedAmount
|
|
: current + signedAmount;
|
|
}
|
|
|
|
if (totalsByCurrency.isEmpty) return null;
|
|
|
|
final selectedCurrency =
|
|
normalizedPreferred != null &&
|
|
totalsByCurrency.containsKey(normalizedPreferred)
|
|
? normalizedPreferred
|
|
: totalsByCurrency.keys.first;
|
|
return totalsByCurrency[selectedCurrency];
|
|
}
|
|
|
|
List<Money> aggregateMoneyByCurrency(Iterable<Money?> values) {
|
|
final totals = <String, Money>{};
|
|
for (final value in values) {
|
|
if (value == null) continue;
|
|
final currency = value.currency.isoCode;
|
|
final current = totals[currency];
|
|
totals[currency] = current == null ? value : current + value;
|
|
}
|
|
|
|
return totals.values.toList();
|
|
}
|
|
|
|
Money? _rebuildSourceDebitTotal(
|
|
PaymentQuote? quote, {
|
|
String? preferredSourceCurrency,
|
|
}) {
|
|
final principal = quote?.amounts?.sourcePrincipal;
|
|
if (principal == null) return null;
|
|
|
|
final principalCurrency = principal.currency.isoCode;
|
|
if (preferredSourceCurrency != null &&
|
|
principalCurrency != preferredSourceCurrency) {
|
|
return null;
|
|
}
|
|
|
|
var totalAmount = principal;
|
|
final fee = quoteFeeTotalFromLines(
|
|
quote?.fees?.lines,
|
|
preferredCurrency: principalCurrency,
|
|
);
|
|
if (fee != null && fee.currency.isoCode == principalCurrency) {
|
|
totalAmount += fee;
|
|
}
|
|
|
|
return totalAmount;
|
|
}
|
|
|
|
bool _isCreditLine(String? side) {
|
|
final normalized = side?.trim().toLowerCase() ?? '';
|
|
switch (normalized) {
|
|
case 'entry_side_credit':
|
|
case 'credit':
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
String? _normalizeCurrency(String? currency) {
|
|
final normalized = currency?.trim();
|
|
if (normalized == null || normalized.isEmpty) return null;
|
|
return money2CurrencyFromCode(normalized)?.isoCode ?? normalized.toUpperCase();
|
|
}
|