@ducatjs/money 0.0.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/NOTICE +51 -0
- package/README.md +1034 -3
- package/assets/CREDITS.md +12 -0
- package/data/adyen-fx.json +19 -0
- package/data/adyen.json +171 -0
- package/data/braintree.json +223 -0
- package/data/cash-rounding.json +520 -0
- package/data/checkout.json +230 -0
- package/data/cldr-cash.json +101 -0
- package/data/historic.json +78 -0
- package/data/iso4217-list-one.xml +1956 -0
- package/data/iso4217-list-three.xml +1185 -0
- package/data/klarna.json +95 -0
- package/data/paypal.json +65 -0
- package/data/stripe-fx.json +17 -0
- package/data/stripe.json +285 -0
- package/dist/adyen-fx.d.ts +25 -0
- package/dist/adyen-fx.d.ts.map +1 -0
- package/dist/adyen-fx.js +140 -0
- package/dist/adyen-fx.js.map +1 -0
- package/dist/adyen.d.ts +25 -0
- package/dist/adyen.d.ts.map +1 -0
- package/dist/adyen.js +34 -0
- package/dist/adyen.js.map +1 -0
- package/dist/allocate.d.ts +72 -0
- package/dist/allocate.d.ts.map +1 -0
- package/dist/allocate.js +314 -0
- package/dist/allocate.js.map +1 -0
- package/dist/bag.d.ts +58 -0
- package/dist/bag.d.ts.map +1 -0
- package/dist/bag.js +122 -0
- package/dist/bag.js.map +1 -0
- package/dist/boc.d.ts +31 -0
- package/dist/boc.d.ts.map +1 -0
- package/dist/boc.js +114 -0
- package/dist/boc.js.map +1 -0
- package/dist/boe.d.ts +33 -0
- package/dist/boe.d.ts.map +1 -0
- package/dist/boe.js +114 -0
- package/dist/boe.js.map +1 -0
- package/dist/braintree.d.ts +34 -0
- package/dist/braintree.d.ts.map +1 -0
- package/dist/braintree.js +45 -0
- package/dist/braintree.js.map +1 -0
- package/dist/cash.d.ts +64 -0
- package/dist/cash.d.ts.map +1 -0
- package/dist/cash.js +134 -0
- package/dist/cash.js.map +1 -0
- package/dist/checkout.d.ts +42 -0
- package/dist/checkout.d.ts.map +1 -0
- package/dist/checkout.js +52 -0
- package/dist/checkout.js.map +1 -0
- package/dist/convert.d.ts +52 -0
- package/dist/convert.d.ts.map +1 -0
- package/dist/convert.js +65 -0
- package/dist/convert.js.map +1 -0
- package/dist/currency.d.ts +22 -0
- package/dist/currency.d.ts.map +1 -0
- package/dist/currency.js +38 -0
- package/dist/currency.js.map +1 -0
- package/dist/decimal.d.ts +52 -0
- package/dist/decimal.d.ts.map +1 -0
- package/dist/decimal.js +251 -0
- package/dist/decimal.js.map +1 -0
- package/dist/drizzle/mysql.d.ts +105 -0
- package/dist/drizzle/mysql.d.ts.map +1 -0
- package/dist/drizzle/mysql.js +60 -0
- package/dist/drizzle/mysql.js.map +1 -0
- package/dist/drizzle/pg.d.ts +103 -0
- package/dist/drizzle/pg.d.ts.map +1 -0
- package/dist/drizzle/pg.js +60 -0
- package/dist/drizzle/pg.js.map +1 -0
- package/dist/drizzle/sqlite.d.ts +102 -0
- package/dist/drizzle/sqlite.d.ts.map +1 -0
- package/dist/drizzle/sqlite.js +59 -0
- package/dist/drizzle/sqlite.js.map +1 -0
- package/dist/ecb.d.ts +52 -0
- package/dist/ecb.d.ts.map +1 -0
- package/dist/ecb.js +285 -0
- package/dist/ecb.js.map +1 -0
- package/dist/exact.d.ts +62 -0
- package/dist/exact.d.ts.map +1 -0
- package/dist/exact.js +147 -0
- package/dist/exact.js.map +1 -0
- package/dist/fed.d.ts +35 -0
- package/dist/fed.d.ts.map +1 -0
- package/dist/fed.js +134 -0
- package/dist/fed.js.map +1 -0
- package/dist/fetch.d.ts +103 -0
- package/dist/fetch.d.ts.map +1 -0
- package/dist/fetch.js +222 -0
- package/dist/fetch.js.map +1 -0
- package/dist/fixed.d.ts +121 -0
- package/dist/fixed.d.ts.map +1 -0
- package/dist/fixed.js +420 -0
- package/dist/fixed.js.map +1 -0
- package/dist/fn.d.ts +34 -0
- package/dist/fn.d.ts.map +1 -0
- package/dist/fn.js +37 -0
- package/dist/fn.js.map +1 -0
- package/dist/format.d.ts +13 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +90 -0
- package/dist/format.js.map +1 -0
- package/dist/generated/adyen.d.ts +3 -0
- package/dist/generated/adyen.d.ts.map +1 -0
- package/dist/generated/adyen.js +144 -0
- package/dist/generated/adyen.js.map +1 -0
- package/dist/generated/braintree.d.ts +3 -0
- package/dist/generated/braintree.d.ts.map +1 -0
- package/dist/generated/braintree.js +140 -0
- package/dist/generated/braintree.js.map +1 -0
- package/dist/generated/cash.d.ts +14 -0
- package/dist/generated/cash.d.ts.map +1 -0
- package/dist/generated/cash.js +465 -0
- package/dist/generated/cash.js.map +1 -0
- package/dist/generated/checkout.d.ts +3 -0
- package/dist/generated/checkout.d.ts.map +1 -0
- package/dist/generated/checkout.js +151 -0
- package/dist/generated/checkout.js.map +1 -0
- package/dist/generated/historic.d.ts +337 -0
- package/dist/generated/historic.d.ts.map +1 -0
- package/dist/generated/historic.js +66 -0
- package/dist/generated/historic.js.map +1 -0
- package/dist/generated/iso4217.d.ts +174 -0
- package/dist/generated/iso4217.d.ts.map +1 -0
- package/dist/generated/iso4217.js +175 -0
- package/dist/generated/iso4217.js.map +1 -0
- package/dist/generated/kernel.d.ts +17 -0
- package/dist/generated/kernel.d.ts.map +1 -0
- package/dist/generated/kernel.js +208 -0
- package/dist/generated/kernel.js.map +1 -0
- package/dist/generated/klarna.d.ts +3 -0
- package/dist/generated/klarna.d.ts.map +1 -0
- package/dist/generated/klarna.js +21 -0
- package/dist/generated/klarna.js.map +1 -0
- package/dist/generated/paypal.d.ts +3 -0
- package/dist/generated/paypal.d.ts.map +1 -0
- package/dist/generated/paypal.js +31 -0
- package/dist/generated/paypal.js.map +1 -0
- package/dist/generated/stripe.d.ts +8 -0
- package/dist/generated/stripe.d.ts.map +1 -0
- package/dist/generated/stripe.js +150 -0
- package/dist/generated/stripe.js.map +1 -0
- package/dist/historic.d.ts +40 -0
- package/dist/historic.d.ts.map +1 -0
- package/dist/historic.js +43 -0
- package/dist/historic.js.map +1 -0
- package/dist/history.d.ts +96 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +213 -0
- package/dist/history.js.map +1 -0
- package/dist/hmrc.d.ts +28 -0
- package/dist/hmrc.d.ts.map +1 -0
- package/dist/hmrc.js +108 -0
- package/dist/hmrc.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/klarna.d.ts +31 -0
- package/dist/klarna.d.ts.map +1 -0
- package/dist/klarna.js +38 -0
- package/dist/klarna.js.map +1 -0
- package/dist/kysely.d.ts +120 -0
- package/dist/kysely.d.ts.map +1 -0
- package/dist/kysely.js +309 -0
- package/dist/kysely.js.map +1 -0
- package/dist/money.d.ts +302 -0
- package/dist/money.d.ts.map +1 -0
- package/dist/money.js +703 -0
- package/dist/money.js.map +1 -0
- package/dist/parse.d.ts +55 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +419 -0
- package/dist/parse.js.map +1 -0
- package/dist/paypal.d.ts +41 -0
- package/dist/paypal.d.ts.map +1 -0
- package/dist/paypal.js +58 -0
- package/dist/paypal.js.map +1 -0
- package/dist/pg.d.ts +100 -0
- package/dist/pg.d.ts.map +1 -0
- package/dist/pg.js +343 -0
- package/dist/pg.js.map +1 -0
- package/dist/plugins/adyen.d.ts +15 -0
- package/dist/plugins/adyen.d.ts.map +1 -0
- package/dist/plugins/adyen.js +10 -0
- package/dist/plugins/adyen.js.map +1 -0
- package/dist/plugins/all.d.ts +29 -0
- package/dist/plugins/all.d.ts.map +1 -0
- package/dist/plugins/all.js +30 -0
- package/dist/plugins/all.js.map +1 -0
- package/dist/plugins/allocate.d.ts +20 -0
- package/dist/plugins/allocate.d.ts.map +1 -0
- package/dist/plugins/allocate.js +26 -0
- package/dist/plugins/allocate.js.map +1 -0
- package/dist/plugins/braintree.d.ts +12 -0
- package/dist/plugins/braintree.d.ts.map +1 -0
- package/dist/plugins/braintree.js +12 -0
- package/dist/plugins/braintree.js.map +1 -0
- package/dist/plugins/cash.d.ts +19 -0
- package/dist/plugins/cash.d.ts.map +1 -0
- package/dist/plugins/cash.js +16 -0
- package/dist/plugins/cash.js.map +1 -0
- package/dist/plugins/checkout.d.ts +21 -0
- package/dist/plugins/checkout.d.ts.map +1 -0
- package/dist/plugins/checkout.js +16 -0
- package/dist/plugins/checkout.js.map +1 -0
- package/dist/plugins/convert.d.ts +19 -0
- package/dist/plugins/convert.d.ts.map +1 -0
- package/dist/plugins/convert.js +13 -0
- package/dist/plugins/convert.js.map +1 -0
- package/dist/plugins/exact.d.ts +15 -0
- package/dist/plugins/exact.d.ts.map +1 -0
- package/dist/plugins/exact.js +13 -0
- package/dist/plugins/exact.js.map +1 -0
- package/dist/plugins/fixed.d.ts +17 -0
- package/dist/plugins/fixed.d.ts.map +1 -0
- package/dist/plugins/fixed.js +13 -0
- package/dist/plugins/fixed.js.map +1 -0
- package/dist/plugins/format.d.ts +9 -0
- package/dist/plugins/format.d.ts.map +1 -0
- package/dist/plugins/format.js +16 -0
- package/dist/plugins/format.js.map +1 -0
- package/dist/plugins/klarna.d.ts +10 -0
- package/dist/plugins/klarna.d.ts.map +1 -0
- package/dist/plugins/klarna.js +10 -0
- package/dist/plugins/klarna.js.map +1 -0
- package/dist/plugins/paypal.d.ts +14 -0
- package/dist/plugins/paypal.d.ts.map +1 -0
- package/dist/plugins/paypal.js +16 -0
- package/dist/plugins/paypal.js.map +1 -0
- package/dist/plugins/prisma.d.ts +8 -0
- package/dist/plugins/prisma.d.ts.map +1 -0
- package/dist/plugins/prisma.js +13 -0
- package/dist/plugins/prisma.js.map +1 -0
- package/dist/plugins/stripe.d.ts +14 -0
- package/dist/plugins/stripe.d.ts.map +1 -0
- package/dist/plugins/stripe.js +16 -0
- package/dist/plugins/stripe.js.map +1 -0
- package/dist/plugins/tax.d.ts +20 -0
- package/dist/plugins/tax.d.ts.map +1 -0
- package/dist/plugins/tax.js +18 -0
- package/dist/plugins/tax.js.map +1 -0
- package/dist/policy.d.ts +34 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +90 -0
- package/dist/policy.js.map +1 -0
- package/dist/prisma.d.ts +77 -0
- package/dist/prisma.d.ts.map +1 -0
- package/dist/prisma.js +76 -0
- package/dist/prisma.js.map +1 -0
- package/dist/processor.d.ts +28 -0
- package/dist/processor.d.ts.map +1 -0
- package/dist/processor.js +118 -0
- package/dist/processor.js.map +1 -0
- package/dist/provider.d.ts +103 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +280 -0
- package/dist/provider.js.map +1 -0
- package/dist/rate-text.d.ts +38 -0
- package/dist/rate-text.d.ts.map +1 -0
- package/dist/rate-text.js +143 -0
- package/dist/rate-text.js.map +1 -0
- package/dist/rate.d.ts +175 -0
- package/dist/rate.d.ts.map +1 -0
- package/dist/rate.js +371 -0
- package/dist/rate.js.map +1 -0
- package/dist/rounding-error.d.ts +9 -0
- package/dist/rounding-error.d.ts.map +1 -0
- package/dist/rounding-error.js +9 -0
- package/dist/rounding-error.js.map +1 -0
- package/dist/rounding.d.ts +50 -0
- package/dist/rounding.d.ts.map +1 -0
- package/dist/rounding.js +87 -0
- package/dist/rounding.js.map +1 -0
- package/dist/schema.d.ts +43 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +77 -0
- package/dist/schema.js.map +1 -0
- package/dist/sql.d.ts +54 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +131 -0
- package/dist/sql.js.map +1 -0
- package/dist/stripe-fx.d.ts +22 -0
- package/dist/stripe-fx.d.ts.map +1 -0
- package/dist/stripe-fx.js +30 -0
- package/dist/stripe-fx.js.map +1 -0
- package/dist/stripe.d.ts +36 -0
- package/dist/stripe.d.ts.map +1 -0
- package/dist/stripe.js +39 -0
- package/dist/stripe.js.map +1 -0
- package/dist/tax.d.ts +33 -0
- package/dist/tax.d.ts.map +1 -0
- package/dist/tax.js +55 -0
- package/dist/tax.js.map +1 -0
- package/dist/testing/arbitraries.d.ts +43 -0
- package/dist/testing/arbitraries.d.ts.map +1 -0
- package/dist/testing/arbitraries.js +98 -0
- package/dist/testing/arbitraries.js.map +1 -0
- package/dist/testing/index.d.ts +67 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +159 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/jest.d.ts +2 -0
- package/dist/testing/jest.d.ts.map +1 -0
- package/dist/testing/jest.js +15 -0
- package/dist/testing/jest.js.map +1 -0
- package/dist/testing/vitest.d.ts +7 -0
- package/dist/testing/vitest.d.ts.map +1 -0
- package/dist/testing/vitest.js +12 -0
- package/dist/testing/vitest.js.map +1 -0
- package/dist/valibot.d.ts +33 -0
- package/dist/valibot.d.ts.map +1 -0
- package/dist/valibot.js +61 -0
- package/dist/valibot.js.map +1 -0
- package/dist/zod.d.ts +36 -0
- package/dist/zod.d.ts.map +1 -0
- package/dist/zod.js +58 -0
- package/dist/zod.js.map +1 -0
- package/package.json +280 -5
- package/src/adyen-fx.ts +175 -0
- package/src/adyen.ts +46 -0
- package/src/allocate.ts +393 -0
- package/src/bag.ts +170 -0
- package/src/boc.ts +136 -0
- package/src/boe.ts +131 -0
- package/src/braintree.ts +71 -0
- package/src/cash.ts +183 -0
- package/src/checkout.ts +77 -0
- package/src/convert.ts +177 -0
- package/src/currency.ts +61 -0
- package/src/decimal.ts +283 -0
- package/src/drizzle/mysql.ts +78 -0
- package/src/drizzle/pg.ts +78 -0
- package/src/drizzle/sqlite.ts +70 -0
- package/src/ecb.ts +328 -0
- package/src/exact.ts +182 -0
- package/src/fed.ts +146 -0
- package/src/fetch.ts +306 -0
- package/src/fixed.ts +558 -0
- package/src/fn.ts +94 -0
- package/src/format.ts +106 -0
- package/src/generated/adyen.ts +144 -0
- package/src/generated/braintree.ts +140 -0
- package/src/generated/cash.ts +478 -0
- package/src/generated/checkout.ts +151 -0
- package/src/generated/historic.ts +67 -0
- package/src/generated/iso4217.ts +179 -0
- package/src/generated/kernel.ts +230 -0
- package/src/generated/klarna.ts +21 -0
- package/src/generated/paypal.ts +31 -0
- package/src/generated/stripe.ts +150 -0
- package/src/historic.ts +77 -0
- package/src/history.ts +333 -0
- package/src/hmrc.ts +125 -0
- package/src/index.ts +41 -0
- package/src/klarna.ts +54 -0
- package/src/kysely.ts +588 -0
- package/src/money.ts +979 -0
- package/src/parse.ts +511 -0
- package/src/paypal.ts +93 -0
- package/src/pg.ts +410 -0
- package/src/plugins/adyen.ts +25 -0
- package/src/plugins/all.ts +57 -0
- package/src/plugins/allocate.ts +53 -0
- package/src/plugins/braintree.ts +23 -0
- package/src/plugins/cash.ts +33 -0
- package/src/plugins/checkout.ts +32 -0
- package/src/plugins/convert.ts +49 -0
- package/src/plugins/exact.ts +23 -0
- package/src/plugins/fixed.ts +28 -0
- package/src/plugins/format.ts +28 -0
- package/src/plugins/klarna.ts +21 -0
- package/src/plugins/paypal.ts +29 -0
- package/src/plugins/prisma.ts +24 -0
- package/src/plugins/stripe.ts +29 -0
- package/src/plugins/tax.ts +40 -0
- package/src/policy.ts +124 -0
- package/src/prisma.ts +199 -0
- package/src/processor.ts +181 -0
- package/src/provider.ts +389 -0
- package/src/rate-text.ts +151 -0
- package/src/rate.ts +546 -0
- package/src/rounding-error.ts +8 -0
- package/src/rounding.ts +122 -0
- package/src/schema.ts +119 -0
- package/src/sql.ts +178 -0
- package/src/stripe-fx.ts +49 -0
- package/src/stripe.ts +69 -0
- package/src/tax.ts +102 -0
- package/src/testing/arbitraries.ts +134 -0
- package/src/testing/index.ts +247 -0
- package/src/testing/jest.ts +18 -0
- package/src/testing/vitest.ts +18 -0
- package/src/valibot.ts +87 -0
- package/src/zod.ts +78 -0
package/dist/cash.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { CASH_RULES } from './generated/cash.js';
|
|
2
|
+
import { CurrencyMismatchError, make, scaleUp, toScale, } from './money.js';
|
|
3
|
+
import { roundingPolicy } from './policy.js';
|
|
4
|
+
import { divideAndRound, divideAndRoundBigint } from './rounding.js';
|
|
5
|
+
import { currencyExponent } from './currency.js';
|
|
6
|
+
/**
|
|
7
|
+
* Rounds to a multiple of `increment` (same currency): roundToIncrement(CHF 10.03, CHF 0.05) = CHF
|
|
8
|
+
* 10.05. Default rounding 'halfExpand' (nearest, ties away from zero), which is what the statutory
|
|
9
|
+
* cash-rounding rules (SE, NO, DK, HU, CZ, FI, BE ...) prescribe.
|
|
10
|
+
*/
|
|
11
|
+
export function roundToIncrement(money, increment, rounding = 'halfExpand') {
|
|
12
|
+
if (money.currency !== increment.currency) {
|
|
13
|
+
throw new CurrencyMismatchError(money.currency, increment.currency);
|
|
14
|
+
}
|
|
15
|
+
if (!(increment.minor > 0)) {
|
|
16
|
+
throw new RangeError('increment must be positive');
|
|
17
|
+
}
|
|
18
|
+
const scale = Math.max(money.scale, increment.scale);
|
|
19
|
+
const minor = scaleUp(money.minor, scale - money.scale);
|
|
20
|
+
const step = scaleUp(increment.minor, scale - increment.scale);
|
|
21
|
+
if (typeof minor === 'number' && typeof step === 'number') {
|
|
22
|
+
const steps = divideAndRound(minor, step, rounding);
|
|
23
|
+
const rounded = steps * step;
|
|
24
|
+
if (Number.isSafeInteger(rounded)) {
|
|
25
|
+
return toScale(make(money.currency, rounded, scale), money.scale > scale ? money.scale : scale);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return make(money.currency, divideAndRoundBigint(BigInt(minor), BigInt(step), rounding) * BigInt(step), scale);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The cash-rounding rule for a currency, optionally narrowed by country (ISO 3166 alpha-2).
|
|
32
|
+
* EUR has no euro-wide rule: pass the country (BE, NL, FI, IE, IT, SK, EE, LT).
|
|
33
|
+
*/
|
|
34
|
+
export function cashRule(currency, country) {
|
|
35
|
+
const rules = cashRulesFor(currency);
|
|
36
|
+
if (rules === undefined) {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
if (country !== undefined) {
|
|
40
|
+
for (let i = 0; i < rules.length; i++) {
|
|
41
|
+
if (rules[i].countries.includes(country)) {
|
|
42
|
+
return rules[i];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
// EUR has no euro-wide rule, so it needs a country
|
|
48
|
+
if (currency === 'EUR') {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
return rules[0];
|
|
52
|
+
}
|
|
53
|
+
// CASH_RULES grouped by currency, in table order. Built on first use, not at import, so the module
|
|
54
|
+
// stays free of side effects; cashRound calls cashRule on every amount, and a scan of the whole table
|
|
55
|
+
// was most of its cost.
|
|
56
|
+
let rulesByCurrency;
|
|
57
|
+
function cashRulesFor(currency) {
|
|
58
|
+
if (rulesByCurrency === undefined) {
|
|
59
|
+
rulesByCurrency = new Map();
|
|
60
|
+
for (let i = 0; i < CASH_RULES.length; i++) {
|
|
61
|
+
const rule = CASH_RULES[i];
|
|
62
|
+
const forCurrency = rulesByCurrency.get(rule.currency);
|
|
63
|
+
if (forCurrency === undefined) {
|
|
64
|
+
rulesByCurrency.set(rule.currency, [rule]);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
forCurrency.push(rule);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return rulesByCurrency.get(currency);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Rounds a cash total to the smallest legal/practical cash step (CHF 0.05, SEK 1, DKK 0.50, CAD
|
|
75
|
+
* 0.05, HUF 5, EUR 0.05 in BE/NL/FI/IE/...). Card and other electronic payments are NOT rounded:
|
|
76
|
+
* only call this for cash tenders. Returns m unchanged when no rule applies.
|
|
77
|
+
*/
|
|
78
|
+
export function cashRound(money, options) {
|
|
79
|
+
const rule = cashRule(money.currency, options?.country);
|
|
80
|
+
if (!rule || (options?.includeUnverified === false && !rule.verified)) {
|
|
81
|
+
return money;
|
|
82
|
+
}
|
|
83
|
+
const inc = make(money.currency, rule.increment, currencyExponent(money.currency));
|
|
84
|
+
return roundToIncrement(money, inc, options?.rounding ?? rule.rounding ?? 'halfExpand');
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* The cash-rounding rule for a currency as a `RoundingPolicy`, to pass wherever a rounding mode
|
|
88
|
+
* goes: `m.multiply('1.075', cashPolicy('CHF'))` rounds once, straight to CHF 0.05. The policy only
|
|
89
|
+
* accepts amounts in `currency`. Throws a RangeError when no rule applies (EUR needs a country);
|
|
90
|
+
* use `isoPolicy` for currencies without cash rounding.
|
|
91
|
+
*/
|
|
92
|
+
export function cashPolicy(currency, options) {
|
|
93
|
+
const rule = cashRule(currency, options?.country);
|
|
94
|
+
if (!rule || (options?.includeUnverified === false && !rule.verified)) {
|
|
95
|
+
const where = options?.country === undefined ? '' : ` in ${options.country}`;
|
|
96
|
+
throw new RangeError(`No cash-rounding rule for ${currency}${where}`);
|
|
97
|
+
}
|
|
98
|
+
return roundingPolicy({
|
|
99
|
+
scale: currencyExponent(currency),
|
|
100
|
+
increment: rule.increment,
|
|
101
|
+
rounding: options?.rounding ?? rule.rounding ?? 'halfExpand',
|
|
102
|
+
currency,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The number of decimals a currency's amounts are shown with: its ISO 4217 exponent, or with
|
|
107
|
+
* `{ usage: 'cash' }`, the decimals of a cash amount (what CLDR calls `cashDigits`): none when cash
|
|
108
|
+
* is rounded to whole units, the exponent otherwise.
|
|
109
|
+
*
|
|
110
|
+
* currencyDigits('SEK') // 2
|
|
111
|
+
* currencyDigits('SEK', { usage: 'cash' }) // 0: cash is rounded to whole kronor
|
|
112
|
+
* currencyDigits('CHF', { usage: 'cash' }) // 2: CHF 0.05 still needs two decimals
|
|
113
|
+
*
|
|
114
|
+
* A currency without a cash rule (or EUR without a country that has one) takes its exponent.
|
|
115
|
+
* Throws for unknown codes, like `currencyExponent`.
|
|
116
|
+
*/
|
|
117
|
+
export function currencyDigits(currency, options) {
|
|
118
|
+
const exponent = currencyExponent(currency);
|
|
119
|
+
if (options?.usage !== 'cash') {
|
|
120
|
+
return exponent;
|
|
121
|
+
}
|
|
122
|
+
const rule = cashRule(currency, options.country);
|
|
123
|
+
if (!rule || (options.includeUnverified === false && !rule.verified)) {
|
|
124
|
+
return exponent;
|
|
125
|
+
}
|
|
126
|
+
// Cash amounts show no decimals once the step is whole units (SEK 1, HUF 5, UZS 50), and the
|
|
127
|
+
// currency's usual decimals otherwise: DKK 0.50 is shown as 10.50, not 10.5, as in CLDR.
|
|
128
|
+
if (rule.increment % 10 ** exponent === 0) {
|
|
129
|
+
return 0;
|
|
130
|
+
}
|
|
131
|
+
return exponent;
|
|
132
|
+
}
|
|
133
|
+
export { CASH_RULES };
|
|
134
|
+
//# sourceMappingURL=cash.js.map
|
package/dist/cash.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cash.js","sourceRoot":"","sources":["../src/cash.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkout.com's amount view (https://www.checkout.com/docs/payments/accept-payments/format-the-amount-value,
|
|
3
|
+
* encoded in data/checkout.json). `amount` is an integer:
|
|
4
|
+
* - the full amount: BIF DJF GNF ISK JPY KMF KRW PYG RWF UGX VUV VND XAF XOF XPF
|
|
5
|
+
* - divided by 1000, last digit 0: BHD IQD JOD KWD LYD OMR TND
|
|
6
|
+
* - divided by 100 for every other currency. CLP is here too (ISO says 0 decimals), and for payment
|
|
7
|
+
* requests its last two digits must be 00 (5000 CLP -> 500000). Standalone authentication is
|
|
8
|
+
* exempt.
|
|
9
|
+
*/
|
|
10
|
+
import { CHECKOUT_RULES } from './generated/checkout.js';
|
|
11
|
+
import { type CurrencyInput, type Money } from './money.js';
|
|
12
|
+
import type { RoundingMode } from './rounding.js';
|
|
13
|
+
export { CHECKOUT_RULES };
|
|
14
|
+
/** Whether Checkout.com lists the currency (case-insensitive). */
|
|
15
|
+
export declare function isCheckoutCurrency(currency: string): boolean;
|
|
16
|
+
/** The exponent Checkout.com's API uses for a currency (CLP 2, JPY 0, BHD 3). */
|
|
17
|
+
export declare function checkoutExponent(currency: string): number;
|
|
18
|
+
/** Options for the Checkout.com amount: how to round when Checkout.com needs a coarser amount. */
|
|
19
|
+
export interface CheckoutAmountOptions {
|
|
20
|
+
/** How to round when Checkout.com needs a coarser amount (default 'unnecessary': throw). */
|
|
21
|
+
readonly rounding?: RoundingMode;
|
|
22
|
+
/**
|
|
23
|
+
* An authentication request to the Standalone API, where CLP's "last two digits 00" rule does not
|
|
24
|
+
* apply.
|
|
25
|
+
*/
|
|
26
|
+
readonly standalone?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The integer `amount` to send, e.g. toCheckoutAmount(money('5000', 'CLP')) === 500000.
|
|
30
|
+
* Throws a RangeError for negative amounts (refunds are sent as positive amounts).
|
|
31
|
+
* SLL and XDR are on Checkout.com's list but not in ISO 4217's active list: call
|
|
32
|
+
* `defineCurrency('SLL', 2)` or `defineCurrency('XDR', 2)` before using them.
|
|
33
|
+
*/
|
|
34
|
+
export declare function toCheckoutAmount(money: Money, options?: CheckoutAmountOptions): number;
|
|
35
|
+
/** `{ amount, currency }` for a payment request. */
|
|
36
|
+
export declare function toCheckout(money: Money, options?: CheckoutAmountOptions): {
|
|
37
|
+
amount: number;
|
|
38
|
+
currency: string;
|
|
39
|
+
};
|
|
40
|
+
/** Reads a Checkout.com amount: fromCheckout(500000, 'CLP') is 5000 CLP. */
|
|
41
|
+
export declare function fromCheckout<C extends CurrencyInput>(amount: number | bigint, currency: C): Money<Uppercase<C>>;
|
|
42
|
+
//# sourceMappingURL=checkout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout.d.ts","sourceRoot":"","sources":["../src/checkout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAE5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,CAAC;AAW1B,kEAAkE;AAClE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED,kGAAkG;AAClG,MAAM,WAAW,qBAAqB;IACpC,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC;IACjC;;;OAGG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,MAAM,CAOtF;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CACxB,KAAK,EAAE,KAAK,EACZ,OAAO,CAAC,EAAE,qBAAqB,GAC9B;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAEtC;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,CAAC,SAAS,aAAa,EAClD,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,QAAQ,EAAE,CAAC,GACV,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAGrB"}
|
package/dist/checkout.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkout.com's amount view (https://www.checkout.com/docs/payments/accept-payments/format-the-amount-value,
|
|
3
|
+
* encoded in data/checkout.json). `amount` is an integer:
|
|
4
|
+
* - the full amount: BIF DJF GNF ISK JPY KMF KRW PYG RWF UGX VUV VND XAF XOF XPF
|
|
5
|
+
* - divided by 1000, last digit 0: BHD IQD JOD KWD LYD OMR TND
|
|
6
|
+
* - divided by 100 for every other currency. CLP is here too (ISO says 0 decimals), and for payment
|
|
7
|
+
* requests its last two digits must be 00 (5000 CLP -> 500000). Standalone authentication is
|
|
8
|
+
* exempt.
|
|
9
|
+
*/
|
|
10
|
+
import { CHECKOUT_RULES } from './generated/checkout.js';
|
|
11
|
+
import {} from './money.js';
|
|
12
|
+
import { fromProcessorAmount, toProcessorAmount } from './processor.js';
|
|
13
|
+
export { CHECKOUT_RULES };
|
|
14
|
+
/** Checkout.com's [exponent, payment multiple, Standalone API multiple] for a currency. */
|
|
15
|
+
function rulesFor(currency) {
|
|
16
|
+
const rules = CHECKOUT_RULES[currency.toUpperCase()];
|
|
17
|
+
if (!rules) {
|
|
18
|
+
throw new RangeError(`${currency} is not a Checkout.com currency`);
|
|
19
|
+
}
|
|
20
|
+
return rules;
|
|
21
|
+
}
|
|
22
|
+
/** Whether Checkout.com lists the currency (case-insensitive). */
|
|
23
|
+
export function isCheckoutCurrency(currency) {
|
|
24
|
+
return CHECKOUT_RULES[currency.toUpperCase()] !== undefined;
|
|
25
|
+
}
|
|
26
|
+
/** The exponent Checkout.com's API uses for a currency (CLP 2, JPY 0, BHD 3). */
|
|
27
|
+
export function checkoutExponent(currency) {
|
|
28
|
+
return rulesFor(currency)[0];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The integer `amount` to send, e.g. toCheckoutAmount(money('5000', 'CLP')) === 500000.
|
|
32
|
+
* Throws a RangeError for negative amounts (refunds are sent as positive amounts).
|
|
33
|
+
* SLL and XDR are on Checkout.com's list but not in ISO 4217's active list: call
|
|
34
|
+
* `defineCurrency('SLL', 2)` or `defineCurrency('XDR', 2)` before using them.
|
|
35
|
+
*/
|
|
36
|
+
export function toCheckoutAmount(money, options) {
|
|
37
|
+
const [exponent, paymentMultiple, standaloneMultiple] = rulesFor(money.currency);
|
|
38
|
+
const multiple = options?.standalone ? standaloneMultiple : paymentMultiple;
|
|
39
|
+
const rounding = options?.rounding ?? 'unnecessary';
|
|
40
|
+
// "Be greater than zero", except 0 for a card verification (API reference); refunds are positive.
|
|
41
|
+
return toProcessorAmount('Checkout.com', money, exponent, multiple, rounding, 'nonNegative');
|
|
42
|
+
}
|
|
43
|
+
/** `{ amount, currency }` for a payment request. */
|
|
44
|
+
export function toCheckout(money, options) {
|
|
45
|
+
return { amount: toCheckoutAmount(money, options), currency: money.currency.toUpperCase() };
|
|
46
|
+
}
|
|
47
|
+
/** Reads a Checkout.com amount: fromCheckout(500000, 'CLP') is 5000 CLP. */
|
|
48
|
+
export function fromCheckout(amount, currency) {
|
|
49
|
+
const code = currency.toUpperCase();
|
|
50
|
+
return fromProcessorAmount('Checkout.com', amount, code, checkoutExponent(code));
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=checkout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout.js","sourceRoot":"","sources":["../src/checkout.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAkC,MAAM,YAAY,CAAC;AAC5D,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGxE,OAAO,EAAE,cAAc,EAAE,CAAC;AAE1B,2FAA2F;AAC3F,SAAS,QAAQ,CAAC,QAAgB;IAChC,MAAM,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;IACrD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,UAAU,CAAC,GAAG,QAAQ,iCAAiC,CAAC,CAAC;IACrE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,kEAAkE;AAClE,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,cAAc,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,KAAK,SAAS,CAAC;AAC9D,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,OAAO,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/B,CAAC;AAaD;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAY,EAAE,OAA+B;IAC5E,MAAM,CAAC,QAAQ,EAAE,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,eAAe,CAAC;IAC5E,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,aAAa,CAAC;IAEpD,kGAAkG;IAClG,OAAO,iBAAiB,CAAC,cAAc,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,CAAC,CAAC;AAC/F,CAAC;AAED,oDAAoD;AACpD,MAAM,UAAU,UAAU,CACxB,KAAY,EACZ,OAA+B;IAE/B,OAAO,EAAE,MAAM,EAAE,gBAAgB,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;AAC9F,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,YAAY,CAC1B,MAAuB,EACvB,QAAW;IAEX,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAkB,CAAC;IACpD,OAAO,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC;AACnF,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type Rounded } from './exact.js';
|
|
2
|
+
import { type Factor } from './decimal.js';
|
|
3
|
+
import { type CurrencyInput, type Money, type RoundingInput } from './money.js';
|
|
4
|
+
import { type RateProvider } from './provider.js';
|
|
5
|
+
import { type ConvertOptions, type Rate } from './rate.js';
|
|
6
|
+
export { exchangeRate, impliedRate, isRate, multiplyByRatioAtScale, Rate, RateExpiredError, rateFromJSON, type ConvertOptions, type RateInfo, type RateJSON, type RateQuote, type RateType, } from './rate.js';
|
|
7
|
+
export { bag, comparator, MoneyBag, sortByValue, sumByCurrency, type ComparatorOptions, type TotalOptions, } from './bag.js';
|
|
8
|
+
export { chain, identity, rateOf, rateTable, RateUnavailableError, reversed, snapshots, snapshotsFrom, via, type RateProvider, type RateQuery, type RateTable, type RateTableSpec, type SnapshotOptions, type Snapshots, } from './provider.js';
|
|
9
|
+
/** Options for converting through a provider. */
|
|
10
|
+
export interface ProviderConvertOptions extends ConvertOptions {
|
|
11
|
+
/** The time the rate is wanted for (an ISO-8601 date or instant, or a Date). */
|
|
12
|
+
readonly asOf?: string | Date;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Converts `money` at a Rate, rounding once to the target currency's exponent (or `options.scale`),
|
|
16
|
+
* or with a rounding policy to its scale and increment (`@ducatjs/money/policy`).
|
|
17
|
+
* The rate's pair is checked, at compile time for literal currencies and at run time otherwise.
|
|
18
|
+
*
|
|
19
|
+
* convert(money('100', 'EUR'), eurUsd, 'halfEven') // 111.65 USD
|
|
20
|
+
* convert(money('100', 'USD'), eurUsd.inverse().andThen(eurJpy)) // composed exactly, rounded once
|
|
21
|
+
*/
|
|
22
|
+
export declare function convert<From extends string, To extends string>(money: Money<From>, rate: Rate<NoInfer<From>, To>, rounding?: RoundingInput, options?: ConvertOptions): Money<To>;
|
|
23
|
+
/**
|
|
24
|
+
* Converts at a bare rate: units of `to` per unit of money's currency, as a decimal string so that
|
|
25
|
+
* no float is involved ('1.0832', every digit kept). Rounds once.
|
|
26
|
+
*
|
|
27
|
+
* convert(money('100', 'EUR'), 'JPY', '162.457', 'halfEven') // 16246 JPY
|
|
28
|
+
*/
|
|
29
|
+
export declare function convert<To extends CurrencyInput>(money: Money, to: To, rate: Factor, rounding?: RoundingInput, options?: ConvertOptions): Money<To>;
|
|
30
|
+
/**
|
|
31
|
+
* Converts through a provider: looks up money's currency → `to` (as of `options.asOf`) and rounds
|
|
32
|
+
* once. Throws RateUnavailableError when the provider has no rate.
|
|
33
|
+
*
|
|
34
|
+
* convert(money('100', 'USD'), 'JPY', via('EUR', ecb), 'halfEven')
|
|
35
|
+
*/
|
|
36
|
+
export declare function convert<To extends CurrencyInput>(money: Money, to: To, provider: RateProvider, rounding?: RoundingInput, options?: ProviderConvertOptions): Money<To>;
|
|
37
|
+
/**
|
|
38
|
+
* A conversion's rounded value, what rounding left out, and the rate used (for the audit trail).
|
|
39
|
+
*/
|
|
40
|
+
export interface DetailedConversion<From extends string, To extends string> extends Rounded<To> {
|
|
41
|
+
readonly rate: Rate<From, To>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Converts at `rate` like convert(), and also reports the residual: `value + residual` is exactly
|
|
45
|
+
* money × rate, so a ledger can book the rounding difference. With a rounding policy, the value
|
|
46
|
+
* is on the policy's scale and increment, and the residual is still the exact difference.
|
|
47
|
+
*
|
|
48
|
+
* const { value, residual } = convertDetailed(money('0.07', 'EUR'), eurUsd, 'halfEven');
|
|
49
|
+
* // value 0.08 USD, residual -0.001845 USD (as an exact ExactMoney)
|
|
50
|
+
*/
|
|
51
|
+
export declare function convertDetailed<From extends string, To extends string>(money: Money<From>, rate: Rate<NoInfer<From>, To>, rounding?: RoundingInput, options?: ConvertOptions): DetailedConversion<From, To>;
|
|
52
|
+
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAEA,OAAO,EAAS,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAS,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,EAAQ,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EAAU,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,IAAI,EACV,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,YAAY,EACZ,WAAW,EACX,MAAM,EACN,sBAAsB,EACtB,IAAI,EACJ,gBAAgB,EAChB,YAAY,EACZ,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,QAAQ,EACb,KAAK,SAAS,EACd,KAAK,QAAQ,GACd,MAAM,WAAW,CAAC;AACnB,OAAO,EACL,GAAG,EACH,UAAU,EACV,QAAQ,EACR,WAAW,EACX,aAAa,EACb,KAAK,iBAAiB,EACtB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,EACL,QAAQ,EACR,MAAM,EACN,SAAS,EACT,oBAAoB,EACpB,QAAQ,EACR,SAAS,EACT,aAAa,EACb,GAAG,EACH,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,eAAe,CAAC;AAEvB,iDAAiD;AACjD,MAAM,WAAW,sBAAuB,SAAQ,cAAc;IAC5D,gFAAgF;IAChF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAMD;;;;;;;GAOG;AACH,wBAAgB,OAAO,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,EAC5D,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAC7B,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,cAAc,GACvB,KAAK,CAAC,EAAE,CAAC,CAAC;AACb;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,SAAS,aAAa,EAC9C,KAAK,EAAE,KAAK,EACZ,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,cAAc,GACvB,KAAK,CAAC,EAAE,CAAC,CAAC;AACb;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,EAAE,SAAS,aAAa,EAC9C,KAAK,EAAE,KAAK,EACZ,EAAE,EAAE,EAAE,EACN,QAAQ,EAAE,YAAY,EACtB,QAAQ,CAAC,EAAE,aAAa,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,KAAK,CAAC,EAAE,CAAC,CAAC;AA0Cb;;GAEG;AACH,MAAM,WAAW,kBAAkB,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,CAAE,SAAQ,OAAO,CAAC,EAAE,CAAC;IAC7F,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,IAAI,SAAS,MAAM,EAAE,EAAE,SAAS,MAAM,EACpE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,EAClB,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAC7B,QAAQ,GAAE,aAAgC,EAC1C,OAAO,CAAC,EAAE,cAAc,GACvB,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC,CAS9B"}
|
package/dist/convert.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// `ducat/convert` free functions: exact exchange rates and conversion that rounds once.
|
|
2
|
+
import { currencyExponent } from './currency.js';
|
|
3
|
+
import { exact } from './exact.js';
|
|
4
|
+
import { ratio } from './decimal.js';
|
|
5
|
+
import { make } from './money.js';
|
|
6
|
+
import { rateOf } from './provider.js';
|
|
7
|
+
import { convertWithPolicy, isRate, multiplyByRatioAtScale, } from './rate.js';
|
|
8
|
+
import { DEFAULT_ROUNDING } from './rounding.js';
|
|
9
|
+
export { exchangeRate, impliedRate, isRate, multiplyByRatioAtScale, Rate, RateExpiredError, rateFromJSON, } from './rate.js';
|
|
10
|
+
export { bag, comparator, MoneyBag, sortByValue, sumByCurrency, } from './bag.js';
|
|
11
|
+
export { chain, identity, rateOf, rateTable, RateUnavailableError, reversed, snapshots, snapshotsFrom, via, } from './provider.js';
|
|
12
|
+
function isProvider(value) {
|
|
13
|
+
return typeof value?.rate === 'function';
|
|
14
|
+
}
|
|
15
|
+
export function convert(money, rateOrTarget, roundingOrRate, optionsOrRounding, maybeOptions) {
|
|
16
|
+
if (isRate(rateOrTarget)) {
|
|
17
|
+
const rounding = roundingOrRate;
|
|
18
|
+
return rateOrTarget.convert(money, rounding, optionsOrRounding);
|
|
19
|
+
}
|
|
20
|
+
const to = rateOrTarget;
|
|
21
|
+
if (isProvider(roundingOrRate)) {
|
|
22
|
+
let query;
|
|
23
|
+
if (maybeOptions?.asOf !== undefined) {
|
|
24
|
+
query = { asOf: maybeOptions.asOf };
|
|
25
|
+
}
|
|
26
|
+
const rate = rateOf(roundingOrRate, money.currency, to, query);
|
|
27
|
+
return rate.convert(money, optionsOrRounding, maybeOptions);
|
|
28
|
+
}
|
|
29
|
+
// The bare-rate form converts directly, without building a Rate, to keep it allocation-light.
|
|
30
|
+
let rate = ratio(roundingOrRate);
|
|
31
|
+
if (typeof roundingOrRate === 'object') {
|
|
32
|
+
// A hand-made Ratio object is passed through by ratio(); rebuild it so it is reduced and its
|
|
33
|
+
// number fields match its bigints. Strings and numbers are already normalised (and cached).
|
|
34
|
+
rate = ratio(rate.num, rate.den);
|
|
35
|
+
}
|
|
36
|
+
if (rate.num <= 0n) {
|
|
37
|
+
throw new RangeError('Exchange rate must be positive');
|
|
38
|
+
}
|
|
39
|
+
const rounding = optionsOrRounding ?? DEFAULT_ROUNDING;
|
|
40
|
+
if (typeof rounding === 'function') {
|
|
41
|
+
return convertWithPolicy(money, to, rate, rounding, maybeOptions);
|
|
42
|
+
}
|
|
43
|
+
const scale = maybeOptions?.scale ?? currencyExponent(to);
|
|
44
|
+
const minor = multiplyByRatioAtScale(money.minor, rate, scale - money.scale, rounding);
|
|
45
|
+
return make(to, minor, scale);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Converts at `rate` like convert(), and also reports the residual: `value + residual` is exactly
|
|
49
|
+
* money × rate, so a ledger can book the rounding difference. With a rounding policy, the value
|
|
50
|
+
* is on the policy's scale and increment, and the residual is still the exact difference.
|
|
51
|
+
*
|
|
52
|
+
* const { value, residual } = convertDetailed(money('0.07', 'EUR'), eurUsd, 'halfEven');
|
|
53
|
+
* // value 0.08 USD, residual -0.001845 USD (as an exact ExactMoney)
|
|
54
|
+
*/
|
|
55
|
+
export function convertDetailed(money, rate, rounding = DEFAULT_ROUNDING, options) {
|
|
56
|
+
const converted = exact(money).convert(rate);
|
|
57
|
+
if (typeof rounding === 'function') {
|
|
58
|
+
// The policy rounds; the residual is still exactly what it left out.
|
|
59
|
+
const value = rate.convert(money, rounding, options);
|
|
60
|
+
return { value, residual: converted.subtract(exact(value)), rate };
|
|
61
|
+
}
|
|
62
|
+
const rounded = converted.roundWithResidual(rounding, options?.scale);
|
|
63
|
+
return { value: rounded.value, residual: rounded.residual, rate };
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=convert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.js","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type IsoCurrencyCode } from './generated/iso4217.js';
|
|
2
|
+
/**
|
|
3
|
+
* Augment this interface to add non-ISO currencies to the `CurrencyCode` type:
|
|
4
|
+
*
|
|
5
|
+
* declare module '@ducatjs/money' { interface CustomCurrencies { BTC: true; USDC: true } }
|
|
6
|
+
* defineCurrency('BTC', 8);
|
|
7
|
+
*/
|
|
8
|
+
export interface CustomCurrencies {
|
|
9
|
+
}
|
|
10
|
+
/** A known currency code: ISO 4217, or one added to `CustomCurrencies`. */
|
|
11
|
+
export type CurrencyCode = IsoCurrencyCode | (keyof CustomCurrencies & string);
|
|
12
|
+
/**
|
|
13
|
+
* Registers a currency that is not in ISO 4217 (crypto, loyalty points, withdrawn codes you still
|
|
14
|
+
* hold balances in). ISO codes cannot be redefined: use an explicit `scale` for extra precision.
|
|
15
|
+
*/
|
|
16
|
+
export declare function defineCurrency(code: string, exponent: number): void;
|
|
17
|
+
/** The minor-unit exponent of a currency (EUR 2, JPY 0, KWD 3). Throws for unknown codes. */
|
|
18
|
+
export declare function currencyExponent(code: string): number;
|
|
19
|
+
/** Whether the code is an ISO 4217 currency or one registered with `defineCurrency`. */
|
|
20
|
+
export declare function isCurrency(code: string): code is CurrencyCode;
|
|
21
|
+
export { ISO_EXPONENTS, ISO_4217_PUBLISHED, ISO_NON_MONETARY, type IsoCurrencyCode, } from './generated/iso4217.js';
|
|
22
|
+
//# sourceMappingURL=currency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency.d.ts","sourceRoot":"","sources":["../src/currency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE7E;;;;;GAKG;AAEH,MAAM,WAAW,gBAAgB;CAAG;AAEpC,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,eAAe,GAAG,CAAC,MAAM,gBAAgB,GAAG,MAAM,CAAC,CAAC;AAK/E;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAYnE;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAYrD;AAED,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,IAAI,YAAY,CAE7D;AAED,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,eAAe,GACrB,MAAM,wBAAwB,CAAC"}
|
package/dist/currency.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ISO_EXPONENTS } from './generated/iso4217.js';
|
|
2
|
+
const custom = new Map();
|
|
3
|
+
const iso = ISO_EXPONENTS;
|
|
4
|
+
/**
|
|
5
|
+
* Registers a currency that is not in ISO 4217 (crypto, loyalty points, withdrawn codes you still
|
|
6
|
+
* hold balances in). ISO codes cannot be redefined: use an explicit `scale` for extra precision.
|
|
7
|
+
*/
|
|
8
|
+
export function defineCurrency(code, exponent) {
|
|
9
|
+
if (!Number.isInteger(exponent) || exponent < 0 || exponent > 30) {
|
|
10
|
+
throw new RangeError(`Invalid exponent ${exponent}`);
|
|
11
|
+
}
|
|
12
|
+
if (typeof iso[code] === 'number') {
|
|
13
|
+
throw new TypeError(`${code} is an ISO 4217 currency and cannot be redefined`);
|
|
14
|
+
}
|
|
15
|
+
const prev = custom.get(code);
|
|
16
|
+
if (prev !== undefined && prev !== exponent) {
|
|
17
|
+
throw new TypeError(`${code} is already defined with exponent ${prev}`);
|
|
18
|
+
}
|
|
19
|
+
custom.set(code, exponent);
|
|
20
|
+
}
|
|
21
|
+
/** The minor-unit exponent of a currency (EUR 2, JPY 0, KWD 3). Throws for unknown codes. */
|
|
22
|
+
export function currencyExponent(code) {
|
|
23
|
+
const isoExponent = iso[code];
|
|
24
|
+
if (typeof isoExponent === 'number') {
|
|
25
|
+
return isoExponent;
|
|
26
|
+
}
|
|
27
|
+
const customExponent = custom.get(code);
|
|
28
|
+
if (customExponent !== undefined) {
|
|
29
|
+
return customExponent;
|
|
30
|
+
}
|
|
31
|
+
throw new RangeError(`Unknown currency "${code}" (not ISO 4217 and not registered with defineCurrency)`);
|
|
32
|
+
}
|
|
33
|
+
/** Whether the code is an ISO 4217 currency or one registered with `defineCurrency`. */
|
|
34
|
+
export function isCurrency(code) {
|
|
35
|
+
return typeof iso[code] === 'number' || custom.has(code);
|
|
36
|
+
}
|
|
37
|
+
export { ISO_EXPONENTS, ISO_4217_PUBLISHED, ISO_NON_MONETARY, } from './generated/iso4217.js';
|
|
38
|
+
//# sourceMappingURL=currency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency.js","sourceRoot":"","sources":["../src/currency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAwB,MAAM,wBAAwB,CAAC;AAc7E,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;AACzC,MAAM,GAAG,GAAG,aAAiD,CAAC;AAE9D;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,QAAgB;IAC3D,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,GAAG,EAAE,EAAE,CAAC;QACjE,MAAM,IAAI,UAAU,CAAC,oBAAoB,QAAQ,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,IAAI,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,kDAAkD,CAAC,CAAC;IACjF,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,SAAS,CAAC,GAAG,IAAI,qCAAqC,IAAI,EAAE,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,WAAW,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;QACpC,OAAO,WAAW,CAAC;IACrB,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO,cAAc,CAAC;IACxB,CAAC;IACD,MAAM,IAAI,UAAU,CAClB,qBAAqB,IAAI,yDAAyD,CACnF,CAAC;AACJ,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,OAAO,OAAO,GAAG,CAAC,IAAI,CAAC,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED,OAAO,EACL,aAAa,EACb,kBAAkB,EAClB,gBAAgB,GAEjB,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An exact rational factor num/den (den > 0). `n`/`d` hold the same values as numbers when both are
|
|
3
|
+
* safe.
|
|
4
|
+
*/
|
|
5
|
+
export interface Ratio {
|
|
6
|
+
readonly num: bigint;
|
|
7
|
+
readonly den: bigint;
|
|
8
|
+
/** num as a number, or NaN when it is not a safe integer */
|
|
9
|
+
readonly n: number;
|
|
10
|
+
/** den as a number, or NaN when it is not a safe integer */
|
|
11
|
+
readonly d: number;
|
|
12
|
+
}
|
|
13
|
+
/** Anything accepted where a multiplier, rate or percentage is expected. */
|
|
14
|
+
export type Factor = number | bigint | string | Ratio;
|
|
15
|
+
/** 10^exponent as a bigint, cached. */
|
|
16
|
+
export declare function pow10n(exponent: number): bigint;
|
|
17
|
+
/** 10^e as a number for 0 <= e <= 15 (all exact and safe). */
|
|
18
|
+
export declare const POW10: readonly [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000];
|
|
19
|
+
/**
|
|
20
|
+
* A bigint as a number when it is a safe integer, else unchanged: the representation Money keeps.
|
|
21
|
+
*/
|
|
22
|
+
export declare const normalizeMinor: (value: bigint) => number | bigint;
|
|
23
|
+
/**
|
|
24
|
+
* Parses a plain decimal string ("-12.345", "+7", "0.50") into digits/10^scale. Returns the integer
|
|
25
|
+
* of all digits (number when safe, else bigint) and the count of fraction digits. Hand-rolled (no
|
|
26
|
+
* regex, no BigInt for short inputs): this is the hot path of `money("12.34", ...)`.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parsePlainDecimal(input: string): {
|
|
29
|
+
digits: number | bigint;
|
|
30
|
+
scale: number;
|
|
31
|
+
} | null;
|
|
32
|
+
/**
|
|
33
|
+
* The largest exponent and number of fraction digits a decimal string may have. Far beyond any real
|
|
34
|
+
* amount or rate, and it keeps input such as "1e999999999" from building enormous powers of ten.
|
|
35
|
+
*/
|
|
36
|
+
export declare const MAX_DECIMAL_SCALE = 1000;
|
|
37
|
+
/** Parses a decimal string, allowing exponent notation ("1e-7", as produced by String(1e-7)). */
|
|
38
|
+
export declare function parseDecimal(input: string): {
|
|
39
|
+
digits: bigint;
|
|
40
|
+
scale: number;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Builds an exact ratio. `ratio('1.075')`, `ratio(3, 4)`, `ratio(10n)`, `ratio('1/3')`.
|
|
44
|
+
* Numbers are taken at their shortest decimal representation: `ratio(0.1)` is exactly 1/10.
|
|
45
|
+
* Pre-build ratios you use in hot loops; strings are also cached (up to 1024 entries).
|
|
46
|
+
*/
|
|
47
|
+
export declare function ratio(value: Factor, den?: Factor): Ratio;
|
|
48
|
+
/** num/den -> exact decimal string if the expansion terminates, else null. */
|
|
49
|
+
export declare function ratioToDecimal(value: Ratio): string | null;
|
|
50
|
+
/** Formats an integer at `scale` as a plain decimal string ("-0.05"). */
|
|
51
|
+
export declare function formatScaled(minor: number | bigint, scale: number): string;
|
|
52
|
+
//# sourceMappingURL=decimal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"decimal.d.ts","sourceRoot":"","sources":["../src/decimal.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,4DAA4D;IAC5D,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,4EAA4E;AAC5E,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAGtD,uCAAuC;AACvC,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE/C;AACD,8DAA8D;AAC9D,eAAO,MAAM,KAAK,mLAER,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,MACC,CAAC;AAE1D;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,MAAM,GACZ;IAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAoDnD;AAID;;;GAGG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC,iGAAiG;AACjG,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAkB7E;AA2CD;;;;GAIG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,KAAK,CA8CxD;AAED,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,IAAI,CAiB1D;AAKD,yEAAyE;AACzE,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAmC1E"}
|