Files
cobble/src/utils/money.ts
T

92 lines
2.7 KiB
TypeScript

/**
* # Format a kobo (₦/100) amount as a Naira currency string.
* @example formatNaira(150050) // "₦1,500.50"
*/
export function formatNaira(kobo: number | string | undefined | null): string {
const amount = Math.round(Number(kobo || 0));
const negative = amount < 0;
const absolute = Math.abs(amount);
const whole = Math.floor(absolute / 100);
const fraction = String(absolute % 100).padStart(2, "0");
const digits = String(whole);
let grouped = "";
for (let i = digits.length - 1, c = 0; i >= 0; i--, c++) {
if (c > 0 && c % 3 == 0) {
grouped = `,${grouped}`;
}
grouped = digits[i] + grouped;
}
return `${negative ? "-" : ""}₦${grouped}.${fraction}`;
}
/**
* # Format a kobo amount with an ISO currency prefix.
* Standard PDF fonts (WinAnsi) cannot encode the ₦ glyph,
* so PDFs use "NGN" instead of "₦".
* @example formatNairaPdf(150050) // "NGN 1,500.50"
*/
export function formatNairaPdf(
kobo: number | string | undefined | null,
): string {
const amount = Math.round(Number(kobo || 0));
const negative = amount < 0;
const absolute = Math.abs(amount);
const whole = Math.floor(absolute / 100);
const fraction = String(absolute % 100).padStart(2, "0");
const digits = String(whole);
let grouped = "";
for (let i = digits.length - 1, c = 0; i >= 0; i--, c++) {
if (c > 0 && c % 3 == 0) {
grouped = `,${grouped}`;
}
grouped = digits[i] + grouped;
}
return `${negative ? "-" : ""}NGN ${grouped}.${fraction}`;
}
/**
* # Convert a Naira string/number to kobo (smallest unit).
* @example nairaToKobo("₦1,500.50") // 150050
*/
export function nairaToKobo(value: string | number | undefined): number {
const cleaned = String(value || 0).replace(/[^0-9.]/g, "");
return Math.round((Number(cleaned) || 0) * 100);
}
/**
* # Convert a kobo amount to a plain Naira string for form inputs.
* @example koboToNairaString(150050) // "1500.5"
*/
export function koboToNairaString(
kobo: number | string | undefined | null,
): string {
const amount = Math.abs(Number(kobo || 0));
const naira = amount / 100;
return String(Math.round(naira * 100) / 100);
}
export type InvoiceItemAmountInput = {
quantity?: number | string | "";
unit_price_kobo?: number | string | "";
};
/**
* # Sum line items into a kobo total.
*/
export function sumInvoiceItemsKobo(
items: InvoiceItemAmountInput[],
): number {
return items.reduce((acc, item) => {
const quantity = Number(item.quantity) || 0;
const unit_price = Number(item.unit_price_kobo) || 0;
return acc + quantity * unit_price;
}, 0);
}