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? lines, { String? preferredCurrency, }) { if (lines == null || lines.isEmpty) return null; final normalizedPreferred = _normalizeCurrency(preferredCurrency); final totalsByCurrency = {}; 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 aggregateMoneyByCurrency(Iterable values) { final totals = {}; 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(); }