/** * Currency conversion and USD equivalent calculation utilities */ import Decimal from 'decimal.js'; export interface ExchangeRate { fromCurrency: string; toCurrency: string; rate: number; effectiveDate: Date; source?: string; } export interface CurrencyConverter { convert(amount: number, fromCurrency: string, toCurrency: string, date?: Date): number; getUSDEquivalent(amount: number, currency: string, date?: Date): number; getRate(fromCurrency: string, toCurrency: string, date?: Date): number | null; } /** * Simple in-memory currency converter with configurable rates * In production, this would integrate with a real-time FX rate service */ export class SimpleCurrencyConverter implements CurrencyConverter { private rates: Map = new Map(); private defaultUSDRates: Record = { USD: 1.0, BRL: 0.2, EUR: 1.1, GBP: 1.27, }; constructor(initialRates?: ExchangeRate[]) { if (initialRates) { initialRates.forEach((rate) => this.addRate(rate)); } this.initializeDefaultRates(); } private initializeDefaultRates(): void { const now = new Date(); Object.entries(this.defaultUSDRates).forEach(([currency, rate]) => { if (currency !== 'USD') { this.addRate({ fromCurrency: currency, toCurrency: 'USD', rate, effectiveDate: now, source: 'default', }); } }); } addRate(rate: ExchangeRate): void { const key = this.getRateKey(rate.fromCurrency, rate.toCurrency); this.rates.set(key, rate); const inverseKey = this.getRateKey(rate.toCurrency, rate.fromCurrency); this.rates.set(inverseKey, { ...rate, fromCurrency: rate.toCurrency, toCurrency: rate.fromCurrency, rate: 1 / rate.rate, }); } private getRateKey(fromCurrency: string, toCurrency: string): string { return `${fromCurrency}:${toCurrency}`; } getRate(fromCurrency: string, toCurrency: string, date?: Date): number | null { if (fromCurrency === toCurrency) { return 1.0; } const key = this.getRateKey(fromCurrency, toCurrency); const rate = this.rates.get(key); if (!rate) { if (fromCurrency !== 'USD' && toCurrency !== 'USD') { const fromToUSD = this.getRate(fromCurrency, 'USD', date); const usdToTo = this.getRate('USD', toCurrency, date); if (fromToUSD && usdToTo) { return fromToUSD * usdToTo; } } return null; } return rate.rate; } convert(amount: number, fromCurrency: string, toCurrency: string, date?: Date): number { if (fromCurrency === toCurrency) { return amount; } const rate = this.getRate(fromCurrency, toCurrency, date); if (rate === null) { throw new Error( `No exchange rate available for ${fromCurrency} to ${toCurrency}` ); } const amountDecimal = new Decimal(amount); const rateDecimal = new Decimal(rate); return amountDecimal.mul(rateDecimal).toNumber(); } getUSDEquivalent(amount: number, currency: string, date?: Date): number { if (currency === 'USD') { return amount; } return this.convert(amount, currency, 'USD', date); } } let defaultConverter: CurrencyConverter | null = null; export function getDefaultConverter(): CurrencyConverter { if (!defaultConverter) { defaultConverter = new SimpleCurrencyConverter(); } return defaultConverter; } export function setDefaultConverter(converter: CurrencyConverter): void { defaultConverter = converter; }