import Dinero from 'dinero.js'; import { Currency } from './types'; import { CURRENCY_CONFIGS } from './constants'; /** * Round amount to the minimum unit for the given currency * RWF: rounds to nearest 100 * XOF: returns the integer value */ export const roundToMinimumUnit = ( amount: number, currency: Currency ): number => { const { minimumUnit } = CURRENCY_CONFIGS[currency]; return Math.round(amount / minimumUnit) * minimumUnit; }; /** * Create a Dinero money object with the appropriate currency */ export const createMoney = ( amount: number, currency: Currency ): Dinero.Dinero => { return Dinero({ amount: Math.round(amount), currency, precision: 0 }); }; /** * Calculate installments with precise distribution and proper rounding * For RWF: each installment (except the last) is rounded to multiples of 100 * For XOF: no rounding constraint * The last installment absorbs any difference to ensure total = totalPrice * * @param totalPrice Total price to split * @param count Number of installments * @param currency Currency to use for calculations * @returns Array of installment amounts that sum exactly to totalPrice */ export const calculateInstallments = ( totalPrice: number, count: number, currency: Currency ): number[] => { if (count <= 0) return []; if (count === 1) return [totalPrice]; const money = createMoney(totalPrice, currency); const ratios = Array(count).fill(1); // Equal distribution const allocated = money.allocate(ratios); const installments: number[] = []; let runningTotal = 0; for (let i = 0; i < count - 1; i++) { let amount = allocated[i].getAmount(); if (currency === 'RWF') { amount = roundToMinimumUnit(amount, currency); } installments.push(amount); runningTotal += amount; } const lastInstallment = totalPrice - runningTotal; installments.push(lastInstallment); return installments; }; /** * Calculate monthly repayment details for investors * * @param amountFunded Amount funded by investor * @param expectedProfit Expected profit for investor * @param paymentLength Number of months * @param currency Currency to use * @returns Object with monthly return, principal, and profit */ export const calculateMonthlyRepayment = ( amountFunded: number, expectedProfit: number, paymentLength: number, currency: Currency ) => { const totalExpectedReturn = amountFunded + expectedProfit; const returnInstallments = calculateInstallments( totalExpectedReturn, paymentLength, currency ); const principalInstallments = calculateInstallments( amountFunded, paymentLength, currency ); const monthlyReturn = returnInstallments[0]; const monthlyPrincipal = principalInstallments[0]; const monthlyProfit = monthlyReturn - monthlyPrincipal; return { monthlyReturn, monthlyPrincipal, monthlyProfit, }; };