@stacksjs/commerce 0.75.38 → 0.75.41
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/dist/imports/http.d.ts +36 -0
- package/dist/imports/identity.d.ts +22 -0
- package/dist/imports/index.d.ts +37 -0
- package/dist/imports/money.d.ts +40 -0
- package/dist/imports/shopify.d.ts +40 -0
- package/dist/imports/shopware.d.ts +80 -0
- package/dist/imports/text.d.ts +6 -0
- package/dist/imports/types.d.ts +79 -0
- package/dist/imports/woocommerce.d.ts +62 -0
- package/dist/imports/writer.d.ts +202 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +19 -19
- package/dist/money.d.ts +107 -0
- package/dist/money.js +2 -0
- package/dist/orders/export.d.ts +25 -1
- package/package.json +12 -13
package/dist/money.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Decimal places of a currency's minor unit (USD 2, JPY 0, KWD 3).
|
|
3
|
+
*
|
|
4
|
+
* Read from `Intl`, which carries the ISO 4217 table, so there is no list here
|
|
5
|
+
* to fall out of date. Unknown or missing codes are treated as 2 decimals, the
|
|
6
|
+
* overwhelmingly common case.
|
|
7
|
+
*/
|
|
8
|
+
export declare function currencyExponent(currency: string | null | undefined): number;
|
|
9
|
+
/**
|
|
10
|
+
* A decimal price string as integer minor units.
|
|
11
|
+
*
|
|
12
|
+
* Accepts plain decimals only: `"19.99"`, `"0.10"`, `"1999"`, `"19.9"`, `".5"`.
|
|
13
|
+
* Rejects thousands separators (`"1,000.00"`), signs, exponents and anything
|
|
14
|
+
* else, because each is ambiguous in some locale (`"1,000"` is one in German).
|
|
15
|
+
* Digits past the currency's precision round half up, which only arises when a
|
|
16
|
+
* store is configured with more decimals than its currency has.
|
|
17
|
+
*
|
|
18
|
+
* @returns The amount in minor units, or null for an empty value (unpriced).
|
|
19
|
+
*/
|
|
20
|
+
export declare function decimalToMinor(value: string | number | null | undefined, exponent?: number): number | null;
|
|
21
|
+
/** Integer minor units back to a decimal string, e.g. `1999, 2 -> "19.99"`. */
|
|
22
|
+
export declare function minorToDecimal(minor: number | bigint | string, exponent?: number): string;
|
|
23
|
+
/**
|
|
24
|
+
* Minor units at one precision as minor units at another.
|
|
25
|
+
*
|
|
26
|
+
* WooCommerce reports `prices.price` at the store's configured decimals
|
|
27
|
+
* (`currency_minor_unit`). A USD store set to 0 decimals sends `"20"` for
|
|
28
|
+
* $20.00, which must become 2000 cents, not 20.
|
|
29
|
+
*/
|
|
30
|
+
export declare function rescaleMinor(amount: string | number | null | undefined, fromExponent: number, toExponent: number): number | null;
|
|
31
|
+
/** `1999, 'USD' -> "19.99 USD"`, for reports and exports. Never used for storage. */
|
|
32
|
+
export declare function formatMinor(minor: number, currency: string | null): string;
|
|
33
|
+
/**
|
|
34
|
+
* A stored minor-unit amount as major units, for `Intl.NumberFormat` and
|
|
35
|
+
* charts. `1999, 'USD' -> 19.99`, `1999, 'JPY' -> 1999`, `1999, 'KWD' -> 1.999`.
|
|
36
|
+
*
|
|
37
|
+
* Display only: the result is a float, so never store it or add it up.
|
|
38
|
+
* A non-integer input is rounded to the nearest minor unit first, which is
|
|
39
|
+
* what a legacy row holding a fraction of a cent would have meant.
|
|
40
|
+
*/
|
|
41
|
+
export declare function minorToMajor(minor: number | string | null | undefined, currency: string | null | undefined): number;
|
|
42
|
+
/**
|
|
43
|
+
* A stored minor-unit amount, formatted for people.
|
|
44
|
+
*
|
|
45
|
+
* `formatCurrency(1999, 'USD', 'en-US')` is `"$19.99"`; `(1999, 'JPY', 'en-US')`
|
|
46
|
+
* is `"¥1,999"`. The locale defaults to the runtime's (the viewer's browser in
|
|
47
|
+
* the dashboard). A currency code `Intl` does not know falls back to the
|
|
48
|
+
* report form, `"19.99 XYZ"`, rather than throwing out of a table render.
|
|
49
|
+
*/
|
|
50
|
+
export declare function formatCurrency(minor: number | string | null | undefined, currency: string | null | undefined, locale?: string): string;
|
|
51
|
+
/**
|
|
52
|
+
* A stored minor-unit amount as the decimal string an input field shows,
|
|
53
|
+
* e.g. `1999, 'USD' -> "19.99"`. The inverse of `parseMoneyInput`.
|
|
54
|
+
*/
|
|
55
|
+
export declare function minorToInput(minor: number | string | null | undefined, currency: string | null | undefined): string;
|
|
56
|
+
/** The `step` attribute for a money input: `"0.01"` for USD, `"1"` for JPY. */
|
|
57
|
+
export declare function moneyInputStep(currency: string | null | undefined): string;
|
|
58
|
+
/**
|
|
59
|
+
* Why `input` is not an acceptable amount of `currency`, or `''` when it is.
|
|
60
|
+
*
|
|
61
|
+
* For forms: the dashboard disables Save and shows this next to the field.
|
|
62
|
+
* Stricter than `decimalToMinor` on purpose: a person typing `19.999` for a
|
|
63
|
+
* USD price has made a mistake, and rounding it silently would hide that.
|
|
64
|
+
*/
|
|
65
|
+
export declare function moneyInputError(input: string | number | null | undefined, currency: string | null | undefined, options?: MoneyInputOptions): string;
|
|
66
|
+
/**
|
|
67
|
+
* A money field's value as integer minor units: `"19.99"` in USD is `1999`.
|
|
68
|
+
*
|
|
69
|
+
* Throws `PriceFormatError` with the same message `moneyInputError` gives, so
|
|
70
|
+
* a caller that skipped validation still cannot store a float. Returns null
|
|
71
|
+
* only for an empty, optional field.
|
|
72
|
+
*/
|
|
73
|
+
export declare function parseMoneyInput(input: string | number | null | undefined, currency: string | null | undefined, options?: MoneyInputOptions & { required?: true }): number;
|
|
74
|
+
export declare function parseMoneyInput(input: string | number | null | undefined, currency: string | null | undefined, options: MoneyInputOptions & { required: false }): number | null;
|
|
75
|
+
export declare interface MoneyInputOptions {
|
|
76
|
+
min?: number
|
|
77
|
+
max?: number
|
|
78
|
+
required?: boolean
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Money, at every boundary it crosses.
|
|
82
|
+
*
|
|
83
|
+
* Every amount Stacks commerce stores is an integer in the currency's MINOR
|
|
84
|
+
* unit: cents for USD, whole yen for JPY, fils for KWD. `products.price`,
|
|
85
|
+
* `order_items.price`, `orders.total_amount`, `payments.amount` and the rest
|
|
86
|
+
* hold that integer, and arithmetic (order totals, refunds) happens on it.
|
|
87
|
+
*
|
|
88
|
+
* Conversion happens only where a human or a foreign system is on the other
|
|
89
|
+
* side, and only through this module:
|
|
90
|
+
*
|
|
91
|
+
* - display: `formatCurrency(1999, 'USD')` is `"$19.99"`
|
|
92
|
+
* - input: `parseMoneyInput('19.99', 'USD')` is `1999`
|
|
93
|
+
* - reports: `formatMinor(1999, 'USD')` is `"19.99 USD"`
|
|
94
|
+
* - import: `decimalToMinor('19.99')` and `rescaleMinor(...)`
|
|
95
|
+
*
|
|
96
|
+
* Decimal strings are converted with string and BigInt arithmetic, never
|
|
97
|
+
* through a float: `Math.round(19.99 * 100)` happens to be right,
|
|
98
|
+
* `Math.round(1.005 * 100)` is 100 rather than 101.
|
|
99
|
+
*
|
|
100
|
+
* The module has no imports, so it is safe to bundle into the browser. The
|
|
101
|
+
* dashboard reaches it as `@stacksjs/commerce/money`; server code can use the
|
|
102
|
+
* `@stacksjs/commerce` barrel.
|
|
103
|
+
*/
|
|
104
|
+
export declare class PriceFormatError extends Error {
|
|
105
|
+
public readonly value: unknown;
|
|
106
|
+
constructor(value: unknown, reason: string);
|
|
107
|
+
}
|
package/dist/money.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
var p=Object.defineProperty;var b=(n)=>n;function h(n,e){this[n]=b.bind(null,e)}var x=(n,e)=>{for(var t in e)p(n,t,{get:e[t],enumerable:!0,configurable:!0,set:h.bind(e,t)})};var O=(n,e,t)=>()=>{if(n)try{e=n(n=0)}catch(r){t=[r]}if(t)throw t[0];return e};var S={};x(S,{PriceFormatError:()=>l,currencyExponent:()=>s,decimalToMinor:()=>m,formatCurrency:()=>y,formatMinor:()=>c,minorToDecimal:()=>a,minorToInput:()=>M,minorToMajor:()=>f,moneyInputError:()=>g,moneyInputStep:()=>I,parseMoneyInput:()=>N,rescaleMinor:()=>w});class l extends Error{value;constructor(n,e){super(`Unreadable price ${JSON.stringify(n)}: ${e}`);this.value=n;this.name="PriceFormatError"}}function s(n){if(!n)return 2;try{let e=new Intl.NumberFormat("en",{style:"currency",currency:n}).resolvedOptions().maximumFractionDigits;return typeof e==="number"?e:2}catch{return 2}}function m(n,e=2){if(n===null||n===void 0)return null;let t=String(n).trim();if(t==="")return null;let r=/^(\d*)(?:\.(\d*))?$/.exec(t);if(!r||!/\d/.test(t))throw new l(n,"expected a plain decimal such as 19.99");let u=r[1]||"0",i=r[2]??"",o;if(i.length<=e)o=BigInt(u+i.padEnd(e,"0"));else if(o=BigInt(u+i.slice(0,e)),i.charCodeAt(e)>=53)o+=1n;if(o>BigInt(Number.MAX_SAFE_INTEGER))throw new l(n,"too large to store exactly");return Number(o)}function a(n,e=2){let t=String(n).trim();if(!/^\d+$/.test(t))throw new l(n,"expected a non-negative integer amount in minor units");if(e===0)return t.replace(/^0+(?=\d)/,"");let r=t.padStart(e+1,"0");return`${r.slice(0,-e).replace(/^0+(?=\d)/,"")}.${r.slice(-e)}`}function w(n,e,t){if(n===null||n===void 0||String(n).trim()==="")return null;if(!Number.isInteger(e)||e<0)throw new l(n,`invalid source precision ${e}`);return m(a(String(n),e),t)}function c(n,e){let t=s(e),r=Math.round(Number(n)),u=Number.isSafeInteger(r)?`${r<0?"-":""}${a(Math.abs(r),t)}`:String(n);return e?`${u} ${e}`:u}function f(n,e){let t=Math.round(Number(n??0));if(!Number.isFinite(t))return 0;let r=a(Math.abs(t),s(e));return t<0?-Number(r):Number(r)}function y(n,e,t){let r=(e||"USD").toUpperCase(),u=f(n,r);try{return new Intl.NumberFormat(t,{style:"currency",currency:r}).format(u)}catch{return c(Math.round(Number(n??0))||0,r)}}function M(n,e){if(n===null||n===void 0||n==="")return"";let t=Math.round(Number(n));if(!Number.isFinite(t))return"";let r=a(Math.abs(t),s(e));return t<0?`-${r}`:r}function I(n){let e=s(n);return e===0?"1":`0.${"1".padStart(e,"0")}`}function g(n,e,t={}){let r=n===null||n===void 0?"":String(n).trim(),u=s(e),i=(e||"USD").toUpperCase();if(r==="")return t.required===!1?"":"Enter an amount.";let o=/^(\d*)(?:\.(\d*))?$/.exec(r);if(!o||!/\d/.test(r))return u===0?"Enter a whole number, for example 1999.":`Enter a plain amount, for example ${a(1999,u)}.`;if((o[2]??"").length>u)return u===0?`${i} amounts have no decimal places.`:`${i} amounts have at most ${u} decimal ${u===1?"place":"places"}.`;let d;try{d=m(r,u)}catch{return"That amount is too large."}if(d===null)return"Enter an amount.";if(t.min!==void 0&&d<t.min)return`Enter at least ${c(t.min,i)}.`;if(t.max!==void 0&&d>t.max)return`Enter at most ${c(t.max,i)}.`;return""}function N(n,e,t={}){let r=g(n,e,t);if(r)throw new l(n,r);return m(n,s(e))}export{l as PriceFormatError,s as currencyExponent,m as decimalToMinor,y as formatCurrency,c as formatMinor,a as minorToDecimal,M as minorToInput,f as minorToMajor,g as moneyInputError,I as moneyInputStep,N as parseMoneyInput,w as rescaleMinor};
|
package/dist/orders/export.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { OrderWithTotals } from '../types';
|
|
1
2
|
import type { SpreadsheetWrapper } from 'ts-spreadsheets';
|
|
2
3
|
/**
|
|
3
4
|
* Export orders to a spreadsheet
|
|
@@ -5,6 +6,29 @@ import type { SpreadsheetWrapper } from 'ts-spreadsheets';
|
|
|
5
6
|
* @returns Spreadsheet object ready for download or storage
|
|
6
7
|
*/
|
|
7
8
|
export declare function exportOrders(format?: 'csv' | 'excel'): Promise<SpreadsheetWrapper>;
|
|
9
|
+
/**
|
|
10
|
+
* Every order with its customer and its line items (each with its product),
|
|
11
|
+
* ready for `prepareOrdersForExport`.
|
|
12
|
+
*
|
|
13
|
+
* Four flat queries, whatever the number of orders: the orders, then the
|
|
14
|
+
* customers, line items and products they reference, each read with `IN` and
|
|
15
|
+
* stitched together in memory. Nothing is fetched per order.
|
|
16
|
+
*
|
|
17
|
+
* The orders are read on their own rather than joined to customers: a
|
|
18
|
+
* `SELECT *` across that join returns two `id` columns, and the customer's
|
|
19
|
+
* silently replaces the order's in the row object.
|
|
20
|
+
*/
|
|
21
|
+
export declare function fetchOrdersForExport(): Promise<OrderWithTotals[]>;
|
|
22
|
+
/**
|
|
23
|
+
* Prepare orders data for spreadsheet export
|
|
24
|
+
*
|
|
25
|
+
* Amounts are stored as integer minor units, so `total_amount: 1999` in USD is
|
|
26
|
+
* written as `19.99 USD`, never as `1999` or `$1999` (stacksjs/stacks#2851).
|
|
27
|
+
*
|
|
28
|
+
* @param orders Array of order objects
|
|
29
|
+
* @returns Spreadsheet data structure
|
|
30
|
+
*/
|
|
31
|
+
export declare function prepareOrdersForExport(orders: OrderWithTotals[]): { headings: (keyof ExportedOrder)[], data: (string | number)[][] };
|
|
8
32
|
/**
|
|
9
33
|
* Export orders and automatically download
|
|
10
34
|
* @param format The format of the spreadsheet (default is CSV)
|
|
@@ -26,7 +50,7 @@ export declare interface ExportedOrder {
|
|
|
26
50
|
'Order ID': number
|
|
27
51
|
'Customer': string
|
|
28
52
|
'Date': string
|
|
29
|
-
'Total':
|
|
53
|
+
'Total': string
|
|
30
54
|
'Status': string
|
|
31
55
|
'Items': string
|
|
32
56
|
}
|
package/package.json
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/commerce",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"
|
|
5
|
-
"version": "0.75.38",
|
|
4
|
+
"version": "0.75.41",
|
|
6
5
|
"description": "Stacks commerce utilities.",
|
|
7
6
|
"author": "Chris Breuer",
|
|
8
7
|
"contributors": [
|
|
@@ -58,17 +57,17 @@
|
|
|
58
57
|
"prepublishOnly": "bun run build"
|
|
59
58
|
},
|
|
60
59
|
"dependencies": {
|
|
61
|
-
"@stacksjs/cache": "0.75.
|
|
62
|
-
"@stacksjs/config": "0.75.
|
|
63
|
-
"@stacksjs/database": "0.75.
|
|
64
|
-
"@stacksjs/env": "0.75.
|
|
65
|
-
"@stacksjs/error-handling": "0.75.
|
|
66
|
-
"@stacksjs/events": "0.75.
|
|
67
|
-
"@stacksjs/logging": "0.75.
|
|
68
|
-
"@stacksjs/orm": "0.75.
|
|
69
|
-
"@stacksjs/payments": "0.75.
|
|
70
|
-
"@stacksjs/realtime": "0.75.
|
|
71
|
-
"@stacksjs/strings": "0.75.
|
|
60
|
+
"@stacksjs/cache": "0.75.41",
|
|
61
|
+
"@stacksjs/config": "0.75.41",
|
|
62
|
+
"@stacksjs/database": "0.75.41",
|
|
63
|
+
"@stacksjs/env": "0.75.41",
|
|
64
|
+
"@stacksjs/error-handling": "0.75.41",
|
|
65
|
+
"@stacksjs/events": "0.75.41",
|
|
66
|
+
"@stacksjs/logging": "0.75.41",
|
|
67
|
+
"@stacksjs/orm": "0.75.41",
|
|
68
|
+
"@stacksjs/payments": "0.75.41",
|
|
69
|
+
"@stacksjs/realtime": "0.75.41",
|
|
70
|
+
"@stacksjs/strings": "0.75.41",
|
|
72
71
|
"ts-spreadsheets": "^0.2.0"
|
|
73
72
|
},
|
|
74
73
|
"devDependencies": {
|