money-calc
v1.3.1
Published
Helper class for calculating money amounts without rounding errors.
Downloads
11
Readme
Helper class for calculating money amounts without rounding errors.
Installation
npm install --save money-calc
# or
yarn install money-calc
# or
pnpm install money-calc
Example
import Money, { MoneyAmount } from "money-calc";
interface Product {
name: string;
manufacturer: string;
weightKg: MoneyAmount;
unitsPerPack: MoneyAmount;
price: MoneyAmount;
}
interface Discount {
percent: MoneyAmount;
}
let product: Product = {
name: "Mr Sparkle Dishwashing Detergent Powder, 2kg, 66 Washes",
manufacturer: "Matsumura Fishworks & Tamaribuchi Heavy Manufacturing Concern",
weightKg: "2.00",
unitsPerPack: "66.00",
price: {
amount: "19.99",
currency: "AUD"
},
shippingFee: {
amount: "4.18",
currency: "AUD"
}
};
let discount: Discount = {
percent: "20.00"
};
let discountRemainder = new Money("100.00")
.subtract(discount.percent);
let originalPrice = new Money(product.price);
let finalPrice = new Money(originalPrice)
.percent(discountRemainder)
.add(product.shippingFee);
let pricePerKg = new Money(finalPrice)
.div(product.weightKg);
let pricePerUnit = new Money(finalPrice)
.div(product.unitsPerPack);
console.log(`Was ${originalPrice}, now ${finalPrice} w/shipping!`);
console.log(`Price per kilogram: ${pricePerKg}`);
console.log(`Price per unit: ${pricePerUnit}`);
let response = {
product,
discount,
originalPrice,
finalPrice,
pricePerKg,
pricePerUnit
};
// Stringify and then parse the object back in, to simulate sending the data
// over the wire to an API client.
let jsonified = JSON.parse(JSON.stringify(response));
console.log("JSON response:");
console.log(jsonified);
Running this script produces the following output:
Was A$19.99, now A$20.17!
Price per kilogram: A$10.09
Price per unit: A$0.31
JSON response:
{
product: {
name: 'Mr Sparkle Dishwashing Detergent Powder, 2kg, 66 Washes',
manufacturer: 'Matsumura Fishworks & Tamaribuchi Heavy Manufacturing Concern',
weightKg: '2.00',
unitsPerPack: '66.00',
price: { amount: '19.99', currency: 'AUD' },
shippingFee: { amount: '4.18', currency: 'AUD' }
},
discount: { percent: '20.00' },
originalPrice: { amount: '19.99', currency: 'AUD' },
finalPrice: { amount: '20.17', currency: 'AUD' },
pricePerKg: { amount: '10.09', currency: 'AUD' },
pricePerUnit: { amount: '0.31', currency: 'AUD' }
}
Usage
MoneyAmount
A string of the format 1234.56
. Two decimal places must be provided. For example: 12.00
or 12.30
, rather than 12
, 12.0
, or 12.3
. Numbers only - no digit separators or currency symbols! The TypeScript type definition will help ensure your inputs are of the right format.
MoneyInput
A money input can be represented as:
- A string matching the format of MoneyAmount.
- The exact string
0
, as a shortcut for0.00
. - An instance of js-big-decimal.
- An instance of the Decimal128 type, as exported by bson (the same type is also re-exported by the MongoDB driver). In MongoDB, this is called NumberDecimal, meaning you can store a NumberDecimal in a MongoDB document, then retrieve and pass it directly to Money.
- You can also pass another instance of Money, or the simplified object returned by
Money.toJSON()
.
Currency
Enumeration of all three-letter currency symbols that account for at least 1% of world trade, according to xe.com. Any other currency supported by ICU (the source of truth used by the Intl classes) will work, however.
ComparisonResult
An enumeration of possible outcomes from a numeric comparison:
ComparisonResult.Ascending = -1
: The first number is less than the second number.ComparisonResult.Same = 0
: The two numbers are equal.ComparisonResult.Descending = 1
: The first number is greater than the second number.
Money
Money objects are immutable, and are designed to be used in a chainable sequence of operations.
new Money(amount: MoneyInput, currency?: Currency)
Initialise a new Money instance with the supplied MoneyInput.
If a currency is not specified, and the amount isn’t an instance of Money, it will fall back to the default of USD.
Throws TypeError
if the input amount is invalid.
add(...amounts: MoneyInput[]): Money
Returns an instance of Money with the result of adding the supplied amounts in sequence.
subtract(...amounts: MoneyInput[]): Money
Returns an instance of Money with the result of subtracting the supplied amounts in sequence.
mul(...amounts: MoneyInput[]): Money
Returns an instance of Money with the result of multiplying by the supplied amounts in sequence.
div(...amounts: MoneyInput[]): Money
Returns an instance of Money with the result of dividing by the supplied amounts in sequence.
mod(...amounts: MoneyInput[]): Money
Returns an instance of Money with the result of the modulus (division remainder) of the supplied amounts in sequence.
percent(amount: MoneyInput): Money
Returns an instance of Money with the result of multiplying by a percentage between 0.00
and 100.00
. This is effectively a shortcut for dividing the input amount by 100.00
before multiplying by that amount. If the percentage is between 0.00
and 1.00
, use mul()
instead.
negate(): Money
Returns an instance of Money with the amount negated - that is, a positive number becomes negative, and a negative number becomes positive.
cmp(amount: MoneyInput): ComparisonResult
Compares the amount with another amount, and returns the result of the comparison.
toString(): string
Formats the money amount for display in a user interface. Includes the appropriate currency sign for the supplied currency, in addition to thousand separators. For a machine-readable string, use amount
.
toJSON(): { amount: MoneyAmount; currency: Currency }
Returns an object that can be used to represent the Money in a JSON object. You can then initialise an instance of Money on the client side by using this as a MoneyInput
, or directly pass these parameters to the number formatting mechanism for the platform.
toJSON()
is called by JSON.stringify()
to retrieve a variant of the object that can be represented in JSON. As such, you likely won’t need to call this directly.
amount: string
The string value that can be stored in a database or serialized into a payload such as JSON. This amount is rounded to 2 decimal places, and is intended to be machine-readable. For a human-readable string, use toString()
.
Credits
Developed by Chariz:
License
Licensed under the Apache License, version 2.0. Refer to LICENSE.md.