platform-types 1.10.778 → 1.10.780
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/cjs/order.js +13 -1
- package/dist/cjs/storefrontWebLiteralKeys.js +11 -46
- package/dist/cjs/wholesaleRequest.js +40 -1
- package/dist/order.d.ts +36 -8
- package/dist/order.js +13 -1
- package/dist/store.d.ts +32 -0
- package/dist/storefrontWebLiteralKeys.d.ts +5 -9
- package/dist/storefrontWebLiteralKeys.js +10 -44
- package/dist/wholesaleRequest.d.ts +22 -0
- package/dist/wholesaleRequest.js +39 -0
- package/package.json +1 -1
package/dist/cjs/order.js
CHANGED
|
@@ -109,7 +109,8 @@ const positiveUnits = (value) => (typeof value === 'number' && value > 0 ? value
|
|
|
109
109
|
* The ONE reader of the per-line fulfilment ledger (`OrderLine.fulfilledQuantity`).
|
|
110
110
|
*
|
|
111
111
|
* - A missing `fulfilledQuantity` counts as 0; lines with no or zero `quantity`
|
|
112
|
-
* are ignored on both sides of the ratio
|
|
112
|
+
* are ignored on both sides of the ratio, and so is a freight line
|
|
113
|
+
* (`lineKind: 'freight'` with no `productId`), which is never shipped.
|
|
113
114
|
* - `deliveredAt > 0` with no `shipments` is `complete` — a whole-order delivery
|
|
114
115
|
* that never went through the shipment ledger.
|
|
115
116
|
* - A `disabled` or cancelled row is `none`, whatever timestamps it carries: a
|
|
@@ -120,6 +121,12 @@ const orderFulfilmentProgress = (order) => {
|
|
|
120
121
|
let orderedUnits = 0;
|
|
121
122
|
let fulfilledUnits = 0;
|
|
122
123
|
for (const line of order.items ?? []) {
|
|
124
|
+
// A freight line is a charge, never handed over, so it would hold a
|
|
125
|
+
// fully shipped order at `partial` forever. The same test as
|
|
126
|
+
// `isFreightLine` (`stacks/helpers/discountCalculations.ts`), inlined
|
|
127
|
+
// because contracts import nothing from `stacks/`.
|
|
128
|
+
if (line?.lineKind === 'freight' && line.productId === undefined)
|
|
129
|
+
continue;
|
|
123
130
|
const ordered = positiveUnits(line?.quantity);
|
|
124
131
|
if (ordered === 0)
|
|
125
132
|
continue;
|
|
@@ -279,6 +286,9 @@ exports.orderFulfilmentProgress = orderFulfilmentProgress;
|
|
|
279
286
|
* is refused after it, like every other refusal at commit.
|
|
280
287
|
* - `ORDER_HAS_KIT_LINES` · 409 — `mode: 'edit'` on an order holding a kit line
|
|
281
288
|
* (`CartLine.kit`). Cancel or return the order instead. Nothing was written.
|
|
289
|
+
* - `ORDER_HAS_FREIGHT_LINE` · 409 — `mode: 'edit'` on an order holding a
|
|
290
|
+
* freight line (`OrderLine.lineKind: 'freight'`). Cancel or return the order
|
|
291
|
+
* instead. Nothing was written.
|
|
282
292
|
* - `CART_PROMOTION_UNAVAILABLE` · 409 — the insert leg converting a STORED
|
|
283
293
|
* ticket whose promotion ended, was paused, deleted, has not started or is
|
|
284
294
|
* no longer cart-applicable; the `PromotionRefusal` rides `data.reason`. No
|
|
@@ -611,6 +621,8 @@ exports.ORDER_ERROR_CODES = [
|
|
|
611
621
|
'CART_PROMOTION_UNAVAILABLE',
|
|
612
622
|
// `mode: 'edit'` on an order holding a kit line; cancel or return it instead.
|
|
613
623
|
'ORDER_HAS_KIT_LINES',
|
|
624
|
+
// `mode: 'edit'` on an order holding a freight line; cancel or return it instead.
|
|
625
|
+
'ORDER_HAS_FREIGHT_LINE',
|
|
614
626
|
// Create-leg refusals about the sale's source, already answered on the wire.
|
|
615
627
|
'ORDER_TARGET_REQUIRED',
|
|
616
628
|
'ORDER_SOURCE_CONFLICT',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isAdoptableStorefrontLiteral = exports.
|
|
3
|
+
exports.isAdoptableStorefrontLiteral = exports.isStorefrontLiteralKey = exports.STOREFRONT_WEB_LITERAL_KEYS = void 0;
|
|
4
4
|
const storefrontDesignRegistry_ts_1 = require("./storefrontDesignRegistry.js");
|
|
5
5
|
/**
|
|
6
6
|
* Every storefront `WEB` literal key a shop may override, in code-unit order.
|
|
@@ -17,6 +17,9 @@ const storefrontDesignRegistry_ts_1 = require("./storefrontDesignRegistry.js");
|
|
|
17
17
|
* - keys whose storefront value is not a plain `{name}`-token sentence (it
|
|
18
18
|
* branches, computes, or is not a string), which a shop string cannot
|
|
19
19
|
* express.
|
|
20
|
+
* Route paths (the former `NAVIGATE_*` keys) are not copy at all: they live in
|
|
21
|
+
* the storefront's own config, and the api refuses and drops a `NAVIGATE_*`
|
|
22
|
+
* literal on every storefront surface.
|
|
20
23
|
* An editor that lists any of those offers an edit the server refuses.
|
|
21
24
|
*
|
|
22
25
|
* Interpolated values use `{name}` tokens named after the storefront's own
|
|
@@ -492,6 +495,8 @@ exports.STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
492
495
|
'DATA_RIGHTS_COLLECTION_NOTES',
|
|
493
496
|
'DATA_RIGHTS_COLLECTION_ORDERS',
|
|
494
497
|
'DATA_RIGHTS_COLLECTION_PAYMENTS',
|
|
498
|
+
'DATA_RIGHTS_COLLECTION_RECENT_PURCHASES',
|
|
499
|
+
'DATA_RIGHTS_COLLECTION_WHOLESALE_REQUESTS',
|
|
495
500
|
'DATA_RIGHTS_DIALOG_ACK',
|
|
496
501
|
'DATA_RIGHTS_DIALOG_CONFIRM',
|
|
497
502
|
'DATA_RIGHTS_DIALOG_FISCAL',
|
|
@@ -815,27 +820,6 @@ exports.STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
815
820
|
'MOBILE_BUTTONS_FAVORITES',
|
|
816
821
|
'MOBILE_BUTTONS_INVOICES',
|
|
817
822
|
'MOBILE_BUTTONS_ORDERS',
|
|
818
|
-
'NAVIGATE_APPOINTMENTS',
|
|
819
|
-
'NAVIGATE_BASKET',
|
|
820
|
-
'NAVIGATE_BRANDS',
|
|
821
|
-
'NAVIGATE_CATEGORIES',
|
|
822
|
-
'NAVIGATE_CHECKOUT',
|
|
823
|
-
'NAVIGATE_FAVORITES',
|
|
824
|
-
'NAVIGATE_HOME',
|
|
825
|
-
'NAVIGATE_INCOMES',
|
|
826
|
-
'NAVIGATE_INVOICES',
|
|
827
|
-
'NAVIGATE_LOGIN',
|
|
828
|
-
'NAVIGATE_LOGOUT',
|
|
829
|
-
'NAVIGATE_MAINTENANCE',
|
|
830
|
-
'NAVIGATE_NEW_ARRIVALS',
|
|
831
|
-
'NAVIGATE_NOTIFICATIONS',
|
|
832
|
-
'NAVIGATE_ORDERS',
|
|
833
|
-
'NAVIGATE_PAYMENTS',
|
|
834
|
-
'NAVIGATE_PROFILE',
|
|
835
|
-
'NAVIGATE_RECOVER',
|
|
836
|
-
'NAVIGATE_REGISTRATION',
|
|
837
|
-
'NAVIGATE_SALE',
|
|
838
|
-
'NAVIGATE_SESSIONS',
|
|
839
823
|
'NETWORK_OFFLINE',
|
|
840
824
|
'NETWORK_REQUEST_FAILED',
|
|
841
825
|
'NETWORK_TIMEOUT',
|
|
@@ -1078,6 +1062,7 @@ exports.STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
1078
1062
|
'PREVIEW_LOADING',
|
|
1079
1063
|
'PREVIEW_READ_FAILED',
|
|
1080
1064
|
'PREVIEW_READ_ONLY',
|
|
1065
|
+
'PREVIEW_RECENTLY_BOUGHT',
|
|
1081
1066
|
'PREVIEW_RESTART',
|
|
1082
1067
|
'PREVIEW_RETRY',
|
|
1083
1068
|
'PREVIEW_TITLE',
|
|
@@ -1346,6 +1331,7 @@ exports.STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
1346
1331
|
'STOREFRONT_FOOTER_NAV_ARIA',
|
|
1347
1332
|
'STOREFRONT_MERCHANT_NAV_ARIA',
|
|
1348
1333
|
'STOREFRONT_NAV_GROUP_FALLBACK',
|
|
1334
|
+
'STOREFRONT_PRODUCTS_REFRESH_FAILED',
|
|
1349
1335
|
'STOREFRONT_SEARCH',
|
|
1350
1336
|
'STOREFRONT_SOCIAL_FACEBOOK',
|
|
1351
1337
|
'STOREFRONT_SOCIAL_INSTAGRAM',
|
|
@@ -1374,34 +1360,13 @@ const STOREFRONT_WEB_LITERAL_KEY_SET = new Set(exports.STOREFRONT_WEB_LITERAL_KE
|
|
|
1374
1360
|
/** Whether a shop may override `key` — membership in {@link STOREFRONT_WEB_LITERAL_KEYS}. */
|
|
1375
1361
|
const isStorefrontLiteralKey = (key) => STOREFRONT_WEB_LITERAL_KEY_SET.has(key);
|
|
1376
1362
|
exports.isStorefrontLiteralKey = isStorefrontLiteralKey;
|
|
1377
|
-
/** Keys whose value is a storefront route the storefront renders as a link target. */
|
|
1378
|
-
const STOREFRONT_NAVIGATE_LITERAL_PREFIX = 'NAVIGATE_';
|
|
1379
|
-
/**
|
|
1380
|
-
* A same-origin path: a leading `/`, a second character that is neither `/` nor `\`
|
|
1381
|
-
* (`//host` and `/\host` are protocol-relative to a browser), and no whitespace,
|
|
1382
|
-
* backslash, control character (`\p{Cc}`) or invisible format character (`\p{Cf}`: every
|
|
1383
|
-
* bidi mark including U+061C, zero-width characters, the soft hyphen, tag characters)
|
|
1384
|
-
* anywhere. Browsers strip tab and newline before parsing, so `/\t/host` becomes `//host`;
|
|
1385
|
-
* invisible and directional characters can also disguise the link target. A scheme
|
|
1386
|
-
* cannot start with `/`.
|
|
1387
|
-
*/
|
|
1388
|
-
const STOREFRONT_SAME_ORIGIN_PATH_RE = /^\/(?![/\\])[^\s\\\p{Cc}\p{Cf}]*$/u;
|
|
1389
|
-
/**
|
|
1390
|
-
* Whether `value` may be stored, published or served for `key`. A `NAVIGATE_*` key is
|
|
1391
|
-
* rendered as a link, so it must be a same-origin path — otherwise an override could
|
|
1392
|
-
* send a shop's customers to an off-site look-alike login page. Every other key is
|
|
1393
|
-
* unconstrained here (key membership, well-formedness and length are checked apart).
|
|
1394
|
-
*/
|
|
1395
|
-
const isAllowedStorefrontLiteralValue = (key, value) => !key.startsWith(STOREFRONT_NAVIGATE_LITERAL_PREFIX) || STOREFRONT_SAME_ORIGIN_PATH_RE.test(value);
|
|
1396
|
-
exports.isAllowedStorefrontLiteralValue = isAllowedStorefrontLiteralValue;
|
|
1397
1363
|
/**
|
|
1398
1364
|
* Whether a shop's stored `value` for `key` is one a save keeps, a read serves and the editor
|
|
1399
|
-
* baseline adopts: a shop-overridable key
|
|
1400
|
-
* {@link STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS} code points
|
|
1365
|
+
* baseline adopts: a shop-overridable key and a well-formed string within
|
|
1366
|
+
* {@link STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS} code points.
|
|
1401
1367
|
*/
|
|
1402
1368
|
const isAdoptableStorefrontLiteral = (key, value) => (0, exports.isStorefrontLiteralKey)(key) &&
|
|
1403
1369
|
typeof value === 'string' &&
|
|
1404
1370
|
value.isWellFormed() &&
|
|
1405
|
-
Array.from(value).length <= storefrontDesignRegistry_ts_1.STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS
|
|
1406
|
-
(0, exports.isAllowedStorefrontLiteralValue)(key, value);
|
|
1371
|
+
Array.from(value).length <= storefrontDesignRegistry_ts_1.STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS;
|
|
1407
1372
|
exports.isAdoptableStorefrontLiteral = isAdoptableStorefrontLiteral;
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* `ecommerce.config.wholesaleRequests` is `true` (absent = off).
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.WHOLESALE_REQUEST_REASON_MAX = exports.WHOLESALE_REQUEST_PHONE_MAX = exports.WHOLESALE_REQUEST_MESSAGE_MAX = exports.WHOLESALE_REQUEST_ACTIVITY_MAX = exports.WHOLESALE_REQUEST_RAZON_SOCIAL_MAX = exports.WHOLESALE_REQUESTS_PAGE_MAX = exports.WHOLESALE_REQUEST_STATES = void 0;
|
|
14
|
+
exports.WHOLESALE_REQUEST_ERROR_CODES = exports.WHOLESALE_REQUEST_REASON_MAX = exports.WHOLESALE_REQUEST_PHONE_MAX = exports.WHOLESALE_REQUEST_MESSAGE_MAX = exports.WHOLESALE_REQUEST_ACTIVITY_MAX = exports.WHOLESALE_REQUEST_RAZON_SOCIAL_MAX = exports.WHOLESALE_REQUESTS_PAGE_MAX = exports.WHOLESALE_REQUEST_STATES = void 0;
|
|
15
15
|
/** The three states a request moves through. */
|
|
16
16
|
exports.WHOLESALE_REQUEST_STATES = ['pending', 'approved', 'declined'];
|
|
17
17
|
/** `GET /customers?mode=wholesale-requests` page ceiling; the default page is 50. */
|
|
@@ -23,3 +23,42 @@ exports.WHOLESALE_REQUEST_MESSAGE_MAX = 1000;
|
|
|
23
23
|
exports.WHOLESALE_REQUEST_PHONE_MAX = 30;
|
|
24
24
|
/** Character ceiling on the operator's decline reason, counted after trimming. */
|
|
25
25
|
exports.WHOLESALE_REQUEST_REASON_MAX = 500;
|
|
26
|
+
/**
|
|
27
|
+
* Every `error` code the wholesale-request flow answers on its own behalf:
|
|
28
|
+
* - web `POST /user { mode: 'wholesale-request' }` (`stacks/web/lambdas/user/_wholesaleRequest.ts`):
|
|
29
|
+
* `WHOLESALE_REQUESTS_DISABLED`, `CUSTOMER_NOT_FOUND`, `CUSTOMER_ANONYMIZED`, `USER_NOT_ENABLED`,
|
|
30
|
+
* `CUSTOMER_ALREADY_WHOLESALE`, `WHOLESALE_REQUEST_CONTENDED`, `WHOLESALE_REQUEST_PENDING`;
|
|
31
|
+
* - app `GET /customers?mode=wholesale-requests` and `POST /customers { mode: 'wholesale-decision' }`
|
|
32
|
+
* (`stacks/lambdas/customers/_wholesaleRequests.ts`): `ROLE_FORBIDDEN`, `ADMIN_REQUIRED`,
|
|
33
|
+
* `INVALID_CURSOR`, `WHOLESALE_REQUEST_NOT_PENDING`, `WHOLESALE_DECISION_CONTENDED`,
|
|
34
|
+
* `CUSTOMER_NOT_FOUND`, `CUSTOMER_ANONYMIZED`, `CUSTOMER_MERGED`, `PRICE_LIST_NOT_FOUND`,
|
|
35
|
+
* `PRICE_LIST_NOT_WHOLESALE`, `WHOLESALE_REQUEST_NOT_FOUND`;
|
|
36
|
+
* - the opt-in refusal both configuration writers answer when `ecommerce.config.wholesaleRequests`
|
|
37
|
+
* turns on with no wholesale-class list: `WHOLESALE_LIST_REQUIRED` (`409`). It is also in
|
|
38
|
+
* `STORE_PATCH_ERROR_CODES`, on purpose: a wholesale client handles it without reading that tuple.
|
|
39
|
+
*
|
|
40
|
+
* The rule: a code is listed when a wholesale handler writes it as its own literal, and each of
|
|
41
|
+
* those literals is typed `satisfies WholesaleRequestErrorCode`, so one this list misses fails
|
|
42
|
+
* typecheck. A code those routes forward from a shared helper is not listed, though a wholesale
|
|
43
|
+
* route can answer it: the customer-access refusals (`refuseCustomerAccess`), `VALIDATION_FAILED`
|
|
44
|
+
* (`validateRequest`), the handler wrapper's own codes and the authorizer's.
|
|
45
|
+
*/
|
|
46
|
+
exports.WHOLESALE_REQUEST_ERROR_CODES = [
|
|
47
|
+
'WHOLESALE_REQUESTS_DISABLED',
|
|
48
|
+
'CUSTOMER_NOT_FOUND',
|
|
49
|
+
'CUSTOMER_ANONYMIZED',
|
|
50
|
+
'USER_NOT_ENABLED',
|
|
51
|
+
'CUSTOMER_ALREADY_WHOLESALE',
|
|
52
|
+
'WHOLESALE_REQUEST_CONTENDED',
|
|
53
|
+
'WHOLESALE_REQUEST_PENDING',
|
|
54
|
+
'ROLE_FORBIDDEN',
|
|
55
|
+
'ADMIN_REQUIRED',
|
|
56
|
+
'INVALID_CURSOR',
|
|
57
|
+
'WHOLESALE_REQUEST_NOT_PENDING',
|
|
58
|
+
'WHOLESALE_DECISION_CONTENDED',
|
|
59
|
+
'CUSTOMER_MERGED',
|
|
60
|
+
'PRICE_LIST_NOT_FOUND',
|
|
61
|
+
'PRICE_LIST_NOT_WHOLESALE',
|
|
62
|
+
'WHOLESALE_REQUEST_NOT_FOUND',
|
|
63
|
+
'WHOLESALE_LIST_REQUIRED',
|
|
64
|
+
];
|
package/dist/order.d.ts
CHANGED
|
@@ -250,6 +250,25 @@ declare global {
|
|
|
250
250
|
productIds: string[];
|
|
251
251
|
}
|
|
252
252
|
interface OrderLine extends CartLine {
|
|
253
|
+
/**
|
|
254
|
+
* What kind of line this is. Absent means a goods (or service) line, which is
|
|
255
|
+
* every line written before freight existed: forward-only, never backfilled.
|
|
256
|
+
*
|
|
257
|
+
* `'freight'`: a server-owned, productless delivery charge. It carries no
|
|
258
|
+
* `productId` — a line naming one is goods whatever this says
|
|
259
|
+
* (`isFreightLine`); the order discount never applies to it, it moves no
|
|
260
|
+
* stock and writes no `SALE#` row, and it is never returnable or shippable.
|
|
261
|
+
* A return never credits it: the freight stays with the store.
|
|
262
|
+
*
|
|
263
|
+
* Fiscally the voucher reads the line's OWN stored `ivaType`, stamped from
|
|
264
|
+
* the store's `integrations.afip.freight` when the line is written, so a
|
|
265
|
+
* later config change never re-rates it. Only its Concepto is read live off
|
|
266
|
+
* that config, on a factura; a credit note restates its factura's.
|
|
267
|
+
*
|
|
268
|
+
* ⚠️ **Server-owned.** No order writer accepts it from a client;
|
|
269
|
+
* `stripServerOwnedLineFields` drops a caller-sent value.
|
|
270
|
+
*/
|
|
271
|
+
lineKind?: 'freight';
|
|
253
272
|
/** Base unit frozen from the product at sale; absent means unknown, never inferred on historical lines. */
|
|
254
273
|
unit?: ProductUnit;
|
|
255
274
|
/** Server-owned denomination of finite cost; absent means unknown. */
|
|
@@ -908,12 +927,17 @@ declare global {
|
|
|
908
927
|
* deduction skips a service line rather than moving inventory a second
|
|
909
928
|
* time.
|
|
910
929
|
*
|
|
911
|
-
* `Order.discount`
|
|
912
|
-
*
|
|
913
|
-
*
|
|
914
|
-
*
|
|
915
|
-
*
|
|
916
|
-
*
|
|
930
|
+
* ⚠️ `Order.discount` DOES reach those lines. The ticket's own absolute
|
|
931
|
+
* `discount` is already spent in them, and `POST /orders` refuses an
|
|
932
|
+
* operator percentage on an order carrying this pointer; but a same-visit
|
|
933
|
+
* handover whose counter basket carries a discount stores
|
|
934
|
+
* `goodsDiscountPercent` (`_deliverOrder.ts`, `buildDeliveryOrderRow`): the
|
|
935
|
+
* basket's discount over the FULL gross, basket plus service lines. Every
|
|
936
|
+
* per-line site (`chargedLineTotal`, `buildInvoiceEconomics`) then cuts
|
|
937
|
+
* EVERY line by it, service lines included, so the order's total discount
|
|
938
|
+
* equals the basket's while being spread across the repair too. With no
|
|
939
|
+
* basket discount it is `0` and the service lines are billed exactly as
|
|
940
|
+
* minted. Only a freight line (`lineKind`) is ever exempt.
|
|
917
941
|
*/
|
|
918
942
|
serviceOrderId?: string;
|
|
919
943
|
/**
|
|
@@ -2542,7 +2566,8 @@ type OrderFulfilmentProgressInput = Pick<Partial<Order>, 'items' | 'shipments' |
|
|
|
2542
2566
|
* The ONE reader of the per-line fulfilment ledger (`OrderLine.fulfilledQuantity`).
|
|
2543
2567
|
*
|
|
2544
2568
|
* - A missing `fulfilledQuantity` counts as 0; lines with no or zero `quantity`
|
|
2545
|
-
* are ignored on both sides of the ratio
|
|
2569
|
+
* are ignored on both sides of the ratio, and so is a freight line
|
|
2570
|
+
* (`lineKind: 'freight'` with no `productId`), which is never shipped.
|
|
2546
2571
|
* - `deliveredAt > 0` with no `shipments` is `complete` — a whole-order delivery
|
|
2547
2572
|
* that never went through the shipment ledger.
|
|
2548
2573
|
* - A `disabled` or cancelled row is `none`, whatever timestamps it carries: a
|
|
@@ -2692,6 +2717,9 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2692
2717
|
* is refused after it, like every other refusal at commit.
|
|
2693
2718
|
* - `ORDER_HAS_KIT_LINES` · 409 — `mode: 'edit'` on an order holding a kit line
|
|
2694
2719
|
* (`CartLine.kit`). Cancel or return the order instead. Nothing was written.
|
|
2720
|
+
* - `ORDER_HAS_FREIGHT_LINE` · 409 — `mode: 'edit'` on an order holding a
|
|
2721
|
+
* freight line (`OrderLine.lineKind: 'freight'`). Cancel or return the order
|
|
2722
|
+
* instead. Nothing was written.
|
|
2695
2723
|
* - `CART_PROMOTION_UNAVAILABLE` · 409 — the insert leg converting a STORED
|
|
2696
2724
|
* ticket whose promotion ended, was paused, deleted, has not started or is
|
|
2697
2725
|
* no longer cart-applicable; the `PromotionRefusal` rides `data.reason`. No
|
|
@@ -2942,6 +2970,6 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
|
|
|
2942
2970
|
* `SUBSCRIPTION_READONLY`) sit on the order CREATE leg only: an edit is not a new
|
|
2943
2971
|
* order, so `bareOrderPostHandler` routes past `requireMetered` entirely.
|
|
2944
2972
|
*/
|
|
2945
|
-
export declare const ORDER_ERROR_CODES: readonly ["ORDER_COST_DENOMINATION_UNKNOWN", "SERVICE_ORDER_DELIVERY_MANAGED", "ORDER_NOT_FOUND", "ORDER_LOCKED", "ORDER_NOT_READY", "ORDER_DELIVERED_ANOTHER_DAY", "ORDER_DELIVERY_STATE_UNCHANGED", "ORDER_ILLEGAL_TRANSITION", "ORDER_VERSION_CONFLICT", "CUSTOMER_NOT_FOUND", "CUSTOMER_MERGED", "ORDER_HAS_NO_CUSTOMER", "CUSTOMER_ANONYMIZED", "FX_CONVERSION_UNAVAILABLE", "ROLE_FORBIDDEN", "ORDER_CANCELLED", "PAYMENT_SETTLED_ON_ANOTHER_ORDER", "ORDER_HAS_SHIPMENTS", "ORDER_HAS_RETURNS", "SHIPMENT_QUANTITY_EXCEEDED", "SHIPMENT_LINE_MISMATCH", "SHIPMENT_NOT_FOUND", "SHIPMENT_LIMIT_REACHED", "SHIPMENT_TOO_LARGE", "ORDER_FULFILMENT_EXTERNAL", "SHIPMENT_FAILED", "ADMIN_REQUIRED", "IDEMPOTENCY_KEY_REQUIRED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_LOCK_CONTENTION", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENT_RESPONSE_NOT_CACHED", "ORDER_CANCELLATION_NOT_PROTECTED", "ORDER_CANCELLATION_COMMITTED", "ORDER_CANCELLATION_LOCKED", "ORDER_CANCELLATION_TOO_LARGE", "ORDER_CANCELLATION_FAILED", "SALE_LEDGER_RETRACTION_REFUSED", "SALE_LEDGER_ROW_NOT_OWNED", "PRODUCT_NOT_FOUND", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "DEPOSIT_SOURCE_NOT_ALLOWED", "DEPOSIT_CURRENCY_MISMATCH", "DEPOSIT_EXCEEDS_TOTAL", "DEPOSIT_FREEZE_REQUIRES_INVOICE", "DEPOSIT_FREEZE_INVOICE_PENDING", "DEPOSIT_CHARACTERIZATION_CONFLICT", "DEPOSIT_FREEZE_INVOICE_NOT_QUALIFYING", "DEPOSIT_INVOICED_ORDER_MUST_FREEZE", "DEPOSIT_FROZEN_ORDER_MUST_FREEZE", "DEPOSIT_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "TILL_TENDER_REQUIRES_DEPOSIT", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "ORDER_PRICE_FROZEN", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "UNIT_QUANTITY_UNREPRESENTABLE", "KIT_RECIPE_CHANGED", "CART_PROMOTION_UNAVAILABLE", "ORDER_HAS_KIT_LINES", "ORDER_TARGET_REQUIRED", "ORDER_SOURCE_CONFLICT", "ORDER_CUSTOMER_REQUIRED", "BASKET_EMPTY", "BASKET_CHANGED_DURING_CHECKOUT", "CART_VERSION_CREATE_ONLY", "CART_VERSION_REQUIRES_CART_ID", "CART_REVISION_STALE", "CART_CUSTOMER_MISMATCH", "COUNTER_SALE_CREATE_ONLY", "SOLD_AT_CREATE_ONLY", "SOLD_AT_IN_FUTURE", "ORDER_TENDER_CREATE_ONLY", "CREDIT_OVERRIDE_CREATE_ONLY", "ON_ACCOUNT_CREATE_ONLY", "ON_ACCOUNT_WITH_TENDERS", "TENDERS_REQUIRE_COUNTER_SALE", "LINES_REQUIRE_COUNTER_SALE", "PRODUCT_COST_UNKNOWN", "PRICE_CHANGE_DISABLED", "LINE_DISCOUNT_EXCEEDS_MAX", "CUSTOMER_DISABLED", "SHIFT_NOT_AVAILABLE", "SOLD_AT_OUTSIDE_SHIFT", "ORDER_CURRENCY_NOT_SUBSCRIBED", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "PAYMENT_METHOD_UNAVAILABLE", "CART_PRICES_CHANGED", "ORDER_ID_COLLISION", "DELIVERY_METHOD_NOT_FOUND", "ORDER_BELOW_MINIMUM_PURCHASE", "ORDER_INVALID_CART", "CART_CHANGED_SINCE_CONFIRM", "EMAIL_VERIFICATION_REQUIRED", "ACCOUNT_DISABLED", "CUSTOMER_ACCESS_PENDING", "CUSTOMER_ACCESS_REJECTED", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "ORDER_DISCOUNT_AFTER_INVOICE", "ORDER_DISCOUNT_ON_SERVICE_ORDER", "ORDER_DISCOUNT_ON_MARKETPLACE_ORDER", "ORDER_INVOICE_METHOD_OUTSTANDING_FACTURA", "ORDER_SERVICE_PERIOD_AFTER_INVOICE", "ORDER_ATTEMPT_COMMITTED", "ORDER_ATTEMPT_ABANDONED", "ORDER_ATTEMPT_KEY_EXPIRED", "ORDER_ATTEMPT_KEY_SCOPE_MISMATCH", "ORDER_COMPLETION_ATTEMPT_COMMITTED", "ORDER_COMPLETION_ATTEMPT_ABANDONED"];
|
|
2973
|
+
export declare const ORDER_ERROR_CODES: readonly ["ORDER_COST_DENOMINATION_UNKNOWN", "SERVICE_ORDER_DELIVERY_MANAGED", "ORDER_NOT_FOUND", "ORDER_LOCKED", "ORDER_NOT_READY", "ORDER_DELIVERED_ANOTHER_DAY", "ORDER_DELIVERY_STATE_UNCHANGED", "ORDER_ILLEGAL_TRANSITION", "ORDER_VERSION_CONFLICT", "CUSTOMER_NOT_FOUND", "CUSTOMER_MERGED", "ORDER_HAS_NO_CUSTOMER", "CUSTOMER_ANONYMIZED", "FX_CONVERSION_UNAVAILABLE", "ROLE_FORBIDDEN", "ORDER_CANCELLED", "PAYMENT_SETTLED_ON_ANOTHER_ORDER", "ORDER_HAS_SHIPMENTS", "ORDER_HAS_RETURNS", "SHIPMENT_QUANTITY_EXCEEDED", "SHIPMENT_LINE_MISMATCH", "SHIPMENT_NOT_FOUND", "SHIPMENT_LIMIT_REACHED", "SHIPMENT_TOO_LARGE", "ORDER_FULFILMENT_EXTERNAL", "SHIPMENT_FAILED", "ADMIN_REQUIRED", "IDEMPOTENCY_KEY_REQUIRED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_LOCK_CONTENTION", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENT_RESPONSE_NOT_CACHED", "ORDER_CANCELLATION_NOT_PROTECTED", "ORDER_CANCELLATION_COMMITTED", "ORDER_CANCELLATION_LOCKED", "ORDER_CANCELLATION_TOO_LARGE", "ORDER_CANCELLATION_FAILED", "SALE_LEDGER_RETRACTION_REFUSED", "SALE_LEDGER_ROW_NOT_OWNED", "PRODUCT_NOT_FOUND", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "DEPOSIT_SOURCE_NOT_ALLOWED", "DEPOSIT_CURRENCY_MISMATCH", "DEPOSIT_EXCEEDS_TOTAL", "DEPOSIT_FREEZE_REQUIRES_INVOICE", "DEPOSIT_FREEZE_INVOICE_PENDING", "DEPOSIT_CHARACTERIZATION_CONFLICT", "DEPOSIT_FREEZE_INVOICE_NOT_QUALIFYING", "DEPOSIT_INVOICED_ORDER_MUST_FREEZE", "DEPOSIT_FROZEN_ORDER_MUST_FREEZE", "DEPOSIT_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "TILL_TENDER_REQUIRES_DEPOSIT", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "ORDER_PRICE_FROZEN", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "UNIT_QUANTITY_UNREPRESENTABLE", "KIT_RECIPE_CHANGED", "CART_PROMOTION_UNAVAILABLE", "ORDER_HAS_KIT_LINES", "ORDER_HAS_FREIGHT_LINE", "ORDER_TARGET_REQUIRED", "ORDER_SOURCE_CONFLICT", "ORDER_CUSTOMER_REQUIRED", "BASKET_EMPTY", "BASKET_CHANGED_DURING_CHECKOUT", "CART_VERSION_CREATE_ONLY", "CART_VERSION_REQUIRES_CART_ID", "CART_REVISION_STALE", "CART_CUSTOMER_MISMATCH", "COUNTER_SALE_CREATE_ONLY", "SOLD_AT_CREATE_ONLY", "SOLD_AT_IN_FUTURE", "ORDER_TENDER_CREATE_ONLY", "CREDIT_OVERRIDE_CREATE_ONLY", "ON_ACCOUNT_CREATE_ONLY", "ON_ACCOUNT_WITH_TENDERS", "TENDERS_REQUIRE_COUNTER_SALE", "LINES_REQUIRE_COUNTER_SALE", "PRODUCT_COST_UNKNOWN", "PRICE_CHANGE_DISABLED", "LINE_DISCOUNT_EXCEEDS_MAX", "CUSTOMER_DISABLED", "SHIFT_NOT_AVAILABLE", "SOLD_AT_OUTSIDE_SHIFT", "ORDER_CURRENCY_NOT_SUBSCRIBED", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "PAYMENT_METHOD_UNAVAILABLE", "CART_PRICES_CHANGED", "ORDER_ID_COLLISION", "DELIVERY_METHOD_NOT_FOUND", "ORDER_BELOW_MINIMUM_PURCHASE", "ORDER_INVALID_CART", "CART_CHANGED_SINCE_CONFIRM", "EMAIL_VERIFICATION_REQUIRED", "ACCOUNT_DISABLED", "CUSTOMER_ACCESS_PENDING", "CUSTOMER_ACCESS_REJECTED", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "ORDER_DISCOUNT_AFTER_INVOICE", "ORDER_DISCOUNT_ON_SERVICE_ORDER", "ORDER_DISCOUNT_ON_MARKETPLACE_ORDER", "ORDER_INVOICE_METHOD_OUTSTANDING_FACTURA", "ORDER_SERVICE_PERIOD_AFTER_INVOICE", "ORDER_ATTEMPT_COMMITTED", "ORDER_ATTEMPT_ABANDONED", "ORDER_ATTEMPT_KEY_EXPIRED", "ORDER_ATTEMPT_KEY_SCOPE_MISMATCH", "ORDER_COMPLETION_ATTEMPT_COMMITTED", "ORDER_COMPLETION_ATTEMPT_ABANDONED"];
|
|
2946
2974
|
export type OrderErrorCode = (typeof ORDER_ERROR_CODES)[number];
|
|
2947
2975
|
export {};
|
package/dist/order.js
CHANGED
|
@@ -103,7 +103,8 @@ const positiveUnits = (value) => (typeof value === 'number' && value > 0 ? value
|
|
|
103
103
|
* The ONE reader of the per-line fulfilment ledger (`OrderLine.fulfilledQuantity`).
|
|
104
104
|
*
|
|
105
105
|
* - A missing `fulfilledQuantity` counts as 0; lines with no or zero `quantity`
|
|
106
|
-
* are ignored on both sides of the ratio
|
|
106
|
+
* are ignored on both sides of the ratio, and so is a freight line
|
|
107
|
+
* (`lineKind: 'freight'` with no `productId`), which is never shipped.
|
|
107
108
|
* - `deliveredAt > 0` with no `shipments` is `complete` — a whole-order delivery
|
|
108
109
|
* that never went through the shipment ledger.
|
|
109
110
|
* - A `disabled` or cancelled row is `none`, whatever timestamps it carries: a
|
|
@@ -114,6 +115,12 @@ export const orderFulfilmentProgress = (order) => {
|
|
|
114
115
|
let orderedUnits = 0;
|
|
115
116
|
let fulfilledUnits = 0;
|
|
116
117
|
for (const line of order.items ?? []) {
|
|
118
|
+
// A freight line is a charge, never handed over, so it would hold a
|
|
119
|
+
// fully shipped order at `partial` forever. The same test as
|
|
120
|
+
// `isFreightLine` (`stacks/helpers/discountCalculations.ts`), inlined
|
|
121
|
+
// because contracts import nothing from `stacks/`.
|
|
122
|
+
if (line?.lineKind === 'freight' && line.productId === undefined)
|
|
123
|
+
continue;
|
|
117
124
|
const ordered = positiveUnits(line?.quantity);
|
|
118
125
|
if (ordered === 0)
|
|
119
126
|
continue;
|
|
@@ -272,6 +279,9 @@ export const orderFulfilmentProgress = (order) => {
|
|
|
272
279
|
* is refused after it, like every other refusal at commit.
|
|
273
280
|
* - `ORDER_HAS_KIT_LINES` · 409 — `mode: 'edit'` on an order holding a kit line
|
|
274
281
|
* (`CartLine.kit`). Cancel or return the order instead. Nothing was written.
|
|
282
|
+
* - `ORDER_HAS_FREIGHT_LINE` · 409 — `mode: 'edit'` on an order holding a
|
|
283
|
+
* freight line (`OrderLine.lineKind: 'freight'`). Cancel or return the order
|
|
284
|
+
* instead. Nothing was written.
|
|
275
285
|
* - `CART_PROMOTION_UNAVAILABLE` · 409 — the insert leg converting a STORED
|
|
276
286
|
* ticket whose promotion ended, was paused, deleted, has not started or is
|
|
277
287
|
* no longer cart-applicable; the `PromotionRefusal` rides `data.reason`. No
|
|
@@ -604,6 +614,8 @@ export const ORDER_ERROR_CODES = [
|
|
|
604
614
|
'CART_PROMOTION_UNAVAILABLE',
|
|
605
615
|
// `mode: 'edit'` on an order holding a kit line; cancel or return it instead.
|
|
606
616
|
'ORDER_HAS_KIT_LINES',
|
|
617
|
+
// `mode: 'edit'` on an order holding a freight line; cancel or return it instead.
|
|
618
|
+
'ORDER_HAS_FREIGHT_LINE',
|
|
607
619
|
// Create-leg refusals about the sale's source, already answered on the wire.
|
|
608
620
|
'ORDER_TARGET_REQUIRED',
|
|
609
621
|
'ORDER_SOURCE_CONFLICT',
|
package/dist/store.d.ts
CHANGED
|
@@ -1599,6 +1599,29 @@ declare global {
|
|
|
1599
1599
|
/** ISO date; stops applying on or after. Omitted => open-ended. */
|
|
1600
1600
|
expiresAt?: string;
|
|
1601
1601
|
}
|
|
1602
|
+
/**
|
|
1603
|
+
* An AFIP Iva Id — one of `IVA_TYPES` (`services/fiscalCatalogs.ts`): 3 (0 %),
|
|
1604
|
+
* 9 (2,5 %), 8 (5 %), 4 (10,5 %), 5 (21 %), 6 (27 %). `number`, like every
|
|
1605
|
+
* `ivaType` in this contract, so a line's stored rate and a configured one
|
|
1606
|
+
* compare without a cast; the catalog, not this type, is the authority.
|
|
1607
|
+
* ⚠️ Not every write path validates against it: `PATCH /store` does
|
|
1608
|
+
* (`afipPatchSchema`), but `POST /store` and `POST /tenants` take `afip`
|
|
1609
|
+
* unvalidated, so a reader falls back on an out-of-catalog value
|
|
1610
|
+
* (`resolveFreightFiscal`) rather than trusting the row.
|
|
1611
|
+
*/
|
|
1612
|
+
type IvaTypeId = number;
|
|
1613
|
+
/**
|
|
1614
|
+
* How the store's freight line (`OrderLine.lineKind: 'freight'`) is declared
|
|
1615
|
+
* to ARCA. Configuration the store's accountant decides, not a fact the code
|
|
1616
|
+
* can derive: whether delivery is a separate service or an accessory of the
|
|
1617
|
+
* sale, and at which rate, depends on how the store sells.
|
|
1618
|
+
*/
|
|
1619
|
+
interface AfipFreightFiscal {
|
|
1620
|
+
/** The alícuota stamped on the freight line, and so declared in `Iva[]`. */
|
|
1621
|
+
ivaType: IvaTypeId;
|
|
1622
|
+
/** Whether the freight line counts as goods or as a service for `Concepto`. */
|
|
1623
|
+
concepto: 'goods' | 'services';
|
|
1624
|
+
}
|
|
1602
1625
|
interface Afip {
|
|
1603
1626
|
production: boolean;
|
|
1604
1627
|
address?: string;
|
|
@@ -1669,6 +1692,14 @@ declare global {
|
|
|
1669
1692
|
fceEnabled?: boolean;
|
|
1670
1693
|
wscdcEnabled?: boolean;
|
|
1671
1694
|
fceReceivedCheckpoint?: number;
|
|
1695
|
+
/**
|
|
1696
|
+
* The freight line's IVA rate and Concepto. Absent means the platform
|
|
1697
|
+
* default, `ivaType` 5 (21 %) and `concepto` `'goods'`
|
|
1698
|
+
* (`DEFAULT_FREIGHT_FISCAL`); read it through `resolveFreightFiscal`, never
|
|
1699
|
+
* directly. ADMIN-tier on `PATCH /store` (`PRIVILEGED_AFIP_FIELDS`); `null`
|
|
1700
|
+
* clears it back to the default.
|
|
1701
|
+
*/
|
|
1702
|
+
freight?: AfipFreightFiscal;
|
|
1672
1703
|
}
|
|
1673
1704
|
/**
|
|
1674
1705
|
* Write shape for the `afip` key of `PATCH /store`'s body. The wire accepts an
|
|
@@ -1683,6 +1714,7 @@ declare global {
|
|
|
1683
1714
|
iibbTransparency?: Afip['iibbTransparency'] | null;
|
|
1684
1715
|
iibbJurisdictions?: IibbJurisdictionConfig[] | null;
|
|
1685
1716
|
actividades?: number[] | null;
|
|
1717
|
+
freight?: AfipFreightFiscal | null;
|
|
1686
1718
|
}
|
|
1687
1719
|
/**
|
|
1688
1720
|
* Write shape for the `config` key of `PATCH /store`'s body. Two things the
|
|
@@ -13,6 +13,9 @@
|
|
|
13
13
|
* - keys whose storefront value is not a plain `{name}`-token sentence (it
|
|
14
14
|
* branches, computes, or is not a string), which a shop string cannot
|
|
15
15
|
* express.
|
|
16
|
+
* Route paths (the former `NAVIGATE_*` keys) are not copy at all: they live in
|
|
17
|
+
* the storefront's own config, and the api refuses and drops a `NAVIGATE_*`
|
|
18
|
+
* literal on every storefront surface.
|
|
16
19
|
* An editor that lists any of those offers an edit the server refuses.
|
|
17
20
|
*
|
|
18
21
|
* Interpolated values use `{name}` tokens named after the storefront's own
|
|
@@ -21,16 +24,9 @@
|
|
|
21
24
|
export declare const STOREFRONT_WEB_LITERAL_KEYS: readonly string[];
|
|
22
25
|
/** Whether a shop may override `key` — membership in {@link STOREFRONT_WEB_LITERAL_KEYS}. */
|
|
23
26
|
export declare const isStorefrontLiteralKey: (key: string) => boolean;
|
|
24
|
-
/**
|
|
25
|
-
* Whether `value` may be stored, published or served for `key`. A `NAVIGATE_*` key is
|
|
26
|
-
* rendered as a link, so it must be a same-origin path — otherwise an override could
|
|
27
|
-
* send a shop's customers to an off-site look-alike login page. Every other key is
|
|
28
|
-
* unconstrained here (key membership, well-formedness and length are checked apart).
|
|
29
|
-
*/
|
|
30
|
-
export declare const isAllowedStorefrontLiteralValue: (key: string, value: string) => boolean;
|
|
31
27
|
/**
|
|
32
28
|
* Whether a shop's stored `value` for `key` is one a save keeps, a read serves and the editor
|
|
33
|
-
* baseline adopts: a shop-overridable key
|
|
34
|
-
* {@link STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS} code points
|
|
29
|
+
* baseline adopts: a shop-overridable key and a well-formed string within
|
|
30
|
+
* {@link STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS} code points.
|
|
35
31
|
*/
|
|
36
32
|
export declare const isAdoptableStorefrontLiteral: (key: string, value: unknown) => value is string;
|
|
@@ -14,6 +14,9 @@ import { STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS } from "./storefrontDesignReg
|
|
|
14
14
|
* - keys whose storefront value is not a plain `{name}`-token sentence (it
|
|
15
15
|
* branches, computes, or is not a string), which a shop string cannot
|
|
16
16
|
* express.
|
|
17
|
+
* Route paths (the former `NAVIGATE_*` keys) are not copy at all: they live in
|
|
18
|
+
* the storefront's own config, and the api refuses and drops a `NAVIGATE_*`
|
|
19
|
+
* literal on every storefront surface.
|
|
17
20
|
* An editor that lists any of those offers an edit the server refuses.
|
|
18
21
|
*
|
|
19
22
|
* Interpolated values use `{name}` tokens named after the storefront's own
|
|
@@ -489,6 +492,8 @@ export const STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
489
492
|
'DATA_RIGHTS_COLLECTION_NOTES',
|
|
490
493
|
'DATA_RIGHTS_COLLECTION_ORDERS',
|
|
491
494
|
'DATA_RIGHTS_COLLECTION_PAYMENTS',
|
|
495
|
+
'DATA_RIGHTS_COLLECTION_RECENT_PURCHASES',
|
|
496
|
+
'DATA_RIGHTS_COLLECTION_WHOLESALE_REQUESTS',
|
|
492
497
|
'DATA_RIGHTS_DIALOG_ACK',
|
|
493
498
|
'DATA_RIGHTS_DIALOG_CONFIRM',
|
|
494
499
|
'DATA_RIGHTS_DIALOG_FISCAL',
|
|
@@ -812,27 +817,6 @@ export const STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
812
817
|
'MOBILE_BUTTONS_FAVORITES',
|
|
813
818
|
'MOBILE_BUTTONS_INVOICES',
|
|
814
819
|
'MOBILE_BUTTONS_ORDERS',
|
|
815
|
-
'NAVIGATE_APPOINTMENTS',
|
|
816
|
-
'NAVIGATE_BASKET',
|
|
817
|
-
'NAVIGATE_BRANDS',
|
|
818
|
-
'NAVIGATE_CATEGORIES',
|
|
819
|
-
'NAVIGATE_CHECKOUT',
|
|
820
|
-
'NAVIGATE_FAVORITES',
|
|
821
|
-
'NAVIGATE_HOME',
|
|
822
|
-
'NAVIGATE_INCOMES',
|
|
823
|
-
'NAVIGATE_INVOICES',
|
|
824
|
-
'NAVIGATE_LOGIN',
|
|
825
|
-
'NAVIGATE_LOGOUT',
|
|
826
|
-
'NAVIGATE_MAINTENANCE',
|
|
827
|
-
'NAVIGATE_NEW_ARRIVALS',
|
|
828
|
-
'NAVIGATE_NOTIFICATIONS',
|
|
829
|
-
'NAVIGATE_ORDERS',
|
|
830
|
-
'NAVIGATE_PAYMENTS',
|
|
831
|
-
'NAVIGATE_PROFILE',
|
|
832
|
-
'NAVIGATE_RECOVER',
|
|
833
|
-
'NAVIGATE_REGISTRATION',
|
|
834
|
-
'NAVIGATE_SALE',
|
|
835
|
-
'NAVIGATE_SESSIONS',
|
|
836
820
|
'NETWORK_OFFLINE',
|
|
837
821
|
'NETWORK_REQUEST_FAILED',
|
|
838
822
|
'NETWORK_TIMEOUT',
|
|
@@ -1075,6 +1059,7 @@ export const STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
1075
1059
|
'PREVIEW_LOADING',
|
|
1076
1060
|
'PREVIEW_READ_FAILED',
|
|
1077
1061
|
'PREVIEW_READ_ONLY',
|
|
1062
|
+
'PREVIEW_RECENTLY_BOUGHT',
|
|
1078
1063
|
'PREVIEW_RESTART',
|
|
1079
1064
|
'PREVIEW_RETRY',
|
|
1080
1065
|
'PREVIEW_TITLE',
|
|
@@ -1343,6 +1328,7 @@ export const STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
1343
1328
|
'STOREFRONT_FOOTER_NAV_ARIA',
|
|
1344
1329
|
'STOREFRONT_MERCHANT_NAV_ARIA',
|
|
1345
1330
|
'STOREFRONT_NAV_GROUP_FALLBACK',
|
|
1331
|
+
'STOREFRONT_PRODUCTS_REFRESH_FAILED',
|
|
1346
1332
|
'STOREFRONT_SEARCH',
|
|
1347
1333
|
'STOREFRONT_SOCIAL_FACEBOOK',
|
|
1348
1334
|
'STOREFRONT_SOCIAL_INSTAGRAM',
|
|
@@ -1370,32 +1356,12 @@ export const STOREFRONT_WEB_LITERAL_KEYS = Object.freeze([
|
|
|
1370
1356
|
const STOREFRONT_WEB_LITERAL_KEY_SET = new Set(STOREFRONT_WEB_LITERAL_KEYS);
|
|
1371
1357
|
/** Whether a shop may override `key` — membership in {@link STOREFRONT_WEB_LITERAL_KEYS}. */
|
|
1372
1358
|
export const isStorefrontLiteralKey = (key) => STOREFRONT_WEB_LITERAL_KEY_SET.has(key);
|
|
1373
|
-
/** Keys whose value is a storefront route the storefront renders as a link target. */
|
|
1374
|
-
const STOREFRONT_NAVIGATE_LITERAL_PREFIX = 'NAVIGATE_';
|
|
1375
|
-
/**
|
|
1376
|
-
* A same-origin path: a leading `/`, a second character that is neither `/` nor `\`
|
|
1377
|
-
* (`//host` and `/\host` are protocol-relative to a browser), and no whitespace,
|
|
1378
|
-
* backslash, control character (`\p{Cc}`) or invisible format character (`\p{Cf}`: every
|
|
1379
|
-
* bidi mark including U+061C, zero-width characters, the soft hyphen, tag characters)
|
|
1380
|
-
* anywhere. Browsers strip tab and newline before parsing, so `/\t/host` becomes `//host`;
|
|
1381
|
-
* invisible and directional characters can also disguise the link target. A scheme
|
|
1382
|
-
* cannot start with `/`.
|
|
1383
|
-
*/
|
|
1384
|
-
const STOREFRONT_SAME_ORIGIN_PATH_RE = /^\/(?![/\\])[^\s\\\p{Cc}\p{Cf}]*$/u;
|
|
1385
|
-
/**
|
|
1386
|
-
* Whether `value` may be stored, published or served for `key`. A `NAVIGATE_*` key is
|
|
1387
|
-
* rendered as a link, so it must be a same-origin path — otherwise an override could
|
|
1388
|
-
* send a shop's customers to an off-site look-alike login page. Every other key is
|
|
1389
|
-
* unconstrained here (key membership, well-formedness and length are checked apart).
|
|
1390
|
-
*/
|
|
1391
|
-
export const isAllowedStorefrontLiteralValue = (key, value) => !key.startsWith(STOREFRONT_NAVIGATE_LITERAL_PREFIX) || STOREFRONT_SAME_ORIGIN_PATH_RE.test(value);
|
|
1392
1359
|
/**
|
|
1393
1360
|
* Whether a shop's stored `value` for `key` is one a save keeps, a read serves and the editor
|
|
1394
|
-
* baseline adopts: a shop-overridable key
|
|
1395
|
-
* {@link STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS} code points
|
|
1361
|
+
* baseline adopts: a shop-overridable key and a well-formed string within
|
|
1362
|
+
* {@link STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS} code points.
|
|
1396
1363
|
*/
|
|
1397
1364
|
export const isAdoptableStorefrontLiteral = (key, value) => isStorefrontLiteralKey(key) &&
|
|
1398
1365
|
typeof value === 'string' &&
|
|
1399
1366
|
value.isWellFormed() &&
|
|
1400
|
-
Array.from(value).length <= STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS
|
|
1401
|
-
isAllowedStorefrontLiteralValue(key, value);
|
|
1367
|
+
Array.from(value).length <= STOREFRONT_DESIGN_LITERAL_MAX_CODE_POINTS;
|
|
@@ -20,6 +20,28 @@ export declare const WHOLESALE_REQUEST_MESSAGE_MAX = 1000;
|
|
|
20
20
|
export declare const WHOLESALE_REQUEST_PHONE_MAX = 30;
|
|
21
21
|
/** Character ceiling on the operator's decline reason, counted after trimming. */
|
|
22
22
|
export declare const WHOLESALE_REQUEST_REASON_MAX = 500;
|
|
23
|
+
/**
|
|
24
|
+
* Every `error` code the wholesale-request flow answers on its own behalf:
|
|
25
|
+
* - web `POST /user { mode: 'wholesale-request' }` (`stacks/web/lambdas/user/_wholesaleRequest.ts`):
|
|
26
|
+
* `WHOLESALE_REQUESTS_DISABLED`, `CUSTOMER_NOT_FOUND`, `CUSTOMER_ANONYMIZED`, `USER_NOT_ENABLED`,
|
|
27
|
+
* `CUSTOMER_ALREADY_WHOLESALE`, `WHOLESALE_REQUEST_CONTENDED`, `WHOLESALE_REQUEST_PENDING`;
|
|
28
|
+
* - app `GET /customers?mode=wholesale-requests` and `POST /customers { mode: 'wholesale-decision' }`
|
|
29
|
+
* (`stacks/lambdas/customers/_wholesaleRequests.ts`): `ROLE_FORBIDDEN`, `ADMIN_REQUIRED`,
|
|
30
|
+
* `INVALID_CURSOR`, `WHOLESALE_REQUEST_NOT_PENDING`, `WHOLESALE_DECISION_CONTENDED`,
|
|
31
|
+
* `CUSTOMER_NOT_FOUND`, `CUSTOMER_ANONYMIZED`, `CUSTOMER_MERGED`, `PRICE_LIST_NOT_FOUND`,
|
|
32
|
+
* `PRICE_LIST_NOT_WHOLESALE`, `WHOLESALE_REQUEST_NOT_FOUND`;
|
|
33
|
+
* - the opt-in refusal both configuration writers answer when `ecommerce.config.wholesaleRequests`
|
|
34
|
+
* turns on with no wholesale-class list: `WHOLESALE_LIST_REQUIRED` (`409`). It is also in
|
|
35
|
+
* `STORE_PATCH_ERROR_CODES`, on purpose: a wholesale client handles it without reading that tuple.
|
|
36
|
+
*
|
|
37
|
+
* The rule: a code is listed when a wholesale handler writes it as its own literal, and each of
|
|
38
|
+
* those literals is typed `satisfies WholesaleRequestErrorCode`, so one this list misses fails
|
|
39
|
+
* typecheck. A code those routes forward from a shared helper is not listed, though a wholesale
|
|
40
|
+
* route can answer it: the customer-access refusals (`refuseCustomerAccess`), `VALIDATION_FAILED`
|
|
41
|
+
* (`validateRequest`), the handler wrapper's own codes and the authorizer's.
|
|
42
|
+
*/
|
|
43
|
+
export declare const WHOLESALE_REQUEST_ERROR_CODES: readonly ["WHOLESALE_REQUESTS_DISABLED", "CUSTOMER_NOT_FOUND", "CUSTOMER_ANONYMIZED", "USER_NOT_ENABLED", "CUSTOMER_ALREADY_WHOLESALE", "WHOLESALE_REQUEST_CONTENDED", "WHOLESALE_REQUEST_PENDING", "ROLE_FORBIDDEN", "ADMIN_REQUIRED", "INVALID_CURSOR", "WHOLESALE_REQUEST_NOT_PENDING", "WHOLESALE_DECISION_CONTENDED", "CUSTOMER_MERGED", "PRICE_LIST_NOT_FOUND", "PRICE_LIST_NOT_WHOLESALE", "WHOLESALE_REQUEST_NOT_FOUND", "WHOLESALE_LIST_REQUIRED"];
|
|
44
|
+
export type WholesaleRequestErrorCode = (typeof WHOLESALE_REQUEST_ERROR_CODES)[number];
|
|
23
45
|
declare global {
|
|
24
46
|
type WholesaleRequestState = (typeof WHOLESALE_REQUEST_STATES)[number];
|
|
25
47
|
/**
|
package/dist/wholesaleRequest.js
CHANGED
|
@@ -20,3 +20,42 @@ export const WHOLESALE_REQUEST_MESSAGE_MAX = 1000;
|
|
|
20
20
|
export const WHOLESALE_REQUEST_PHONE_MAX = 30;
|
|
21
21
|
/** Character ceiling on the operator's decline reason, counted after trimming. */
|
|
22
22
|
export const WHOLESALE_REQUEST_REASON_MAX = 500;
|
|
23
|
+
/**
|
|
24
|
+
* Every `error` code the wholesale-request flow answers on its own behalf:
|
|
25
|
+
* - web `POST /user { mode: 'wholesale-request' }` (`stacks/web/lambdas/user/_wholesaleRequest.ts`):
|
|
26
|
+
* `WHOLESALE_REQUESTS_DISABLED`, `CUSTOMER_NOT_FOUND`, `CUSTOMER_ANONYMIZED`, `USER_NOT_ENABLED`,
|
|
27
|
+
* `CUSTOMER_ALREADY_WHOLESALE`, `WHOLESALE_REQUEST_CONTENDED`, `WHOLESALE_REQUEST_PENDING`;
|
|
28
|
+
* - app `GET /customers?mode=wholesale-requests` and `POST /customers { mode: 'wholesale-decision' }`
|
|
29
|
+
* (`stacks/lambdas/customers/_wholesaleRequests.ts`): `ROLE_FORBIDDEN`, `ADMIN_REQUIRED`,
|
|
30
|
+
* `INVALID_CURSOR`, `WHOLESALE_REQUEST_NOT_PENDING`, `WHOLESALE_DECISION_CONTENDED`,
|
|
31
|
+
* `CUSTOMER_NOT_FOUND`, `CUSTOMER_ANONYMIZED`, `CUSTOMER_MERGED`, `PRICE_LIST_NOT_FOUND`,
|
|
32
|
+
* `PRICE_LIST_NOT_WHOLESALE`, `WHOLESALE_REQUEST_NOT_FOUND`;
|
|
33
|
+
* - the opt-in refusal both configuration writers answer when `ecommerce.config.wholesaleRequests`
|
|
34
|
+
* turns on with no wholesale-class list: `WHOLESALE_LIST_REQUIRED` (`409`). It is also in
|
|
35
|
+
* `STORE_PATCH_ERROR_CODES`, on purpose: a wholesale client handles it without reading that tuple.
|
|
36
|
+
*
|
|
37
|
+
* The rule: a code is listed when a wholesale handler writes it as its own literal, and each of
|
|
38
|
+
* those literals is typed `satisfies WholesaleRequestErrorCode`, so one this list misses fails
|
|
39
|
+
* typecheck. A code those routes forward from a shared helper is not listed, though a wholesale
|
|
40
|
+
* route can answer it: the customer-access refusals (`refuseCustomerAccess`), `VALIDATION_FAILED`
|
|
41
|
+
* (`validateRequest`), the handler wrapper's own codes and the authorizer's.
|
|
42
|
+
*/
|
|
43
|
+
export const WHOLESALE_REQUEST_ERROR_CODES = [
|
|
44
|
+
'WHOLESALE_REQUESTS_DISABLED',
|
|
45
|
+
'CUSTOMER_NOT_FOUND',
|
|
46
|
+
'CUSTOMER_ANONYMIZED',
|
|
47
|
+
'USER_NOT_ENABLED',
|
|
48
|
+
'CUSTOMER_ALREADY_WHOLESALE',
|
|
49
|
+
'WHOLESALE_REQUEST_CONTENDED',
|
|
50
|
+
'WHOLESALE_REQUEST_PENDING',
|
|
51
|
+
'ROLE_FORBIDDEN',
|
|
52
|
+
'ADMIN_REQUIRED',
|
|
53
|
+
'INVALID_CURSOR',
|
|
54
|
+
'WHOLESALE_REQUEST_NOT_PENDING',
|
|
55
|
+
'WHOLESALE_DECISION_CONTENDED',
|
|
56
|
+
'CUSTOMER_MERGED',
|
|
57
|
+
'PRICE_LIST_NOT_FOUND',
|
|
58
|
+
'PRICE_LIST_NOT_WHOLESALE',
|
|
59
|
+
'WHOLESALE_REQUEST_NOT_FOUND',
|
|
60
|
+
'WHOLESALE_LIST_REQUIRED',
|
|
61
|
+
];
|