@type-ddd/money
Version:
This package provides TypeScript type definitions for handling Money in Domain-Driven Design contexts
473 lines (472 loc) • 19.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Money = exports.Locales = exports.Currencies = void 0;
const rich_domain_1 = require("rich-domain");
var Currencies;
(function (Currencies) {
Currencies["USD"] = "USD";
Currencies["EUR"] = "EUR";
Currencies["JPY"] = "JPY";
Currencies["GBP"] = "GBP";
Currencies["AUD"] = "AUD";
Currencies["CAD"] = "CAD";
Currencies["CHF"] = "CHF";
Currencies["CNY"] = "CNY";
Currencies["SEK"] = "SEK";
Currencies["NZD"] = "NZD";
Currencies["KRW"] = "KRW";
Currencies["SGD"] = "SGD";
Currencies["NOK"] = "NOK";
Currencies["MXN"] = "MXN";
Currencies["INR"] = "INR";
Currencies["BRL"] = "BRL";
Currencies["RUB"] = "RUB";
Currencies["ZAR"] = "ZAR";
Currencies["TRY"] = "TRY";
Currencies["HKD"] = "HKD";
})(Currencies || (exports.Currencies = Currencies = {}));
var Locales;
(function (Locales) {
Locales["en-US"] = "en-US";
Locales["en-GB"] = "en-GB";
Locales["en-CA"] = "en-CA";
Locales["en-AU"] = "en-AU";
Locales["en-NZ"] = "en-NZ";
Locales["fr-FR"] = "fr-FR";
Locales["fr-CA"] = "fr-CA";
Locales["es-ES"] = "es-ES";
Locales["es-MX"] = "es-MX";
Locales["pt-BR"] = "pt-BR";
Locales["pt-PT"] = "pt-PT";
Locales["de-DE"] = "de-DE";
Locales["it-IT"] = "it-IT";
Locales["ja-JP"] = "ja-JP";
Locales["ko-KR"] = "ko-KR";
Locales["zh-CN"] = "zh-CN";
Locales["zh-TW"] = "zh-TW";
Locales["ru-RU"] = "ru-RU";
})(Locales || (exports.Locales = Locales = {}));
class Money extends rich_domain_1.ValueObject {
constructor(prop) {
super(prop);
}
value() {
return this.props;
}
/**
* @description Validate if provided value is a valid money value.
* @param value The value to validate.
* @returns A boolean indicating whether the provided value is a valid money value.
*/
static isValid(value) {
return this.isValidProps(value);
}
/**
* @description Validate if provided value is a valid money value.
* @param value The value to validate.
* @returns A boolean indicating whether the provided value is a valid money value.
*/
static isValidProps(value) {
return this.validator.number(value).isSafeInteger();
}
/**
* @description Formats the money value as currency according to the specified currency and locale.
* @param currency The currency code or enum representing the currency. Defaults to Brazilian Real (BRL).
* @param locale The locale code or enum representing the locale. Defaults to Brazilian Portuguese (pt-BR).
* @returns A string representing the money value formatted as currency.
*/
coin(currency, locale) {
return Intl.NumberFormat(locale ?? Locales['pt-BR'], {
currency: currency ?? Currencies.BRL,
style: 'currency'
}).format(this.value());
}
/**
* @description Performs addition with another Money object or a numeric value.
* @param money The Money object or numeric value to add.
* @returns A new Money object representing the result of the addition.
*/
sum(money) {
const current = this.value();
const target = money instanceof Money ? money.value() : money;
const total = this.util.number(current).sum(target, { fractionDigits: 3 });
return new Money(total);
}
/**
* @description Performs subtraction with another Money object or a numeric value.
* @param money The Money object or numeric value to subtract.
* @returns A new Money object representing the result of the subtraction.
*/
subtract(money) {
const current = this.value();
const target = money instanceof Money ? money.value() : money;
const total = this.util.number(current).subtract(target, { fractionDigits: 3 });
return new Money(total);
}
/**
* @description Performs multiplication with another Money object or a numeric value.
* @param money The Money object or numeric value to multiply by.
* @returns A new Money object representing the result of the multiplication.
*/
multiply(money) {
const current = this.value();
const target = money instanceof Money ? money.value() : money;
const total = this.util.number(current).multiplyBy(target, { fractionDigits: 3 });
return new Money(total);
}
/**
* @description Performs division with another Money object or a numeric value.
* @param money The Money object or numeric value to divide by.
* @returns A new Money object representing the result of the division.
*/
divide(money) {
const current = this.value();
const target = money instanceof Money ? money.value() : money;
const total = this.util.number(current).divideBy(target, { fractionDigits: 3 });
return new Money(total);
}
/**
* @description Adds a percentage to the money value.
* @param percent The percentage to add.
* @returns A new Money object representing the result of adding the percentage.
*/
addPercent(percent) {
const current = this.value();
const multiply = this.util.number(current).multiplyBy(percent);
const percents = this.util.number(multiply).divideBy(100);
const total = this.util.number(percents).sum(current, { fractionDigits: 3 });
return new Money(total);
}
/**
* @description Calculates the percentage of the money value.
* @param percent The percentage to calculate.
* @returns A new Money object representing the calculated percentage.
*/
percent(percent) {
const current = this.value();
const multiply = this.util.number(current).multiplyBy(percent);
const percents = this.util.number(multiply).divideBy(100, { fractionDigits: 3 });
return new Money(percents);
}
/**
* @description Checks if the money value is greater than the provided value.
* @param value The value to compare.
* @returns A boolean indicating whether the money value is greater than the provided value.
*/
isGt(value) {
const target = value instanceof Money ? value.value() : value;
const current = this.value();
return this.validator.number(current).isGreaterThan(target);
}
/**
* @description Checks if the money value is greater than or equal to the provided value.
* @param value The value to compare.
* @returns A boolean indicating whether the money value is greater than or equal to the provided value.
*/
isGte(value) {
const target = value instanceof Money ? value.value() : value;
const current = this.value();
return this.validator.number(current).isGreaterOrEqualTo(target);
}
/**
* @description Checks if the money value is less than the provided value.
* @param value The value to compare.
* @returns A boolean indicating whether the money value is less than the provided value.
*/
isLt(value) {
const target = value instanceof Money ? value.value() : value;
const current = this.value();
return this.validator.number(current).isLessThan(target);
}
/**
* @description Checks if the money value is less than or equal to the provided value.
* @param value The value to compare.
* @returns A boolean indicating whether the money value is less than or equal to the provided value.
*/
isLte(value) {
const target = value instanceof Money ? value.value() : value;
const current = this.value();
return this.validator.number(current).isLessOrEqualTo(target);
}
/**
* @description Checks if the money value is equal to the provided value.
* @param value The value to compare.
* @returns A boolean indicating whether the money value is equal to the provided value.
*/
isEq(value) {
const target = value instanceof Money ? value.value() : value;
const current = this.value();
return this.validator.number(current).isEqualTo(target);
}
/**
* @description Checks if the money value is positive.
* @returns A boolean indicating whether the money value is positive.
*/
isPos() {
return this.validator.number(this.props).isPositive();
}
/**
* @description Checks if the money value is negative.
* @returns A boolean indicating whether the money value is negative.
*/
isNeg() {
return this.validator.number(this.props).isNegative();
}
/**
* @description Checks if the money value is zero.
* @returns A boolean indicating whether the money value is zero.
*/
isZero() {
return this.validator.number(this.props).isEqualTo(0);
}
/**
* @description Makes the money value positive.
* @returns A new Money object with a positive value.
*/
makePos() {
const value = this.value();
if (this.validator.number(value).isNegative()) {
return new Money(value * -1);
}
return new Money(value);
}
/**
* @description Makes the money value negative.
* @returns A new Money object with a negative value.
*/
makeNeg() {
const value = this.value();
if (this.validator.number(value).isPositive()) {
return new Money(value * -1);
}
return new Money(value);
}
/**
* @description Creates a new Money object with a value of zero.
* @returns A new Money object initialized with a value of zero.
*/
static zero() {
return new Money(0);
}
/**
* @description Creates a new Money object with a value of one.
* @returns A new Money object initialized with a value of one.
*/
static one() {
return new Money(1);
}
/**
* @description Creates a new Money object with a value of ten.
* @returns A new Money object initialized with a value of ten.
*/
static ten() {
return new Money(10);
}
/**
* @description Creates a new Money object with a value of one hundred.
* @returns A new Money object initialized with a value of one hundred.
*/
static one_hundred() {
return new Money(100);
}
/**
* @description Creates a new Money object with a value of one thousand.
* @returns A new Money object initialized with a value of one thousand.
*/
static one_thousand() {
return new Money(1000);
}
/**
* @description Performs summation of two values.
* @param a The first value to sum, which can be a number or a Money object.
* @param b The second value to sum, which can be a number or a Money object.
* @returns The result of the summation as a number.
*/
static sum(a, b) {
const valueA = a instanceof Money ? a.value() : a;
const valueB = b instanceof Money ? b.value() : b;
return this.util.number(valueA).sum(valueB, { fractionDigits: 3 });
}
/**
* @description Performs division of two values.
* @param a The numerator value, which can be a number or a Money object.
* @param b The denominator value, which can be a number or a Money object.
* @returns The result of the division as a number.
*/
static divide(a, b) {
const valueA = a instanceof Money ? a.value() : a;
const valueB = b instanceof Money ? b.value() : b;
return this.util.number(valueA).divideBy(valueB, { fractionDigits: 3 });
}
/**
* @description Performs multiplication of two values.
* @param a The first value to multiply, which can be a number or a Money object.
* @param b The second value to multiply, which can be a number or a Money object.
* @returns The result of the multiplication as a number.
*/
static multiply(a, b) {
const valueA = a instanceof Money ? a.value() : a;
const valueB = b instanceof Money ? b.value() : b;
return this.util.number(valueA).multiplyBy(valueB, { fractionDigits: 3 });
}
/**
* @description Performs subtraction of two values.
* @param a The minuend value, which can be a number or a Money object.
* @param b The subtrahend value, which can be a number or a Money object.
* @returns The result of the subtraction as a number.
*/
static subtract(a, b) {
const valueA = a instanceof Money ? a.value() : a;
const valueB = b instanceof Money ? b.value() : b;
return this.util.number(valueA).subtract(valueB, { fractionDigits: 3 });
}
/**
* @description Rounds down the money value to the nearest integer.
* @returns A new Money object representing the rounded-down value.
*/
floor() {
const ceil = Math.floor(this.props);
return new Money(ceil);
}
;
/**
* @description Rounds up the money value to the nearest integer.
* @returns A new Money object representing the rounded-up value.
*/
ceil() {
const ceil = Math.ceil(this.props);
return new Money(ceil);
}
/**
* @description Generates a closure that performs arithmetic operations with a predefined initial value.
* @param initial The initial value for arithmetic operations.
* @returns An object containing functions for performing `summation`, `division`, `multiplication`, and `subtraction` with the initial value.
*/
static closure(initial) {
return {
sum: (value) => Money.sum(initial, value),
divide: (value) => Money.divide(initial, value),
multiply: (value) => Money.multiply(initial, value),
subtract: (value) => Money.subtract(initial, value)
};
}
/**
* @description Calculates the simple interest based on the provided rate and periods.
* @param rate The interest rate as a percentage.
* @param periods The number of periods over which the interest is applied.
* @returns A new Money object representing the calculated interest.
* @throws {Error} If either the rate or periods is negative.
*/
interest(rate, periods) {
if (this.validator.number(rate).isNegative() ||
this.validator.number(periods).isNegative()) {
throw new Error('period and rate must be greater than zero');
}
const rateBy100 = this.util.number(rate).divideBy(100);
const amount = this.util.number(this.props).multiplyBy(rateBy100);
const interest = this.util.number(amount).multiplyBy(periods);
return new Money(interest);
}
/**
* @description Finds the maximum value among the provided Money objects.
* @param values An array of Money objects.
* @returns A new Money object representing the maximum value found.
*/
static max(values) {
const arr = values.map((item) => item.value());
const max = Math.max(...arr);
return new Money(max);
}
/**
* @description Finds the minimum value among the provided Money objects.
* @param values An array of Money objects.
* @returns A new Money object representing the minimum value found.
*/
static min(values) {
const arr = values.map((item) => item.value());
const max = Math.min(...arr);
return new Money(max);
}
/**
* @description Calculates the compound interest based on the provided rate and periods.
* @param rate The interest rate as a percentage.
* @param periods The number of periods over which the interest is applied.
* @returns A new Money object representing the calculated compound interest.
* @throws {Error} If either the rate or periods is negative.
*/
compoundInterest(rate, periods) {
if (this.validator.number(rate).isNegative() ||
this.validator.number(periods).isNegative()) {
throw new Error('period and rate must be greater than zero');
}
;
const rateBy100 = this.util.number(rate).divideBy(100);
const base = this.util.number(rateBy100).sum(1);
const pow = Math.pow(base, periods);
const amount = this.util.number(this.props).multiplyBy(pow);
const compoundInterest = this.util.number(amount).subtract(this.props, { fractionDigits: 3 });
return new Money(compoundInterest);
}
/**
* @description Generates a random Money value within the specified range.
* @param min The minimum value of the range.
* @param max The maximum value of the range.
* @returns A new Money object representing a random value within the specified range.
*/
static random(min, max) {
if (min >= max)
return Money.zero();
const randomValue = Math.random() * (max - min) + min;
const roundedValue = Math.round(randomValue * 100) / 100;
return new Money(roundedValue);
}
/**
* @description Calculates the average value among the provided Money objects.
* @param values An array of Money objects.
* @returns A new Money object representing the average value of the Money objects.
*/
static average(values) {
const items = values.length;
const calc = (prev, current) => current.sum(prev);
const total = values.reduce(calc, Money.zero());
return total.divide(items);
}
/**
* @description Converts the current Money value to another currency using the provided exchange rate.
* @param exchangeRate The exchange rate, which can be a Money object representing the rate or a number.
* @returns A new Money object representing the converted value.
*/
convertTo(exchangeRate) {
const current = this.value();
const rate = exchangeRate instanceof Money ? exchangeRate.value() : exchangeRate;
const value = this.util.number(current).multiplyBy(rate, { fractionDigits: 3 });
return new Money(value);
}
/**
* @description Initializes a Money object with the provided value.
* @param value The initial value for the Money object.
* @returns A new Money object initialized with the provided value.
* @throws {Error} If the provided value is invalid.
*/
static init(value) {
const isValidValue = Money.isValidProps(value);
if (!isValidValue)
throw new Error(Money.MESSAGE);
return new Money(value);
}
/**
* @description Creates a Result object containing a Money object initialized with the provided value.
* @param value The initial value for the Money object.
* @returns A Result object containing either a Money object or an error message.
*/
static create(value) {
if (!Money.isValidProps(value)) {
return rich_domain_1.Result.fail(Money.MESSAGE);
}
return rich_domain_1.Result.Ok(new Money(value));
}
;
}
exports.Money = Money;
Money.MESSAGE = 'Invalid money value';
exports.default = Money;