Files
Novault-Frontend-web/src/utils/money.ts

203 lines
4.6 KiB
TypeScript

/**
* Money utility functions using decimal.js for precise financial calculations
* Feature: financial-core-upgrade
* Validates: Requirements 4.1-4.4, 13.1-13.4
*/
import Decimal from 'decimal.js';
// Configure decimal.js for financial calculations
Decimal.set({
precision: 20,
rounding: Decimal.ROUND_HALF_UP,
});
// Currency symbols mapping
const CURRENCY_SYMBOLS: Record<string, string> = {
CNY: '¥',
USD: '$',
EUR: '€',
JPY: '¥',
GBP: '£',
HKD: 'HK$',
AUD: 'A$',
CAD: 'C$',
SGD: 'S$',
KRW: '₩',
THB: '฿',
TWD: 'NT$',
INR: '₹',
RUB: '₽',
BRL: 'R$',
};
/**
* Money utility object with all financial calculation functions
*/
export const Money = {
/**
* Add two monetary values
*/
add(a: number | string, b: number | string): number {
return new Decimal(a).plus(b).toNumber();
},
/**
* Subtract b from a
*/
subtract(a: number | string, b: number | string): number {
return new Decimal(a).minus(b).toNumber();
},
/**
* Multiply two values
*/
multiply(a: number | string, b: number | string): number {
return new Decimal(a).times(b).toNumber();
},
/**
* Divide a by b
*/
divide(a: number | string, b: number | string): number {
const divisor = new Decimal(b);
if (divisor.isZero()) {
throw new Error('Division by zero');
}
return new Decimal(a).dividedBy(divisor).toNumber();
},
/**
* Round to specified decimal places (default 2)
*/
round(value: number | string, decimals: number = 2): number {
return new Decimal(value).toDecimalPlaces(decimals).toNumber();
},
/**
* Format money for display with currency symbol (Standard v7.0)
*/
format(value: number | string, currency: string = 'CNY'): string {
const num = new Decimal(value).toNumber();
try {
return new Intl.NumberFormat('zh-CN', {
style: 'currency',
currency: currency,
minimumFractionDigits: 2,
maximumFractionDigits: 2,
}).format(num);
} catch (e) {
// Fallback for invalid currency codes
const symbol = CURRENCY_SYMBOLS[currency] || currency;
const formatted = num.toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
return `${symbol}${formatted}`;
}
},
/**
* Format money without currency symbol
*/
formatNumber(value: number | string): string {
const num = new Decimal(value).toDecimalPlaces(2).toNumber();
return num.toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
});
},
/**
* Parse money string to number
*/
parse(value: string): number {
const cleaned = value.replace(/[¥$€£₩฿₹₽,\s]/g, '');
return new Decimal(cleaned).toNumber();
},
/**
* Check if value is a valid monetary amount
*/
isValid(value: unknown): boolean {
try {
if (value === null || value === undefined || value === '') {
return false;
}
new Decimal(value as string | number);
return true;
} catch {
return false;
}
},
/**
* Calculate daily interest
*/
calculateDailyInterest(balance: number, annualRate: number): number {
return this.round(this.divide(this.multiply(balance, annualRate), 365), 2);
},
/**
* Compare two monetary values
*/
compare(a: number | string, b: number | string): number {
const result = new Decimal(a).comparedTo(b);
return typeof result === 'number' ? result : 0;
},
/**
* Check if value is zero
*/
isZero(value: number | string): boolean {
return new Decimal(value).isZero();
},
/**
* Check if value is positive
*/
isPositive(value: number | string): boolean {
return new Decimal(value).isPositive();
},
/**
* Check if value is negative
*/
isNegative(value: number | string): boolean {
return new Decimal(value).isNegative();
},
/**
* Get absolute value
*/
abs(value: number | string): number {
return new Decimal(value).abs().toNumber();
},
/**
* Get minimum of two values
*/
min(a: number | string, b: number | string): number {
return Decimal.min(a, b).toNumber();
},
/**
* Get maximum of two values
*/
max(a: number | string, b: number | string): number {
return Decimal.max(a, b).toNumber();
},
/**
* Sum an array of values
*/
sum(values: (number | string)[]): number {
return values.reduce<number>((acc, val) => this.add(acc, val), 0);
},
};
// Export individual functions for convenience
export const { add, subtract, multiply, divide, round, format, parse, isValid, calculateDailyInterest } = Money;
export default Money;