@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
@@ -0,0 +1,293 @@
1
+ import { R as DecimalText, i as Money, z as RoundingMode } from "./money-B-3aFjNJ.cjs";
2
+ import { t as RetailRounding } from "./retail-C_BPLvMj.cjs";
3
+ //#region src/commerce/convention.d.ts
4
+ /**
5
+ * Currencies with storage digits: step 1, `'x100'`. Zero-decimal currencies: step 100 when
6
+ * there is a positive sample and every positive sample is a multiple of 100 (the platform
7
+ * convention), else step 1 `'whole-unit'` (never truncate a whole-unit store to hundreds).
8
+ */
9
+ export declare function storageConventionOf(currency: string, samples: readonly Money[]): {
10
+ step: 1 | 100;
11
+ convention: 'x100' | 'whole-unit';
12
+ };
13
+ //#endregion
14
+ //#region src/commerce/cost.d.ts
15
+ /**
16
+ * Extra costs (freight, duties) spread over receipt lines by quantity, exactly: `extras`
17
+ * (rounded half-up to `scale`, default 4) is allocated with the last line absorbing the
18
+ * remainder; each line's landed unit cost is `max(0, round(unitCost + share / quantity))` at
19
+ * `scale`. Non-positive extras or quantities spread nothing.
20
+ */
21
+ export declare function landedUnitCosts(lines: readonly {
22
+ quantity: number;
23
+ unitCost: DecimalText;
24
+ }[], extras: DecimalText, options?: {
25
+ scale?: number;
26
+ }): {
27
+ share: DecimalText;
28
+ landedUnitCost: DecimalText;
29
+ }[];
30
+ /**
31
+ * The weighted-average unit cost after a receipt: the receipt's cost (half-up to `scale`,
32
+ * default 4) when there is no average, nothing on hand or nothing received; else
33
+ * `(onHand x average + quantity x unitCost) / (onHand + quantity)` half-up to `scale`.
34
+ */
35
+ export declare function weightedAverageCost(current: {
36
+ onHand: number;
37
+ average: DecimalText | null;
38
+ }, receipt: {
39
+ quantity: number;
40
+ unitCost: DecimalText;
41
+ }, options?: {
42
+ scale?: number;
43
+ }): DecimalText;
44
+ //#endregion
45
+ //#region src/commerce/discount.d.ts
46
+ interface DiscountSpec {
47
+ readonly type: 'percentage' | 'fixed';
48
+ /** A percent (0..100, clamped) for `'percentage'`; Money (currency-carrying) for `'fixed'`. */
49
+ readonly value: number | DecimalText | Money;
50
+ }
51
+ interface DiscountAmountOptions {
52
+ /** `'total'` (default): one rounding on the whole base. `'unit'`: round per unit, then x `quantity` (Shopify line discounts). */
53
+ per?: 'total' | 'unit';
54
+ /** Units in `base` for `per: 'unit'` (a positive integer). */
55
+ quantity?: number;
56
+ /** Default `'currency'` (D12): whole yen for JPY. */
57
+ unit?: 'storage' | 'currency';
58
+ /** Default `'half-up'`; `'floor-after-tenth'` is the promotion parity engine's truncation. */
59
+ rounding?: RoundingMode;
60
+ }
61
+ /**
62
+ * The discount `spec` takes off `base` (a line or order total), clamped to `[0, base]`; a
63
+ * non-positive base gives 0. A percentage of the total rounds once (`per: 'total'`) or per
64
+ * unit then times the quantity (`per: 'unit'`: 10% of 2 x 18.99 truncated is 2 x 1.89); a
65
+ * fixed amount is Money in base's currency, per unit times the quantity with `per: 'unit'`.
66
+ */
67
+ export declare function discountAmount(spec: DiscountSpec, base: Money, options?: DiscountAmountOptions): Money;
68
+ type BuyGetRewardSpec = {
69
+ readonly kind: 'percent';
70
+ readonly value: number | DecimalText;
71
+ } | {
72
+ readonly kind: 'fixed-each';
73
+ readonly value: Money;
74
+ };
75
+ /**
76
+ * The reward of a buy X get Y offer on one line: `min(quantity, maxQuantity)` discounted
77
+ * units, each `percent` of the unit price (rounded once on the total to the currency unit) or
78
+ * a fixed amount off each, never more than the unit price (promotion `fixBuyGetFixedRewards`).
79
+ * The units come from the input, never recovered from an amount.
80
+ */
81
+ export declare function buyGetReward(input: {
82
+ unitPrice: Money;
83
+ quantity: number;
84
+ reward: BuyGetRewardSpec;
85
+ maxQuantity?: number;
86
+ }): {
87
+ amount: Money;
88
+ discountedUnits: number;
89
+ };
90
+ /** `'10%'`, `'12.5%'` (up to 2 decimals, half-up) or the fixed amount via `formatMoney` (its currency must be `currency`). */
91
+ export declare function formatDiscount(spec: DiscountSpec, currency: string, options?: {
92
+ locale?: string;
93
+ }): string;
94
+ //#endregion
95
+ //#region src/commerce/order-value.d.ts
96
+ interface OrderValueInput {
97
+ currency: string;
98
+ /** The query.graph `order.total`; used only with `trustGraph` and only when positive. */
99
+ graphTotal?: unknown;
100
+ /** `order_summary.totals.current_order_total`: any readable value, 0 and negatives included (`''` is unreadable). */
101
+ summaryTotal?: unknown;
102
+ /** Last resort: lines netted of their adjustments, each floored at 0; used only when positive. */
103
+ items?: readonly {
104
+ unit_price: unknown;
105
+ quantity: unknown;
106
+ adjustments?: readonly {
107
+ amount: unknown;
108
+ }[];
109
+ }[];
110
+ /** Default false (GA4: the graph total can read a spurious 0); Meta passes true. */
111
+ trustGraph?: boolean;
112
+ /** `'net-of-tax-shipping'` subtracts `taxTotal` and `shippingTotal` from a graph or summary total. Default `'total'`. */
113
+ basis?: 'total' | 'net-of-tax-shipping';
114
+ taxTotal?: unknown;
115
+ shippingTotal?: unknown;
116
+ }
117
+ /**
118
+ * The value an order reports to ad platforms, and where it came from: the graph total when
119
+ * trusted and positive, else the summary total (a genuine 0 or a negative is kept), else the
120
+ * items netted of adjustments when positive, else null. The result is rounded half-up to a
121
+ * storage unit. Skipping a send when the value is not positive (GA4) stays an app policy.
122
+ */
123
+ export declare function resolveOrderValue(input: OrderValueInput): {
124
+ value: Money;
125
+ source: 'graph' | 'summary' | 'items';
126
+ } | null;
127
+ //#endregion
128
+ //#region src/commerce/payable.d.ts
129
+ /**
130
+ * `false` when the cart can complete with no payment (`total <= 0` and no negative credit-line
131
+ * balance: `credit_line_total >= 0 && total <= 0`), `true` when it must be paid, `undefined`
132
+ * when the total is not a finite number (still loading: fail closed, never "free"). As in the
133
+ * starter, only a number counts as a total, and an absent credit-line total counts as none.
134
+ */
135
+ export declare function requiresPayment(input: {
136
+ total: unknown;
137
+ creditLineTotal?: unknown;
138
+ }, currency: string): boolean | undefined;
139
+ //#endregion
140
+ //#region src/commerce/pricing.d.ts
141
+ interface MarkupOptions {
142
+ /** Percent added (negative = a discount). */
143
+ percent?: number | DecimalText;
144
+ /** A flat amount added, same currency. */
145
+ flat?: Money;
146
+ /** Default `'percent-then-flat'` (handling fee: $5 + 50% + $1 = $8.50); `'flat-then-percent'` (Amazon MCF). */
147
+ order?: 'percent-then-flat' | 'flat-then-percent';
148
+ floor?: Money;
149
+ ceiling?: Money;
150
+ /** The one rounding, to a storage unit. Default `'half-up'`. */
151
+ rounding?: RoundingMode;
152
+ }
153
+ /**
154
+ * `m` with a markup: exact percent and flat in `order`, one rounding to a storage unit, then
155
+ * clamped to `[floor, ceiling]`, then to `>= 0`. A non-positive `m` (a failed quote) is
156
+ * returned unchanged.
157
+ */
158
+ export declare function applyMarkup(m: Money, options: MarkupOptions): Money;
159
+ type RetailMarkup = {
160
+ readonly percent: number | DecimalText;
161
+ } | {
162
+ readonly bps: number;
163
+ readonly capTiers?: readonly {
164
+ readonly below?: Money;
165
+ readonly cap: Money;
166
+ }[];
167
+ };
168
+ interface RetailPriceInput {
169
+ cost: Money;
170
+ markup: RetailMarkup;
171
+ /** Added after the markup (domain DNS cost). */
172
+ extras?: Money;
173
+ /** A card fee charged on the subtotal: `ceil(subtotal x bps / 1e4) + fixed`. */
174
+ fee?: {
175
+ bps: number;
176
+ fixed: Money;
177
+ };
178
+ /** Default `'none'` (rounded half-up to the currency unit). */
179
+ rounding?: RetailRounding;
180
+ floor?: Money;
181
+ }
182
+ /**
183
+ * The one retail price:
184
+ * - AliExpress (`markup: { percent }`): `cost x (1 + percent / 100)`, exact, then `rounding`
185
+ * once (`'none'`: half-up to the currency unit; `'.99'`, `'.95'`, `'whole'`: up to the ending).
186
+ * - Domains (`markup: { bps, capTiers }`, integer cents): `markup = min(round(cost x bps / 1e4),
187
+ * cap)` with the cap of the first tier whose `below` the cost is under (or that has none);
188
+ * `subtotal = cost + markup + extras`; `fee = ceil(subtotal x feeBps / 1e4) + fixed`; then
189
+ * `max(roundRetail(subtotal + fee, rounding), floor)` (`'up-to-99'` for domains).
190
+ */
191
+ export declare function retailPrice(input: RetailPriceInput): Money;
192
+ /** `(price - cost) / price` in percent, half-up to `decimals` (default 1); a non-positive price gives 0. */
193
+ export declare function marginPercent(price: Money, cost: Money, options?: {
194
+ decimals?: number;
195
+ }): number;
196
+ /**
197
+ * The change from `from` to `to` in percent, half-up to `decimals` (default 1): `'change'`
198
+ * (default) is `(to - from) / from`, `'off'` the discount `(from - to) / from` (promotion
199
+ * percent off, subscription `discount_percentage`). A non-positive `from` gives null.
200
+ */
201
+ export declare function percentChange(from: Money, to: Money, options?: {
202
+ decimals?: number;
203
+ as?: 'change' | 'off';
204
+ }): number | null;
205
+ /** What is kept of a charge after a card fee: `m - round(m x bps / 1e4) - fixed`. */
206
+ export declare function netOfFee(m: Money, fee: {
207
+ bps: number;
208
+ fixed: Money;
209
+ }): Money;
210
+ //#endregion
211
+ //#region src/commerce/tax.d.ts
212
+ /**
213
+ * The tax rate in percent that `tax` on `net` implies, snapped half-up to a multiple of `snap`
214
+ * (default 0.5, every real EU VAT rate; 0 = no snap, 10 decimals). `net <= 0` gives 0.
215
+ * sevDesk `inferTaxRatePercent`, exact.
216
+ */
217
+ export declare function inferTaxRatePercent(net: Money, tax: Money, options?: {
218
+ snap?: number;
219
+ }): number;
220
+ /**
221
+ * The rate in percent behind `tax` on `base` (Shopify archive `taxRateFor`): exclusive
222
+ * `100 tax / base`, inclusive `100 tax / (base - tax)`, half-up to `decimals` (default 10),
223
+ * trailing zeros dropped. Null when tax or base is not positive, or the denominator is not.
224
+ */
225
+ export declare function solveTaxRate(input: {
226
+ tax: Money;
227
+ base: Money;
228
+ inclusive: boolean;
229
+ decimals?: number;
230
+ }): string | null;
231
+ /**
232
+ * Whether prices include tax (Shopify archive `inferTaxesIncluded`): `explicit` wins; a null
233
+ * total or a non-positive tax is exclusive; else inclusive iff
234
+ * `|sub + ship - total| < |sub + ship + tax - total|`.
235
+ */
236
+ export declare function inferTaxesIncluded(input: {
237
+ subtotal: Money;
238
+ shipping: Money;
239
+ tax: Money;
240
+ total: Money | null;
241
+ explicit?: boolean;
242
+ }): boolean;
243
+ /** `gross` split into `net = round(gross x 100 / (100 + rate))` and `tax = gross - net` (net + tax == gross). */
244
+ export declare function splitGross(gross: Money, ratePercent: number | DecimalText, options?: {
245
+ rounding?: RoundingMode;
246
+ }): {
247
+ net: Money;
248
+ tax: Money;
249
+ };
250
+ /** A unit price without its tax when prices include tax (`round(unit x 100 / (100 + rate))`), else `unit`. */
251
+ export declare function unitNetOfTax(unit: Money, options: {
252
+ taxInclusive: boolean;
253
+ ratePercent: number | DecimalText;
254
+ }): Money;
255
+ /**
256
+ * `refund` spread over positions (each a net and its tax): capped at the gross total, split by
257
+ * gross with the largest remainder, then each gross share split into net and tax in the
258
+ * position's proportion (largest remainder). Per row `net + tax == gross`, and the grosses
259
+ * sum to the (capped) refund. Negative amounts throw `amount_invalid`.
260
+ */
261
+ export declare function allocateWithTax(refund: Money, positions: readonly {
262
+ net: Money;
263
+ tax: Money;
264
+ }[]): {
265
+ net: Money;
266
+ tax: Money;
267
+ gross: Money;
268
+ }[];
269
+ /** The Medusa totals fields `displayTotals` reads (BigNumber shapes or numbers; `raw_<key>` siblings win). */
270
+ interface MedusaTotalsLike {
271
+ readonly [key: string]: unknown;
272
+ }
273
+ interface DisplayTotals {
274
+ readonly subtotal: Money | null;
275
+ readonly discount: Money | null;
276
+ readonly shipping: Money | null;
277
+ readonly tax: Money | null;
278
+ readonly total: Money | null;
279
+ /** True when the tax is already inside the other amounts ("including tax"), false when added. */
280
+ readonly taxIncluded: boolean;
281
+ }
282
+ /**
283
+ * The totals a customer-facing summary shows, one selection for every email: tax-inclusive
284
+ * stores show the gross item and shipping totals with the tax "included", exclusive stores the
285
+ * net subtotals with the tax "added". Each field reads `raw_<key>` first, like
286
+ * `readStoredField`; Medusa's fractional totals round half-up to a storage unit; a missing or
287
+ * unreadable field is null, never 0.
288
+ */
289
+ export declare function displayTotals(totals: MedusaTotalsLike, currency: string, options: {
290
+ taxInclusive: boolean;
291
+ }): DisplayTotals;
292
+ //#endregion
293
+ export type { BuyGetRewardSpec, DiscountAmountOptions, DiscountSpec, DisplayTotals, MarkupOptions, MedusaTotalsLike, OrderValueInput, RetailMarkup, RetailPriceInput };
@@ -0,0 +1,293 @@
1
+ import { R as DecimalText, i as Money, z as RoundingMode } from "./money-B-3aFjNJ.js";
2
+ import { t as RetailRounding } from "./retail-DRUTTQoJ.js";
3
+ //#region src/commerce/convention.d.ts
4
+ /**
5
+ * Currencies with storage digits: step 1, `'x100'`. Zero-decimal currencies: step 100 when
6
+ * there is a positive sample and every positive sample is a multiple of 100 (the platform
7
+ * convention), else step 1 `'whole-unit'` (never truncate a whole-unit store to hundreds).
8
+ */
9
+ export declare function storageConventionOf(currency: string, samples: readonly Money[]): {
10
+ step: 1 | 100;
11
+ convention: 'x100' | 'whole-unit';
12
+ };
13
+ //#endregion
14
+ //#region src/commerce/cost.d.ts
15
+ /**
16
+ * Extra costs (freight, duties) spread over receipt lines by quantity, exactly: `extras`
17
+ * (rounded half-up to `scale`, default 4) is allocated with the last line absorbing the
18
+ * remainder; each line's landed unit cost is `max(0, round(unitCost + share / quantity))` at
19
+ * `scale`. Non-positive extras or quantities spread nothing.
20
+ */
21
+ export declare function landedUnitCosts(lines: readonly {
22
+ quantity: number;
23
+ unitCost: DecimalText;
24
+ }[], extras: DecimalText, options?: {
25
+ scale?: number;
26
+ }): {
27
+ share: DecimalText;
28
+ landedUnitCost: DecimalText;
29
+ }[];
30
+ /**
31
+ * The weighted-average unit cost after a receipt: the receipt's cost (half-up to `scale`,
32
+ * default 4) when there is no average, nothing on hand or nothing received; else
33
+ * `(onHand x average + quantity x unitCost) / (onHand + quantity)` half-up to `scale`.
34
+ */
35
+ export declare function weightedAverageCost(current: {
36
+ onHand: number;
37
+ average: DecimalText | null;
38
+ }, receipt: {
39
+ quantity: number;
40
+ unitCost: DecimalText;
41
+ }, options?: {
42
+ scale?: number;
43
+ }): DecimalText;
44
+ //#endregion
45
+ //#region src/commerce/discount.d.ts
46
+ interface DiscountSpec {
47
+ readonly type: 'percentage' | 'fixed';
48
+ /** A percent (0..100, clamped) for `'percentage'`; Money (currency-carrying) for `'fixed'`. */
49
+ readonly value: number | DecimalText | Money;
50
+ }
51
+ interface DiscountAmountOptions {
52
+ /** `'total'` (default): one rounding on the whole base. `'unit'`: round per unit, then x `quantity` (Shopify line discounts). */
53
+ per?: 'total' | 'unit';
54
+ /** Units in `base` for `per: 'unit'` (a positive integer). */
55
+ quantity?: number;
56
+ /** Default `'currency'` (D12): whole yen for JPY. */
57
+ unit?: 'storage' | 'currency';
58
+ /** Default `'half-up'`; `'floor-after-tenth'` is the promotion parity engine's truncation. */
59
+ rounding?: RoundingMode;
60
+ }
61
+ /**
62
+ * The discount `spec` takes off `base` (a line or order total), clamped to `[0, base]`; a
63
+ * non-positive base gives 0. A percentage of the total rounds once (`per: 'total'`) or per
64
+ * unit then times the quantity (`per: 'unit'`: 10% of 2 x 18.99 truncated is 2 x 1.89); a
65
+ * fixed amount is Money in base's currency, per unit times the quantity with `per: 'unit'`.
66
+ */
67
+ export declare function discountAmount(spec: DiscountSpec, base: Money, options?: DiscountAmountOptions): Money;
68
+ type BuyGetRewardSpec = {
69
+ readonly kind: 'percent';
70
+ readonly value: number | DecimalText;
71
+ } | {
72
+ readonly kind: 'fixed-each';
73
+ readonly value: Money;
74
+ };
75
+ /**
76
+ * The reward of a buy X get Y offer on one line: `min(quantity, maxQuantity)` discounted
77
+ * units, each `percent` of the unit price (rounded once on the total to the currency unit) or
78
+ * a fixed amount off each, never more than the unit price (promotion `fixBuyGetFixedRewards`).
79
+ * The units come from the input, never recovered from an amount.
80
+ */
81
+ export declare function buyGetReward(input: {
82
+ unitPrice: Money;
83
+ quantity: number;
84
+ reward: BuyGetRewardSpec;
85
+ maxQuantity?: number;
86
+ }): {
87
+ amount: Money;
88
+ discountedUnits: number;
89
+ };
90
+ /** `'10%'`, `'12.5%'` (up to 2 decimals, half-up) or the fixed amount via `formatMoney` (its currency must be `currency`). */
91
+ export declare function formatDiscount(spec: DiscountSpec, currency: string, options?: {
92
+ locale?: string;
93
+ }): string;
94
+ //#endregion
95
+ //#region src/commerce/order-value.d.ts
96
+ interface OrderValueInput {
97
+ currency: string;
98
+ /** The query.graph `order.total`; used only with `trustGraph` and only when positive. */
99
+ graphTotal?: unknown;
100
+ /** `order_summary.totals.current_order_total`: any readable value, 0 and negatives included (`''` is unreadable). */
101
+ summaryTotal?: unknown;
102
+ /** Last resort: lines netted of their adjustments, each floored at 0; used only when positive. */
103
+ items?: readonly {
104
+ unit_price: unknown;
105
+ quantity: unknown;
106
+ adjustments?: readonly {
107
+ amount: unknown;
108
+ }[];
109
+ }[];
110
+ /** Default false (GA4: the graph total can read a spurious 0); Meta passes true. */
111
+ trustGraph?: boolean;
112
+ /** `'net-of-tax-shipping'` subtracts `taxTotal` and `shippingTotal` from a graph or summary total. Default `'total'`. */
113
+ basis?: 'total' | 'net-of-tax-shipping';
114
+ taxTotal?: unknown;
115
+ shippingTotal?: unknown;
116
+ }
117
+ /**
118
+ * The value an order reports to ad platforms, and where it came from: the graph total when
119
+ * trusted and positive, else the summary total (a genuine 0 or a negative is kept), else the
120
+ * items netted of adjustments when positive, else null. The result is rounded half-up to a
121
+ * storage unit. Skipping a send when the value is not positive (GA4) stays an app policy.
122
+ */
123
+ export declare function resolveOrderValue(input: OrderValueInput): {
124
+ value: Money;
125
+ source: 'graph' | 'summary' | 'items';
126
+ } | null;
127
+ //#endregion
128
+ //#region src/commerce/payable.d.ts
129
+ /**
130
+ * `false` when the cart can complete with no payment (`total <= 0` and no negative credit-line
131
+ * balance: `credit_line_total >= 0 && total <= 0`), `true` when it must be paid, `undefined`
132
+ * when the total is not a finite number (still loading: fail closed, never "free"). As in the
133
+ * starter, only a number counts as a total, and an absent credit-line total counts as none.
134
+ */
135
+ export declare function requiresPayment(input: {
136
+ total: unknown;
137
+ creditLineTotal?: unknown;
138
+ }, currency: string): boolean | undefined;
139
+ //#endregion
140
+ //#region src/commerce/pricing.d.ts
141
+ interface MarkupOptions {
142
+ /** Percent added (negative = a discount). */
143
+ percent?: number | DecimalText;
144
+ /** A flat amount added, same currency. */
145
+ flat?: Money;
146
+ /** Default `'percent-then-flat'` (handling fee: $5 + 50% + $1 = $8.50); `'flat-then-percent'` (Amazon MCF). */
147
+ order?: 'percent-then-flat' | 'flat-then-percent';
148
+ floor?: Money;
149
+ ceiling?: Money;
150
+ /** The one rounding, to a storage unit. Default `'half-up'`. */
151
+ rounding?: RoundingMode;
152
+ }
153
+ /**
154
+ * `m` with a markup: exact percent and flat in `order`, one rounding to a storage unit, then
155
+ * clamped to `[floor, ceiling]`, then to `>= 0`. A non-positive `m` (a failed quote) is
156
+ * returned unchanged.
157
+ */
158
+ export declare function applyMarkup(m: Money, options: MarkupOptions): Money;
159
+ type RetailMarkup = {
160
+ readonly percent: number | DecimalText;
161
+ } | {
162
+ readonly bps: number;
163
+ readonly capTiers?: readonly {
164
+ readonly below?: Money;
165
+ readonly cap: Money;
166
+ }[];
167
+ };
168
+ interface RetailPriceInput {
169
+ cost: Money;
170
+ markup: RetailMarkup;
171
+ /** Added after the markup (domain DNS cost). */
172
+ extras?: Money;
173
+ /** A card fee charged on the subtotal: `ceil(subtotal x bps / 1e4) + fixed`. */
174
+ fee?: {
175
+ bps: number;
176
+ fixed: Money;
177
+ };
178
+ /** Default `'none'` (rounded half-up to the currency unit). */
179
+ rounding?: RetailRounding;
180
+ floor?: Money;
181
+ }
182
+ /**
183
+ * The one retail price:
184
+ * - AliExpress (`markup: { percent }`): `cost x (1 + percent / 100)`, exact, then `rounding`
185
+ * once (`'none'`: half-up to the currency unit; `'.99'`, `'.95'`, `'whole'`: up to the ending).
186
+ * - Domains (`markup: { bps, capTiers }`, integer cents): `markup = min(round(cost x bps / 1e4),
187
+ * cap)` with the cap of the first tier whose `below` the cost is under (or that has none);
188
+ * `subtotal = cost + markup + extras`; `fee = ceil(subtotal x feeBps / 1e4) + fixed`; then
189
+ * `max(roundRetail(subtotal + fee, rounding), floor)` (`'up-to-99'` for domains).
190
+ */
191
+ export declare function retailPrice(input: RetailPriceInput): Money;
192
+ /** `(price - cost) / price` in percent, half-up to `decimals` (default 1); a non-positive price gives 0. */
193
+ export declare function marginPercent(price: Money, cost: Money, options?: {
194
+ decimals?: number;
195
+ }): number;
196
+ /**
197
+ * The change from `from` to `to` in percent, half-up to `decimals` (default 1): `'change'`
198
+ * (default) is `(to - from) / from`, `'off'` the discount `(from - to) / from` (promotion
199
+ * percent off, subscription `discount_percentage`). A non-positive `from` gives null.
200
+ */
201
+ export declare function percentChange(from: Money, to: Money, options?: {
202
+ decimals?: number;
203
+ as?: 'change' | 'off';
204
+ }): number | null;
205
+ /** What is kept of a charge after a card fee: `m - round(m x bps / 1e4) - fixed`. */
206
+ export declare function netOfFee(m: Money, fee: {
207
+ bps: number;
208
+ fixed: Money;
209
+ }): Money;
210
+ //#endregion
211
+ //#region src/commerce/tax.d.ts
212
+ /**
213
+ * The tax rate in percent that `tax` on `net` implies, snapped half-up to a multiple of `snap`
214
+ * (default 0.5, every real EU VAT rate; 0 = no snap, 10 decimals). `net <= 0` gives 0.
215
+ * sevDesk `inferTaxRatePercent`, exact.
216
+ */
217
+ export declare function inferTaxRatePercent(net: Money, tax: Money, options?: {
218
+ snap?: number;
219
+ }): number;
220
+ /**
221
+ * The rate in percent behind `tax` on `base` (Shopify archive `taxRateFor`): exclusive
222
+ * `100 tax / base`, inclusive `100 tax / (base - tax)`, half-up to `decimals` (default 10),
223
+ * trailing zeros dropped. Null when tax or base is not positive, or the denominator is not.
224
+ */
225
+ export declare function solveTaxRate(input: {
226
+ tax: Money;
227
+ base: Money;
228
+ inclusive: boolean;
229
+ decimals?: number;
230
+ }): string | null;
231
+ /**
232
+ * Whether prices include tax (Shopify archive `inferTaxesIncluded`): `explicit` wins; a null
233
+ * total or a non-positive tax is exclusive; else inclusive iff
234
+ * `|sub + ship - total| < |sub + ship + tax - total|`.
235
+ */
236
+ export declare function inferTaxesIncluded(input: {
237
+ subtotal: Money;
238
+ shipping: Money;
239
+ tax: Money;
240
+ total: Money | null;
241
+ explicit?: boolean;
242
+ }): boolean;
243
+ /** `gross` split into `net = round(gross x 100 / (100 + rate))` and `tax = gross - net` (net + tax == gross). */
244
+ export declare function splitGross(gross: Money, ratePercent: number | DecimalText, options?: {
245
+ rounding?: RoundingMode;
246
+ }): {
247
+ net: Money;
248
+ tax: Money;
249
+ };
250
+ /** A unit price without its tax when prices include tax (`round(unit x 100 / (100 + rate))`), else `unit`. */
251
+ export declare function unitNetOfTax(unit: Money, options: {
252
+ taxInclusive: boolean;
253
+ ratePercent: number | DecimalText;
254
+ }): Money;
255
+ /**
256
+ * `refund` spread over positions (each a net and its tax): capped at the gross total, split by
257
+ * gross with the largest remainder, then each gross share split into net and tax in the
258
+ * position's proportion (largest remainder). Per row `net + tax == gross`, and the grosses
259
+ * sum to the (capped) refund. Negative amounts throw `amount_invalid`.
260
+ */
261
+ export declare function allocateWithTax(refund: Money, positions: readonly {
262
+ net: Money;
263
+ tax: Money;
264
+ }[]): {
265
+ net: Money;
266
+ tax: Money;
267
+ gross: Money;
268
+ }[];
269
+ /** The Medusa totals fields `displayTotals` reads (BigNumber shapes or numbers; `raw_<key>` siblings win). */
270
+ interface MedusaTotalsLike {
271
+ readonly [key: string]: unknown;
272
+ }
273
+ interface DisplayTotals {
274
+ readonly subtotal: Money | null;
275
+ readonly discount: Money | null;
276
+ readonly shipping: Money | null;
277
+ readonly tax: Money | null;
278
+ readonly total: Money | null;
279
+ /** True when the tax is already inside the other amounts ("including tax"), false when added. */
280
+ readonly taxIncluded: boolean;
281
+ }
282
+ /**
283
+ * The totals a customer-facing summary shows, one selection for every email: tax-inclusive
284
+ * stores show the gross item and shipping totals with the tax "included", exclusive stores the
285
+ * net subtotals with the tax "added". Each field reads `raw_<key>` first, like
286
+ * `readStoredField`; Medusa's fractional totals round half-up to a storage unit; a missing or
287
+ * unreadable field is null, never 0.
288
+ */
289
+ export declare function displayTotals(totals: MedusaTotalsLike, currency: string, options: {
290
+ taxInclusive: boolean;
291
+ }): DisplayTotals;
292
+ //#endregion
293
+ export type { BuyGetRewardSpec, DiscountAmountOptions, DiscountSpec, DisplayTotals, MarkupOptions, MedusaTotalsLike, OrderValueInput, RetailMarkup, RetailPriceInput };