@amboras-dev/money 0.0.0-stage → 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.
Files changed (78) hide show
  1. package/README.md +401 -2
  2. package/dist/ai.cjs +185 -0
  3. package/dist/ai.d.cts +97 -0
  4. package/dist/ai.d.ts +97 -0
  5. package/dist/ai.js +175 -0
  6. package/dist/allocate-CZRg4TOP.cjs +222 -0
  7. package/dist/allocate-X7_jAtOj.js +199 -0
  8. package/dist/amount-BV0O-aN8.cjs +241 -0
  9. package/dist/amount-BoYBMgK9.js +200 -0
  10. package/dist/arithmetic-BhNwisjb.js +132 -0
  11. package/dist/arithmetic-DjT4Kzgt.cjs +233 -0
  12. package/dist/billing.cjs +184 -0
  13. package/dist/billing.d.cts +81 -0
  14. package/dist/billing.d.ts +81 -0
  15. package/dist/billing.js +175 -0
  16. package/dist/commerce.cjs +536 -0
  17. package/dist/commerce.d.cts +293 -0
  18. package/dist/commerce.d.ts +293 -0
  19. package/dist/commerce.js +516 -0
  20. package/dist/format-BdPnijvn.js +99 -0
  21. package/dist/format-DLhno7eX.cjs +128 -0
  22. package/dist/fx.cjs +407 -0
  23. package/dist/fx.d.cts +157 -0
  24. package/dist/fx.d.ts +157 -0
  25. package/dist/fx.js +374 -0
  26. package/dist/index.cjs +352 -0
  27. package/dist/index.d.cts +300 -0
  28. package/dist/index.d.ts +300 -0
  29. package/dist/index.js +276 -0
  30. package/dist/input.cjs +163 -0
  31. package/dist/input.d.cts +203 -0
  32. package/dist/input.d.ts +203 -0
  33. package/dist/input.js +153 -0
  34. package/dist/iso-minor-CqkWDxHS.js +48 -0
  35. package/dist/iso-minor-wSwJN57T.cjs +65 -0
  36. package/dist/medusa-4K8N1pUc.d.cts +87 -0
  37. package/dist/medusa-DBXJXXvF.d.ts +87 -0
  38. package/dist/medusa-DqJY1qpj.js +116 -0
  39. package/dist/medusa-lRY9xlsf.cjs +175 -0
  40. package/dist/money-B-3aFjNJ.d.cts +248 -0
  41. package/dist/money-B-3aFjNJ.d.ts +248 -0
  42. package/dist/money-B3wH_Z4S.cjs +3990 -0
  43. package/dist/money-WhnGiI00.js +3583 -0
  44. package/dist/number-text-BWu67jUq.cjs +145 -0
  45. package/dist/number-text-DE-q4jO5.js +134 -0
  46. package/dist/own-D7544D3k.js +4 -0
  47. package/dist/own-oP9DXFWv.cjs +9 -0
  48. package/dist/percent-C0InC2t2.cjs +43 -0
  49. package/dist/percent-D1VB9xXG.js +20 -0
  50. package/dist/rate-CVeMii4a.cjs +217 -0
  51. package/dist/rate-DBPiYgT1.d.ts +63 -0
  52. package/dist/rate-DicStBue.js +152 -0
  53. package/dist/rate-tqK8ijG0.d.cts +63 -0
  54. package/dist/reporting-CG-ai2sM.d.cts +31 -0
  55. package/dist/reporting-tpGJbqYp.d.ts +31 -0
  56. package/dist/retail-1mu888J1.js +69 -0
  57. package/dist/retail-C_BPLvMj.d.cts +31 -0
  58. package/dist/retail-Cml8YSKg.cjs +86 -0
  59. package/dist/retail-DRUTTQoJ.d.ts +31 -0
  60. package/dist/rounding-DHBtNCHG.cjs +79 -0
  61. package/dist/rounding-g9rvye0k.js +50 -0
  62. package/dist/sql.cjs +290 -0
  63. package/dist/sql.d.cts +147 -0
  64. package/dist/sql.d.ts +147 -0
  65. package/dist/sql.js +271 -0
  66. package/dist/testing.cjs +61995 -0
  67. package/dist/testing.d.cts +125 -0
  68. package/dist/testing.d.ts +125 -0
  69. package/dist/testing.js +61986 -0
  70. package/dist/wire-Bhuut8cW.cjs +2097 -0
  71. package/dist/wire-CaUN9Vf_.d.ts +309 -0
  72. package/dist/wire-sW0yzqth.js +1888 -0
  73. package/dist/wire-xjYXv4go.d.cts +309 -0
  74. package/dist/wire.cjs +37 -0
  75. package/dist/wire.d.cts +2 -0
  76. package/dist/wire.d.ts +2 -0
  77. package/dist/wire.js +2 -0
  78. package/package.json +158 -3
package/dist/fx.js ADDED
@@ -0,0 +1,374 @@
1
+ import { $ as describeValue, B as decimalOf, E as resolveCurrency, J as compareRatio, M as resolveLocale, Q as MoneyError, X as mulDiv, Y as gcd, Z as ratioToDecimal, it as formatDecimal, j as numberFormat, n as fromMajor, nt as decimalFromNumber, pt as toDecimalText, s as storedDecimal, t as boundedMoney, ut as pow10, y as findCurrency } from "./money-WhnGiI00.js";
2
+ import { t as mulDivToUnit } from "./rounding-g9rvye0k.js";
3
+ import { t as hasOwnKey } from "./own-D7544D3k.js";
4
+ import { r as moneyFor } from "./medusa-DqJY1qpj.js";
5
+ import { a as invertRate, c as rateFromDecimal, d as rateToNumber, i as crossRate, l as rateFromRow, n as RATE_REF, o as rate, r as checkRate, s as rateEquals, t as RATE_BOUNDS, u as rateToDecimal } from "./rate-DicStBue.js";
6
+ import { n as retailUnits, r as roundRetail, t as priceRoundingParams } from "./retail-1mu888J1.js";
7
+ //#region src/fx/convert.ts
8
+ const infoOf = (code) => resolveCurrency(code, { allowHistoric: true });
9
+ /**
10
+ * The factor taking a stored `from` amount to a stored `to` amount for the major rate `r`
11
+ * (1 from = r to): `{ r.n x storageScale(to), r.d x storageScale(from) }`. Replaces Medusa
12
+ * `storedRateFactor`, `regionSwitchFactor`, `conversionFactor`.
13
+ */
14
+ function convertFactor(from, to, r) {
15
+ const { numerator, denominator } = checkRate(r);
16
+ return {
17
+ numerator: numerator * BigInt(infoOf(to).storageScale),
18
+ denominator: denominator * BigInt(infoOf(from).storageScale)
19
+ };
20
+ }
21
+ /**
22
+ * `m` in `to` at the major rate `r` (1 m.currency = r to): exact `m x convertFactor`, rounded
23
+ * once to `unit`, then `retail`. The same currency returns `m` unchanged.
24
+ */
25
+ function convert(m, to, r, options = {}) {
26
+ const { info: source } = storedDecimal(m);
27
+ const target = infoOf(to);
28
+ if (source.code === target.code) return m;
29
+ const { numerator, denominator } = convertFactor(source.code, target.code, r);
30
+ const units = mulDivToUnit(BigInt(m.amount), numerator, denominator, target, options.unit ?? "currency", options.rounding);
31
+ return boundedMoney(options.retail === void 0 ? units : retailUnits(units, 1n, target, options.retail), target);
32
+ }
33
+ /**
34
+ * The major rate two prices imply, `major(b) / major(a)`, exactly and in lowest terms (JPY
35
+ * 150000 against USD 1000 gives 150). Both must be positive, else `rate_invalid`.
36
+ */
37
+ function impliedRate(a, b) {
38
+ const { info: left } = storedDecimal(a);
39
+ const { info: right } = storedDecimal(b);
40
+ if (a.amount <= 0 || b.amount <= 0) throw new MoneyError("rate_invalid", `An implied rate needs two positive amounts, got ${a.amount} and ${b.amount}`);
41
+ const numerator = BigInt(b.amount) * BigInt(left.storageScale);
42
+ const denominator = BigInt(a.amount) * BigInt(right.storageScale);
43
+ const divisor = gcd(numerator, denominator);
44
+ return {
45
+ numerator: numerator / divisor,
46
+ denominator: denominator / divisor
47
+ };
48
+ }
49
+ //#endregion
50
+ //#region src/fx/format-rate.ts
51
+ /** `floor(log10(n / d))` of a positive ratio, exactly. */
52
+ function exponentOf(n, d) {
53
+ let e = n.toString().length - d.toString().length;
54
+ const at = (k) => k >= 0 ? compareRatio(n, d, pow10(k), 1n) : compareRatio(n, d, 1n, pow10(-k));
55
+ if (at(e) < 0) e -= 1;
56
+ return e;
57
+ }
58
+ const asIntlValue = (text) => text;
59
+ /**
60
+ * `'1 USD = 83.42 INR'`. `decimals: 'auto'` (default) shows 4 significant digits with at
61
+ * least 2 and at most 8 fraction digits; a number fixes them. Rounded half-up exactly, then
62
+ * grouped for `locale` (default `'en-US'`).
63
+ */
64
+ function formatRate(r, from, to, options = {}) {
65
+ const { numerator, denominator } = checkRate(r);
66
+ const fromCode = resolveCurrency(from, { allowHistoric: true }).code;
67
+ const toCode = resolveCurrency(to, { allowHistoric: true }).code;
68
+ const requested = options.decimals ?? "auto";
69
+ let digits;
70
+ if (requested === "auto") digits = Math.min(8, Math.max(2, 3 - exponentOf(numerator, denominator)));
71
+ else if (Number.isSafeInteger(requested) && requested >= 0 && requested <= 20) digits = requested;
72
+ else throw new MoneyError("amount_invalid", `decimals must be 'auto' or an integer from 0 to 20, got ${describeValue(requested)}`);
73
+ const value = ratioToDecimal(numerator, denominator, digits);
74
+ return `1 ${fromCode} = ${numberFormat(resolveLocale(options.locale), {
75
+ minimumFractionDigits: digits,
76
+ maximumFractionDigits: digits
77
+ }).format(asIntlValue(formatDecimal(value)))} ${toCode}`;
78
+ }
79
+ //#endregion
80
+ //#region src/fx/plausibility.ts
81
+ /** Medusa PRICE_SEED_RATE_MAX_DEVIATION's default. */
82
+ const DEFAULT_RATE_MAX_DEVIATION = 2;
83
+ /** chooseFactor's tolerance between the conventional factor and the observed median. */
84
+ const FACTOR_TOLERANCE = .02;
85
+ /** How far apart two positive rates are, as a factor >= 1 (2 = one is double the other). */
86
+ function deviationFactor(stored, reference) {
87
+ const ratio = stored / reference;
88
+ return ratio >= 1 ? ratio : 1 / ratio;
89
+ }
90
+ const isPositiveFinite$1 = (n) => typeof n === "number" && Number.isFinite(n) && n > 0;
91
+ /** A positive finite number as an exact Decimal; anything else throws `amount_invalid` naming `name`. */
92
+ function positiveDecimal(n, name) {
93
+ if (!isPositiveFinite$1(n)) throw new MoneyError("amount_invalid", `${name} must be a positive finite number, got ${describeValue(n)}`);
94
+ return decimalFromNumber(n);
95
+ }
96
+ function validRate(r) {
97
+ try {
98
+ return checkRate(r);
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
103
+ /**
104
+ * One locked rate against the reference, in Medusa `classifyRates` order: invalid (null or not
105
+ * a rate) is refused `invalid`; no reference is unverifiable `no_reference`; no positive
106
+ * reference for the currency is unverifiable `no_pair`; a deviation strictly above
107
+ * `maxDeviation` (default 2) is refused `implausible`; else plausible.
108
+ */
109
+ function classifyRate(r, code, reference, options = {}) {
110
+ const currency = code.toLowerCase();
111
+ const max = positiveDecimal(options.maxDeviation ?? 2, "maxDeviation");
112
+ const valid = validRate(r);
113
+ if (!valid) return {
114
+ status: "refused",
115
+ reason: "invalid",
116
+ currency,
117
+ stored: NaN
118
+ };
119
+ const stored = rateToNumber(valid, { decimals: "exact" });
120
+ if (!reference) return {
121
+ status: "unverifiable",
122
+ reason: "no_reference",
123
+ currency,
124
+ stored
125
+ };
126
+ const ref = hasOwnKey(reference.rates, currency) ? reference.rates[currency] : void 0;
127
+ if (!isPositiveFinite$1(ref)) return {
128
+ status: "unverifiable",
129
+ reason: "no_pair",
130
+ currency,
131
+ stored
132
+ };
133
+ const refValue = decimalFromNumber(ref);
134
+ const top = valid.numerator * pow10(refValue.scale);
135
+ const bottom = valid.denominator * refValue.units;
136
+ const maxD = pow10(max.scale);
137
+ if (compareRatio(top, bottom, max.units, maxD) > 0 || compareRatio(bottom, top, max.units, maxD) > 0) return {
138
+ status: "refused",
139
+ reason: "implausible",
140
+ currency,
141
+ stored,
142
+ reference: ref,
143
+ factor: deviationFactor(stored, ref),
144
+ source: reference.source
145
+ };
146
+ return {
147
+ status: "plausible",
148
+ currency,
149
+ stored
150
+ };
151
+ }
152
+ /** `|value - c| / c <= tolerance`, exactly (`c` positive). */
153
+ function closeTo(value, c, tolerance) {
154
+ const scaledC = c.numerator * pow10(value.scale);
155
+ const gap = value.units * c.denominator - scaledC;
156
+ return compareRatio((gap < 0n ? -gap : gap) * pow10(tolerance.scale), 1n, tolerance.units * scaledC, 1n) <= 0;
157
+ }
158
+ /**
159
+ * The storage factor confirmed by the store's own prices (Medusa `chooseFactor`): the
160
+ * candidates `[c, c / 100, c x 100]` against the upper median of the finite positive observed
161
+ * ratios; the first within `tolerance` (default 0.02) wins, none gives null. No observations
162
+ * trusts `conventional`.
163
+ */
164
+ function confirmStoredFactor(conventional, observedRatios, options = {}) {
165
+ const c = checkRate(conventional);
166
+ const tolerance = decimalFromNumber(nonNegative(options.tolerance ?? .02));
167
+ const ratios = observedRatios.filter(isPositiveFinite$1).sort((a, b) => a - b);
168
+ if (ratios.length === 0) return c;
169
+ const median = decimalFromNumber(ratios[Math.floor(ratios.length / 2)]);
170
+ return [
171
+ c,
172
+ {
173
+ numerator: c.numerator,
174
+ denominator: c.denominator * 100n
175
+ },
176
+ {
177
+ numerator: c.numerator * 100n,
178
+ denominator: c.denominator
179
+ }
180
+ ].find((candidate) => closeTo(median, candidate, tolerance)) ?? null;
181
+ }
182
+ function nonNegative(n) {
183
+ if (typeof n !== "number" || !Number.isFinite(n) || n < 0) throw new MoneyError("amount_invalid", `tolerance must be a non-negative finite number, got ${describeValue(n)}`);
184
+ return n;
185
+ }
186
+ /**
187
+ * The upper median of `rates` and which of them lie within `tolerance` (default 0.01) of it:
188
+ * accepted iff `|r / median - 1| <= tolerance`, exactly. No rates: `{ median: null, accepted: [] }`.
189
+ */
190
+ function rateConsensus(rates, options = {}) {
191
+ const valid = rates.map(checkRate);
192
+ const tolerance = decimalFromNumber(nonNegative(options.tolerance ?? .01));
193
+ if (valid.length === 0) return {
194
+ median: null,
195
+ accepted: []
196
+ };
197
+ const sorted = [...valid].sort((a, b) => compareRatio(a.numerator, a.denominator, b.numerator, b.denominator));
198
+ const median = sorted[Math.floor(sorted.length / 2)];
199
+ return {
200
+ median,
201
+ accepted: valid.map((r) => {
202
+ const gap = r.numerator * median.denominator - median.numerator * r.denominator;
203
+ const scale = pow10(tolerance.scale);
204
+ return compareRatio((gap < 0n ? -gap : gap) * scale, 1n, tolerance.units * median.numerator * r.denominator, 1n) <= 0;
205
+ })
206
+ };
207
+ }
208
+ //#endregion
209
+ //#region src/fx/reporting.ts
210
+ const FACTOR_DIGITS = 20;
211
+ /**
212
+ * The reporting factors of a store whose locked rates say `1 default = n/d <code>`:
213
+ * `factor(code) = storageScale(default) / storageScale(code) x d / n`, rounded half-up to 20
214
+ * fraction digits; the default currency is `'1'`. Rows for the default currency, unknown
215
+ * codes or invalid rates (see `rateFromRow`) are skipped, so those currencies have no factor.
216
+ * Port of Medusa `storeTotalFactors`, exact (it measured the factor at a 1e9 reference).
217
+ */
218
+ function storeFactors(defaultCurrency, rows) {
219
+ const base = resolveCurrency(defaultCurrency, { allowHistoric: true });
220
+ const factors = { [base.code.toLowerCase()]: "1" };
221
+ for (const row of rows) {
222
+ const info = findCurrency(row?.currency_code, { allowHistoric: true });
223
+ const r = rateFromRow(row);
224
+ if (!info || !r || info.code === base.code) continue;
225
+ const units = mulDiv(BigInt(base.storageScale) * r.denominator, pow10(FACTOR_DIGITS), BigInt(info.storageScale) * r.numerator, "half-up");
226
+ factors[info.code.toLowerCase()] = toDecimalText({
227
+ units,
228
+ scale: FACTOR_DIGITS
229
+ });
230
+ }
231
+ return {
232
+ base: base.code,
233
+ factors: Object.freeze(factors)
234
+ };
235
+ }
236
+ /**
237
+ * The sum of `items` in `table.base`: each converted with its currency's factor and rounded
238
+ * half-up to a storage unit (per item, as customer-stats rounds per order), then summed.
239
+ * Items whose currency has no factor are excluded and reported in `missing`.
240
+ */
241
+ function toReporting(items, table) {
242
+ const base = resolveCurrency(table.base, { allowHistoric: true });
243
+ const missing = /* @__PURE__ */ new Set();
244
+ let total = 0n;
245
+ for (const item of items) {
246
+ const { info } = storedDecimal(item);
247
+ const key = info.code.toLowerCase();
248
+ const text = hasOwnKey(table.factors, key) ? table.factors[key] : void 0;
249
+ if (text === void 0) {
250
+ missing.add(info.code);
251
+ continue;
252
+ }
253
+ const factor = decimalOf(text, false, `factors.${key}`);
254
+ total += mulDiv(BigInt(item.amount), factor.units, pow10(factor.scale), "half-up");
255
+ }
256
+ return {
257
+ total: boundedMoney(total, base),
258
+ complete: missing.size === 0,
259
+ missing: [...missing].sort()
260
+ };
261
+ }
262
+ //#endregion
263
+ //#region src/fx/settings.ts
264
+ const RATE_MODES = ["manual", "dynamic"];
265
+ const PRICE_ROUNDINGS = ["none", "nearest"];
266
+ /** `store_currency_rate.rate_mode` as readers coerce it: `'manual'` exactly, else `'dynamic'`. */
267
+ function parseRateMode(value) {
268
+ return value === "manual" ? "manual" : "dynamic";
269
+ }
270
+ /** `store_currency_rate.rounding` as readers coerce it: `'nearest'` exactly, else `'none'`. */
271
+ function parsePriceRounding(value) {
272
+ return value === "nearest" ? "nearest" : "none";
273
+ }
274
+ /**
275
+ * The amount a per-currency setting holds for `currency`: the listed entry, else the explicit
276
+ * fallback: `'refuse'` gives null; `'major'` is that many major units of `currency` itself
277
+ * (the store-credit cap `{ kind: 'major', amount: '15000' }`); `'convert'` converts the
278
+ * `from` entry at `rate` (null when there is no `from` entry). Never a silent default.
279
+ */
280
+ function resolveMoneyByCurrency(setting, currency, options) {
281
+ const info = resolveCurrency(currency, { allowHistoric: true });
282
+ const listed = moneyFor(setting, info.code);
283
+ if (listed) return {
284
+ money: listed,
285
+ source: "listed"
286
+ };
287
+ const fallback = options.fallback;
288
+ if (fallback.kind === "major") return {
289
+ money: fromMajor(fallback.amount, info.code),
290
+ source: "fallback"
291
+ };
292
+ if (fallback.kind === "convert") {
293
+ const base = moneyFor(setting, fallback.from);
294
+ return base ? {
295
+ money: convert(base, info.code, fallback.rate, { retail: fallback.retail }),
296
+ source: "fallback"
297
+ } : null;
298
+ }
299
+ return null;
300
+ }
301
+ //#endregion
302
+ //#region src/fx/tables.ts
303
+ /** 1 USD = rate units of the currency, exact (see data/pegs.ts for the sources). Upper-case keys. */
304
+ const USD_PEGS = Object.freeze(Object.fromEntries(Object.entries({
305
+ AED: [36725n, 10000n],
306
+ SAR: [375n, 100n],
307
+ QAR: [364n, 100n],
308
+ BHD: [376n, 1000n],
309
+ OMR: [3845n, 10000n]
310
+ }).map(([code, [numerator, denominator]]) => [code, Object.freeze({
311
+ numerator,
312
+ denominator
313
+ })])));
314
+ const isPositiveFinite = (n) => typeof n === "number" && Number.isFinite(n) && n > 0;
315
+ /** A feed's rate table with lower-case keys and only finite positive numbers kept (Medusa `lowerKeys`). Never throws. */
316
+ function sanitizeRateTable(raw) {
317
+ const out = {};
318
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return out;
319
+ for (const [key, value] of Object.entries(raw)) if (isPositiveFinite(value)) out[key.toLowerCase()] = value;
320
+ return out;
321
+ }
322
+ /** `{ ...fallback, ...primary }`: the primary feed (ECB) wins every currency it publishes. */
323
+ function mergeRateTables(primary, fallback) {
324
+ return {
325
+ ...fallback,
326
+ ...primary
327
+ };
328
+ }
329
+ function own(table, code) {
330
+ for (const key of [code.toUpperCase(), code.toLowerCase()]) if (hasOwnKey(table, key)) return table[key];
331
+ }
332
+ /** Units of `code` per 1 USD: the feed's finite positive value, else its peg, else undefined. */
333
+ function perUsd(code, ratesPerUsd, pegs) {
334
+ const live = own(ratesPerUsd, code);
335
+ if (isPositiveFinite(live)) {
336
+ const d = decimalFromNumber(live);
337
+ return {
338
+ numerator: d.units,
339
+ denominator: pow10(d.scale)
340
+ };
341
+ }
342
+ const peg = own(pegs, code);
343
+ return peg === void 0 ? void 0 : checkRate(peg);
344
+ }
345
+ /**
346
+ * The rate 1 `from` = ? `to` when the live pair is unavailable, through the USD pegs
347
+ * (orch `resolveRateMajor`): a pegged `to` gives the peg from USD, else `(from -> USD) x peg`
348
+ * with `from -> USD` read from `ratesPerUsd` (units per 1 USD, any key case) or from `from`'s
349
+ * own peg; a pegged `from` into USD gives the inverse peg (new, symmetric). The same code
350
+ * gives 1/1; anything else null.
351
+ */
352
+ function pegFallback(from, to, ratesPerUsd, pegs = USD_PEGS) {
353
+ const f = from.toUpperCase();
354
+ const t = to.toUpperCase();
355
+ if (f === t) return {
356
+ numerator: 1n,
357
+ denominator: 1n
358
+ };
359
+ const toPeg = own(pegs, t);
360
+ if (toPeg !== void 0) {
361
+ const peg = checkRate(toPeg);
362
+ if (f === "USD") return peg;
363
+ const source = perUsd(f, ratesPerUsd, pegs);
364
+ if (!source) return null;
365
+ return {
366
+ numerator: peg.numerator * source.denominator,
367
+ denominator: peg.denominator * source.numerator
368
+ };
369
+ }
370
+ const fromPeg = own(pegs, f);
371
+ return fromPeg !== void 0 && t === "USD" ? invertRate(fromPeg) : null;
372
+ }
373
+ //#endregion
374
+ export { DEFAULT_RATE_MAX_DEVIATION, FACTOR_TOLERANCE, PRICE_ROUNDINGS, RATE_BOUNDS, RATE_MODES, RATE_REF, USD_PEGS, classifyRate, confirmStoredFactor, convert, convertFactor, crossRate, deviationFactor, formatRate, impliedRate, invertRate, mergeRateTables, parsePriceRounding, parseRateMode, pegFallback, priceRoundingParams, rate, rateConsensus, rateEquals, rateFromDecimal, rateFromRow, rateToDecimal, rateToNumber, resolveMoneyByCurrency, roundRetail, sanitizeRateTable, storeFactors, toReporting };