platform-types 1.10.851 → 1.10.853

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.
@@ -15,7 +15,11 @@
15
15
  //
16
16
  // Every existing reader of those fields keeps working unchanged. Forward-only:
17
17
  // a customer written before the address book has no address rows; the first
18
- // edit of their address (through `/customers/addresses`, `POST /customers`, the
19
- // storefront profile, or an order's `saveAsDefault`) creates the row and points
20
- // the default at it. Nothing sweeps.
18
+ // edit of their address (through `/customers/addresses`, the web `/addresses`,
19
+ // `POST /customers`, the storefront profile, or an order's `saveAsDefault`)
20
+ // creates the row and points the default at it. Nothing sweeps.
21
+ //
22
+ // Two surfaces: staff `/customers/addresses` (both kinds, uncapped) and the
23
+ // shopper's own web `/addresses` (the `delivery` kind only, at most
24
+ // `SHOPPER_DELIVERY_ADDRESS_CAP` = 20, plus an order's `saveAddress`).
21
25
  Object.defineProperty(exports, "__esModule", { value: true });
package/dist/cjs/index.js CHANGED
@@ -103,6 +103,7 @@ __exportStar(require("./rma.js"), exports);
103
103
  __exportStar(require("./roles.js"), exports);
104
104
  __exportStar(require("./sentry.js"), exports);
105
105
  __exportStar(require("./serviceOrder.js"), exports);
106
+ __exportStar(require("./serviceTracking.js"), exports);
106
107
  __exportStar(require("./serviceTemplate.js"), exports);
107
108
  __exportStar(require("./socket.js"), exports);
108
109
  __exportStar(require("./stock.js"), exports);
@@ -301,6 +301,11 @@ exports.SERVICE_ORDER_ERROR_CODES = [
301
301
  'WARRANTY_BELOW_LEGAL_MINIMUM',
302
302
  'TECHNICIAN_NOT_FOUND',
303
303
  'TECHNICIAN_NOT_ELIGIBLE',
304
+ // The customer tracking link (`mode: 'trackingLink'`) — see `SERVICE_TRACKING_OPERATOR_ERROR_CODES`
305
+ 'SERVICE_TRACKING_DISABLED',
306
+ 'SERVICE_TRACKING_NO_ADDRESS',
307
+ 'SERVICE_TRACKING_LINK_LAPSED',
308
+ 'ADMIN_REQUIRED',
304
309
  'CUSTODY_ILLEGAL_TRANSITION',
305
310
  'SERVICE_ORDER_BILLABLE_FROZEN',
306
311
  'SERVICE_ORDER_EDIT_CHANGED',
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ /**
3
+ * Customer service-order tracking — the page a customer opens from a link a
4
+ * shop sends (`/servicio/{handle}`), and the same view for a signed-in customer
5
+ * on their account.
6
+ *
7
+ * The HANDLE is 16 base62 characters (~95 bits), stored server-side and a
8
+ * bearer credential over exactly ONE service order of one store. It authorises
9
+ * the read (`GET /services/tracking?handle=`) and the current presupuesto PDF
10
+ * (`GET /services/tracking?handle=&mode=quote-pdf`), and nothing else. Every
11
+ * earlier link of an order dies when staff revoke it. A link stops reading
12
+ * `serviceTrackingLinkDaysAfterClose` days (platform global, default 90) after
13
+ * the order reached a terminal status.
14
+ *
15
+ * The gate is `ecommerce.config.serviceTracking` AND the `workshop` module on.
16
+ * With the gate off, staff cannot mint and the signed-in reads refuse, but a
17
+ * link minted earlier keeps reading (STORE_MODULES rule 4).
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.SERVICE_TRACKING_HANDLE_RE = exports.SERVICE_TRACKING_PATH_PREFIX = exports.SERVICE_TRACKING_LINK_ACTIONS = exports.SERVICE_TRACKING_OPERATOR_ERROR_CODES = exports.SERVICE_TRACKING_ACCOUNT_ERROR_CODES = exports.SERVICE_TRACKING_ERROR_CODES = void 0;
21
+ /**
22
+ * The refusals the PUBLIC tracking routes answer themselves.
23
+ *
24
+ * - SERVICE_TRACKING_TOKEN_INVALID (401): every reason a handle cannot be
25
+ * honoured — missing, malformed, unknown, revoked, past the lifetime,
26
+ * presented on another store's host or with no store host at all, or naming
27
+ * an order that is gone or disabled — with one identical body, so a handle is
28
+ * never an oracle.
29
+ * - SERVICE_QUOTE_NOT_FOUND (404, `mode=quote-pdf` only): the order has no
30
+ * current presupuesto a customer was sent.
31
+ */
32
+ exports.SERVICE_TRACKING_ERROR_CODES = ['SERVICE_TRACKING_TOKEN_INVALID', 'SERVICE_QUOTE_NOT_FOUND'];
33
+ /**
34
+ * The refusals of the signed-in reads (`GET /user?mode=service-orders` and
35
+ * `?mode=service-order&serviceOrderId=`).
36
+ *
37
+ * - SERVICE_TRACKING_DISABLED (403): the store's gate is off.
38
+ * - SERVICE_ORDER_NOT_FOUND (404): no such order, a disabled one, or one that
39
+ * belongs to another customer — one answer for all three.
40
+ */
41
+ exports.SERVICE_TRACKING_ACCOUNT_ERROR_CODES = ['SERVICE_TRACKING_DISABLED', 'SERVICE_ORDER_NOT_FOUND'];
42
+ /**
43
+ * The refusals of the staff `POST /services { mode: 'trackingLink' }`, beside
44
+ * the router's own (`ROLE_FORBIDDEN`, `VALIDATION_FAILED`, `SERVICE_ORDER_NOT_FOUND`).
45
+ *
46
+ * - SERVICE_TRACKING_DISABLED (403, mint only): the store's gate is off.
47
+ * - SERVICE_TRACKING_NO_ADDRESS (409, mint only): the store has no public
48
+ * storefront address to build the link on (no slug, or public links off).
49
+ * - SERVICE_TRACKING_LINK_LAPSED (409, mint only): the order closed more than
50
+ * `serviceTrackingLinkDaysAfterClose` days ago, so a link would not read.
51
+ * - ADMIN_REQUIRED (403, revoke only): revoking takes ADMIN, SUPERVISOR or MANAGER.
52
+ */
53
+ exports.SERVICE_TRACKING_OPERATOR_ERROR_CODES = [
54
+ 'SERVICE_TRACKING_DISABLED',
55
+ 'SERVICE_TRACKING_NO_ADDRESS',
56
+ 'SERVICE_TRACKING_LINK_LAPSED',
57
+ 'ADMIN_REQUIRED',
58
+ ];
59
+ /** `POST /services { mode: 'trackingLink' }` actions. */
60
+ exports.SERVICE_TRACKING_LINK_ACTIONS = ['mint', 'revoke'];
61
+ /** The storefront path a tracking link opens: `/servicio/{handle}`. */
62
+ exports.SERVICE_TRACKING_PATH_PREFIX = '/servicio/';
63
+ /** The handle's exact shape: 16 base62 characters. */
64
+ exports.SERVICE_TRACKING_HANDLE_RE = /^[0-9A-Za-z]{16}$/;
@@ -30,7 +30,8 @@ declare global {
30
30
  }
31
31
  /**
32
32
  * `GET /customers/addresses?customerId=` — one page, ascending by
33
- * `addressId` (oldest first).
33
+ * `addressId` (oldest first). Also web `GET /addresses`, where it holds the
34
+ * caller's own `delivery` addresses only.
34
35
  */
35
36
  interface CustomerAddressPage {
36
37
  items: CustomerAddress[];
@@ -41,8 +42,10 @@ declare global {
41
42
  }
42
43
  /**
43
44
  * `data` of the `customerAddress` socket frame. OPERATOR audience only — the
44
- * customer's own socket is NOT addressed (staff only, for now: no storefront
45
- * address-book surface consumes it).
45
+ * customer's own socket is NOT addressed, also when the customer made the
46
+ * change through web `/addresses` (the storefront reads its own write from
47
+ * the REST answer). A shopper's write sends exactly the frame a staff write
48
+ * does.
46
49
  *
47
50
  * `address` is the whole row on the admin tier for `created` / `updated`.
48
51
  * It is absent on a `deleted` change, and on the rare `updated` frame of a
@@ -97,9 +100,48 @@ declare global {
97
100
  updatedAt: number;
98
101
  }
99
102
  /**
100
- * Every DOMAIN refusal on `/customers/addresses`, one bare code each (the
101
- * generic `VALIDATION_FAILED`, `CAPABILITY_REQUIRED` and `INVALID_CURSOR`
102
- * are not listed). None of them writes.
103
+ * Web `POST /addresses` body — the shopper's own new `delivery` address.
104
+ * There is no `kind` (a sent one is ignored: the shopper surface books
105
+ * `delivery` only) and no `customerId` (the session names the customer).
106
+ * `address` is required; every text field is trimmed and at most 200
107
+ * characters.
108
+ */
109
+ interface ShopperAddressCreateRequest {
110
+ label?: string;
111
+ fullName?: string;
112
+ phone?: string;
113
+ address: string;
114
+ city?: string;
115
+ province?: string;
116
+ postalCode?: string;
117
+ /** Make it the delivery default — `Customer.deliveryAddress` follows in the same write. */
118
+ makeDefault?: boolean;
119
+ }
120
+ /**
121
+ * Web `PUT /addresses` body: the address to edit plus ONLY the fields that
122
+ * changed (the storefront sends a dirty-field diff), and/or `makeDefault:
123
+ * true`. At least one of the two. A billing `addressId`, or another
124
+ * customer's, is `404 CUSTOMER_ADDRESS_NOT_FOUND`.
125
+ */
126
+ interface ShopperAddressUpdateRequest extends Partial<Omit<ShopperAddressCreateRequest, 'makeDefault'>> {
127
+ addressId: string;
128
+ /** A default is replaced, never cleared, so only `true` is accepted. */
129
+ makeDefault?: true;
130
+ }
131
+ /**
132
+ * Web `POST` / `PUT /addresses` → `{ data, defaultAddressId }`: the address
133
+ * as written, and the delivery default AFTER the write — a create that
134
+ * adopted the customer's legacy `deliveryAddress` leaves THAT one the
135
+ * default. Absent when the customer has no delivery default.
136
+ */
137
+ interface ShopperAddressWriteResult {
138
+ data: CustomerAddress;
139
+ defaultAddressId?: string;
140
+ }
141
+ /**
142
+ * Every DOMAIN refusal on `/customers/addresses` and the web `/addresses`,
143
+ * one bare code each (the generic `VALIDATION_FAILED`, `CAPABILITY_REQUIRED`
144
+ * and `INVALID_CURSOR` are not listed). None of them writes.
103
145
  *
104
146
  * - `CUSTOMER_ADDRESS_CUSTOMER_NOT_FOUND` (404) — not a customer of the
105
147
  * caller's store; covers «no such id», so the route is no cross-tenant
@@ -108,13 +150,20 @@ declare global {
108
150
  * art. 16; enforced atomically with the write.
109
151
  * - `CUSTOMER_ADDRESS_CUSTOMER_MERGED` (409) — folded into another customer
110
152
  * (`mergedInto`); write on the survivor.
111
- * - `CUSTOMER_ADDRESS_NOT_FOUND` (404) — no such address for that customer.
153
+ * - `CUSTOMER_ADDRESS_NOT_FOUND` (404) — no such address for that customer;
154
+ * on the web `/addresses`, also a `billing` address.
112
155
  * - `CUSTOMER_ADDRESS_IS_DEFAULT` (409) — the address is its kind's default;
113
156
  * make another address the default first. The default is what
114
157
  * `Customer.address` / `deliveryAddress` mirror, so it is never deleted
115
- * out from under them.
158
+ * out from under them. One exception, web `/addresses` only: the
159
+ * shopper's ONLY delivery address may be deleted, which unmarks the
160
+ * default and removes `Customer.deliveryAddress` in the same write.
161
+ * - `CUSTOMER_ADDRESS_LIMIT_REACHED` (409) — web `/addresses` only: the
162
+ * shopper already holds 20 delivery addresses (a book too large to count
163
+ * counts as full). Delete one first. Staff routes are uncapped.
116
164
  * - `CUSTOMER_ADDRESS_WRITE_CONTENDED` (503) — the customer's default or the
117
- * address changed under every bounded retry; retry is safe. ALSO answered
165
+ * address changed under every bounded retry, on either surface; retry is
166
+ * safe. ALSO answered
118
167
  * by `POST /customers` and the storefront `POST /user` when an edit of
119
168
  * the address loses to a rival that moved the default or its copy — those
120
169
  * refuse on the FIRST failure, with no retry of their own. The storefront
@@ -126,6 +175,6 @@ declare global {
126
175
  * `409 CUSTOMER_ANONYMIZED` (see `Customer.anonymizedAt`) and `409
127
176
  * CUSTOMER_MERGE_IN_PROGRESS` (merged or mid-merge after their read).
128
177
  */
129
- type CustomerAddressErrorCode = 'CUSTOMER_ADDRESS_CUSTOMER_NOT_FOUND' | 'CUSTOMER_ADDRESS_CUSTOMER_ANONYMIZED' | 'CUSTOMER_ADDRESS_CUSTOMER_MERGED' | 'CUSTOMER_ADDRESS_NOT_FOUND' | 'CUSTOMER_ADDRESS_IS_DEFAULT' | 'CUSTOMER_ADDRESS_WRITE_CONTENDED';
178
+ type CustomerAddressErrorCode = 'CUSTOMER_ADDRESS_CUSTOMER_NOT_FOUND' | 'CUSTOMER_ADDRESS_CUSTOMER_ANONYMIZED' | 'CUSTOMER_ADDRESS_CUSTOMER_MERGED' | 'CUSTOMER_ADDRESS_NOT_FOUND' | 'CUSTOMER_ADDRESS_IS_DEFAULT' | 'CUSTOMER_ADDRESS_LIMIT_REACHED' | 'CUSTOMER_ADDRESS_WRITE_CONTENDED';
130
179
  }
131
180
  export {};
@@ -14,7 +14,11 @@
14
14
  //
15
15
  // Every existing reader of those fields keeps working unchanged. Forward-only:
16
16
  // a customer written before the address book has no address rows; the first
17
- // edit of their address (through `/customers/addresses`, `POST /customers`, the
18
- // storefront profile, or an order's `saveAsDefault`) creates the row and points
19
- // the default at it. Nothing sweeps.
17
+ // edit of their address (through `/customers/addresses`, the web `/addresses`,
18
+ // `POST /customers`, the storefront profile, or an order's `saveAsDefault`)
19
+ // creates the row and points the default at it. Nothing sweeps.
20
+ //
21
+ // Two surfaces: staff `/customers/addresses` (both kinds, uncapped) and the
22
+ // shopper's own web `/addresses` (the `delivery` kind only, at most
23
+ // `SHOPPER_DELIVERY_ADDRESS_CAP` = 20, plus an order's `saveAddress`).
20
24
  export {};
package/dist/index.d.ts CHANGED
@@ -79,6 +79,7 @@ export * from './rma.ts';
79
79
  export * from './roles.ts';
80
80
  export * from './sentry.ts';
81
81
  export * from './serviceOrder.ts';
82
+ export * from './serviceTracking.ts';
82
83
  export * from './serviceTemplate.ts';
83
84
  export * from './socket.ts';
84
85
  export * from './stock.ts';
package/dist/index.js CHANGED
@@ -87,6 +87,7 @@ export * from "./rma.js";
87
87
  export * from "./roles.js";
88
88
  export * from "./sentry.js";
89
89
  export * from "./serviceOrder.js";
90
+ export * from "./serviceTracking.js";
90
91
  export * from "./serviceTemplate.js";
91
92
  export * from "./socket.js";
92
93
  export * from "./stock.js";
package/dist/order.d.ts CHANGED
@@ -2524,8 +2524,33 @@ declare global {
2524
2524
  province?: string;
2525
2525
  postalCode?: string;
2526
2526
  };
2527
- /** Persist `deliveryAddress` as the customer's default. Directive only, never stored. */
2527
+ /**
2528
+ * Persist `deliveryAddress` as the customer's default, OVERWRITING the
2529
+ * current delivery default's text in place (creating one only when there
2530
+ * is none). Directive only, never stored.
2531
+ *
2532
+ * DEPRECATED — use {@link saveAddress}, which appends a new address to
2533
+ * the customer's book instead of overwriting the default. `saveAsDefault`
2534
+ * keeps working, and retires one release after `saveAddress` is live.
2535
+ * `saveAsDefault: true` together with `saveAddress` is `400
2536
+ * VALIDATION_FAILED`; `false` asks for nothing and is accepted beside it.
2537
+ */
2528
2538
  saveAsDefault?: boolean;
2539
+ /**
2540
+ * Save `deliveryAddress` as a NEW delivery address in the customer's
2541
+ * book (web `/addresses`), AFTER the order commits — best effort: it
2542
+ * never refuses or fails the order. `makeDefault: true` also makes it the
2543
+ * delivery default (and `Customer.deliveryAddress`); otherwise the
2544
+ * current default, text included, is left as it was. Ignored without
2545
+ * `deliveryAddress`, or when that address carries no `address` line or a
2546
+ * field over 200 characters; skipped (and logged) when the customer
2547
+ * already holds 20 delivery addresses. Directive only, never stored.
2548
+ * Sending it together with `saveAsDefault: true` is `400
2549
+ * VALIDATION_FAILED`; an unknown inner key is stripped.
2550
+ */
2551
+ saveAddress?: {
2552
+ makeDefault?: boolean;
2553
+ };
2529
2554
  /**
2530
2555
  * The `cartId` of the cart the shopper confirmed (`CART` + 6-10 digits).
2531
2556
  * Omit it ONLY when that cart had none (a legacy cart). ⚠️ Compared
@@ -2560,11 +2585,12 @@ declare global {
2560
2585
  /**
2561
2586
  * Web `POST /orders/guest` body: a guest places an order from the server
2562
2587
  * guest cart its `X-Guest-Cart-Token` names. `StorefrontOrderCreateRequest`
2563
- * without `saveAsDefault` (a guest has no defaults), plus the guest's
2588
+ * without `saveAsDefault` / `saveAddress` (a guest has no defaults and no
2589
+ * address book), plus the guest's
2564
2590
  * `contact`, and with the cart pin REQUIRED: the guest cart always has an
2565
2591
  * id and a version.
2566
2592
  */
2567
- interface StorefrontGuestOrderCreateRequest extends Omit<StorefrontOrderCreateRequest, 'saveAsDefault' | 'expectedCartId' | 'expectedCartVersion'> {
2593
+ interface StorefrontGuestOrderCreateRequest extends Omit<StorefrontOrderCreateRequest, 'saveAsDefault' | 'saveAddress' | 'expectedCartId' | 'expectedCartVersion'> {
2568
2594
  contact: GuestContact;
2569
2595
  expectedCartId: string;
2570
2596
  expectedCartVersion: number;
@@ -1131,6 +1131,16 @@ declare global {
1131
1131
  * CURRENT `printJobId`.
1132
1132
  */
1133
1133
  printedAt?: number;
1134
+ /**
1135
+ * The customer tracking link (`/servicio/{handle}`), as staff see it.
1136
+ * Server-written only, by `POST /services { mode: 'trackingLink' }`:
1137
+ * `mintedAt` when a link is minted (a mint that finds a live link writes
1138
+ * nothing), `revokedAt` when every earlier link is revoked; a mint after a
1139
+ * revoke stamps a new `mintedAt` and removes `revokedAt`. Absent on an order
1140
+ * that never had a link. The handle and its fence generation are never on
1141
+ * this row and never reach staff after the mint answer.
1142
+ */
1143
+ trackingLink?: ServiceTrackingLinkState;
1134
1144
  disabled: boolean;
1135
1145
  }
1136
1146
  /**
@@ -1521,6 +1531,6 @@ export declare const MAX_SERVICE_PICTURES = 20;
1521
1531
  * check `GATING_ERROR_CODES` in addition. The deposit's opt-in idempotency
1522
1532
  * refusals are included here.
1523
1533
  */
1524
- export declare const SERVICE_ORDER_ERROR_CODES: readonly ["UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "ROLE_FORBIDDEN", "PARENT_FILTER_CONFLICT", "VALIDATION_FAILED", "INVALID_CURSOR", "INVALID_FROM_DATE", "INVALID_TO_DATE", "INVALID_DATE_RANGE", "REWORK_INDEX_UNAVAILABLE", "STORE_NOT_FOUND", "SERVICE_ORDER_NOT_FOUND", "PRINT_JOB_DOCUMENT_NOT_FOUND", "CUSTOMER_NOT_FOUND", "PARENT_SERVICE_ORDER_NOT_FOUND", "SERVICE_TEMPLATE_NOT_FOUND", "SERVICE_TYPE_REQUIRED", "INVALID_IMAGE_REFERENCE", "MISSING_STORE_CONTEXT", "WARRANTY_BELOW_LEGAL_MINIMUM", "TECHNICIAN_NOT_FOUND", "TECHNICIAN_NOT_ELIGIBLE", "CUSTODY_ILLEGAL_TRANSITION", "SERVICE_ORDER_BILLABLE_FROZEN", "SERVICE_ORDER_EDIT_CHANGED", "SERVICE_ORDER_DISABLED_STATE_UNCHANGED", "APPOINTMENT_NOT_FOUND", "APPOINTMENT_NOT_LINKABLE", "APPOINTMENT_NOT_OPEN", "APPOINTMENT_CUSTOMER_MISMATCH", "APPOINTMENT_VERSION_CONFLICT", "SERVICE_ORDER_TERMINAL", "SERVICE_ORDER_DISABLED", "SERVICE_ORDER_ILLEGAL_TRANSITION", "SERVICE_ORDER_STATUS_CHANGED", "SERVICE_ORDER_OUTCOME_REQUIRED", "SERVICE_ORDER_OUTCOME_NOT_ALLOWED", "SERVICE_ORDER_CUSTODY_NOT_RECEIVED", "SERVICE_ORDER_BILLABLE_NOT_AT_THIS_TRANSITION", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "SERVICE_ORDER_DEPOSIT_CHANGED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENCY_LOCK_CONTENTION", "SERVICE_DEPOSIT_CURRENCY_MISMATCH", "SERVICE_DEPOSIT_INVALID", "INVALID_AMOUNT", "DEFAULT_DRAWER_UNAVAILABLE", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "SERVICE_BILLING_PRODUCTS_UNAVAILABLE", "CATEGORY_NOT_FOUND", "CATEGORY_DISABLED", "CATEGORY_DISABLE_IN_PROGRESS", "SERVICE_BILLING_PRODUCT_IN_BASKET", "SERVICE_DELIVERY_BASKET_DECISION_REQUIRED", "SERVICE_DELIVERY_BASKET_CURRENCY_MISMATCH", "PRODUCT_NOT_AVAILABLE", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "FX_CONVERSION_UNAVAILABLE", "TRANSACT_ITEMS_LIMIT_EXCEEDED", "SERVICE_LINE_PRICE_TOO_LARGE", "SERVICE_PARTS_RESTORE_EXCEEDS_CONSUMED", "SERVICE_PARTS_RESTORE_EXCEEDS_AMOUNT", "SERVICE_PARTS_STOCK_INSUFFICIENT", "SERVICE_PARTS_PRODUCT_NOT_FOUND", "SERVICE_PARTS_LEDGER_FULL", "SERVICE_PARTS_TOO_MANY", "SERVICE_ORDER_PARTS_CHANGED", "SERVICE_QUOTE_NOT_FOUND", "SERVICE_QUOTE_NOT_OFFERABLE", "SERVICE_QUOTE_HOLDS_TOO_MANY", "SERVICE_QUOTE_SUPERSEDED", "SERVICE_QUOTE_ALREADY_RESOLVED", "SERVICE_QUOTE_LAPSED", "SERVICE_QUOTE_CHANNEL_RESERVED", "SERVICE_QUOTE_CHANNEL_NOT_APPLICABLE", "SERVICE_QUOTE_REASON_NOT_APPLICABLE", "SERVICE_ORDER_QUOTE_CHANGED", "SERVICE_ORDER_NOT_READY", "SERVICE_RENOTIFY_IMPERSONATED", "SERVICE_RENOTIFY_TOO_SOON", "SERVICE_RENOTIFY_CONFLICT", "SERVICE_RENOTIFY_NOT_RECORDED", "SERVICE_RENOTIFY_LEDGER_UNREADABLE", "SERVICE_RENOTIFY_NOT_DISPATCHED", "SERVICE_TIMER_ALREADY_RUNNING", "SERVICE_TIMER_NOT_RUNNING", "SERVICE_TIMER_STOP_CONFLICT", "TECHNICIAN_NOT_CLOCKED_IN", "SERVICE_ORDER_GONE", "SERVICE_WORKLOG_NOT_FOUND", "SERVICE_WORKLOG_NOT_REVERSIBLE", "SERVICE_WORKLOG_ALREADY_REVERSED", "SERVICE_ORDER_WORKLOG_CHANGED", "CART_PROMOTION_UNAVAILABLE", "COUPON_NOT_FOUND", "COUPON_NOT_ACTIVE", "COUPON_EXPIRED", "COUPON_EXHAUSTED", "COUPON_EXHAUSTED_AT_CHECKOUT", "COUPON_MIN_SUBTOTAL", "COUPON_REQUIRES_CUSTOMER", "COUPON_BUDGET_EXHAUSTED", "COUPON_CURRENCY_MISMATCH"];
1534
+ export declare const SERVICE_ORDER_ERROR_CODES: readonly ["UNIT_QUANTITY_NOT_WHOLE", "UNIT_REVISION_STALE", "ROLE_FORBIDDEN", "PARENT_FILTER_CONFLICT", "VALIDATION_FAILED", "INVALID_CURSOR", "INVALID_FROM_DATE", "INVALID_TO_DATE", "INVALID_DATE_RANGE", "REWORK_INDEX_UNAVAILABLE", "STORE_NOT_FOUND", "SERVICE_ORDER_NOT_FOUND", "PRINT_JOB_DOCUMENT_NOT_FOUND", "CUSTOMER_NOT_FOUND", "PARENT_SERVICE_ORDER_NOT_FOUND", "SERVICE_TEMPLATE_NOT_FOUND", "SERVICE_TYPE_REQUIRED", "INVALID_IMAGE_REFERENCE", "MISSING_STORE_CONTEXT", "WARRANTY_BELOW_LEGAL_MINIMUM", "TECHNICIAN_NOT_FOUND", "TECHNICIAN_NOT_ELIGIBLE", "SERVICE_TRACKING_DISABLED", "SERVICE_TRACKING_NO_ADDRESS", "SERVICE_TRACKING_LINK_LAPSED", "ADMIN_REQUIRED", "CUSTODY_ILLEGAL_TRANSITION", "SERVICE_ORDER_BILLABLE_FROZEN", "SERVICE_ORDER_EDIT_CHANGED", "SERVICE_ORDER_DISABLED_STATE_UNCHANGED", "APPOINTMENT_NOT_FOUND", "APPOINTMENT_NOT_LINKABLE", "APPOINTMENT_NOT_OPEN", "APPOINTMENT_CUSTOMER_MISMATCH", "APPOINTMENT_VERSION_CONFLICT", "SERVICE_ORDER_TERMINAL", "SERVICE_ORDER_DISABLED", "SERVICE_ORDER_ILLEGAL_TRANSITION", "SERVICE_ORDER_STATUS_CHANGED", "SERVICE_ORDER_OUTCOME_REQUIRED", "SERVICE_ORDER_OUTCOME_NOT_ALLOWED", "SERVICE_ORDER_CUSTODY_NOT_RECEIVED", "SERVICE_ORDER_BILLABLE_NOT_AT_THIS_TRANSITION", "PAYMENT_METHODS_NOT_CONFIGURED", "PAYMENT_METHOD_NOT_FOUND", "SERVICE_ORDER_DEPOSIT_CHANGED", "INVALID_IDEMPOTENCY_KEY", "IDEMPOTENCY_KEY_REUSE", "IDEMPOTENCY_IN_PROGRESS", "IDEMPOTENCY_KEY_FAILED", "IDEMPOTENCY_LOCK_CONTENTION", "SERVICE_DEPOSIT_CURRENCY_MISMATCH", "SERVICE_DEPOSIT_INVALID", "INVALID_AMOUNT", "DEFAULT_DRAWER_UNAVAILABLE", "CURRENCY_MISMATCH", "SHIFT_NOT_OPEN", "SERVICE_BILLING_PRODUCTS_UNAVAILABLE", "CATEGORY_NOT_FOUND", "CATEGORY_DISABLED", "CATEGORY_DISABLE_IN_PROGRESS", "SERVICE_BILLING_PRODUCT_IN_BASKET", "SERVICE_DELIVERY_BASKET_DECISION_REQUIRED", "SERVICE_DELIVERY_BASKET_CURRENCY_MISMATCH", "PRODUCT_NOT_AVAILABLE", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "FX_CONVERSION_UNAVAILABLE", "TRANSACT_ITEMS_LIMIT_EXCEEDED", "SERVICE_LINE_PRICE_TOO_LARGE", "SERVICE_PARTS_RESTORE_EXCEEDS_CONSUMED", "SERVICE_PARTS_RESTORE_EXCEEDS_AMOUNT", "SERVICE_PARTS_STOCK_INSUFFICIENT", "SERVICE_PARTS_PRODUCT_NOT_FOUND", "SERVICE_PARTS_LEDGER_FULL", "SERVICE_PARTS_TOO_MANY", "SERVICE_ORDER_PARTS_CHANGED", "SERVICE_QUOTE_NOT_FOUND", "SERVICE_QUOTE_NOT_OFFERABLE", "SERVICE_QUOTE_HOLDS_TOO_MANY", "SERVICE_QUOTE_SUPERSEDED", "SERVICE_QUOTE_ALREADY_RESOLVED", "SERVICE_QUOTE_LAPSED", "SERVICE_QUOTE_CHANNEL_RESERVED", "SERVICE_QUOTE_CHANNEL_NOT_APPLICABLE", "SERVICE_QUOTE_REASON_NOT_APPLICABLE", "SERVICE_ORDER_QUOTE_CHANGED", "SERVICE_ORDER_NOT_READY", "SERVICE_RENOTIFY_IMPERSONATED", "SERVICE_RENOTIFY_TOO_SOON", "SERVICE_RENOTIFY_CONFLICT", "SERVICE_RENOTIFY_NOT_RECORDED", "SERVICE_RENOTIFY_LEDGER_UNREADABLE", "SERVICE_RENOTIFY_NOT_DISPATCHED", "SERVICE_TIMER_ALREADY_RUNNING", "SERVICE_TIMER_NOT_RUNNING", "SERVICE_TIMER_STOP_CONFLICT", "TECHNICIAN_NOT_CLOCKED_IN", "SERVICE_ORDER_GONE", "SERVICE_WORKLOG_NOT_FOUND", "SERVICE_WORKLOG_NOT_REVERSIBLE", "SERVICE_WORKLOG_ALREADY_REVERSED", "SERVICE_ORDER_WORKLOG_CHANGED", "CART_PROMOTION_UNAVAILABLE", "COUPON_NOT_FOUND", "COUPON_NOT_ACTIVE", "COUPON_EXPIRED", "COUPON_EXHAUSTED", "COUPON_EXHAUSTED_AT_CHECKOUT", "COUPON_MIN_SUBTOTAL", "COUPON_REQUIRES_CUSTOMER", "COUPON_BUDGET_EXHAUSTED", "COUPON_CURRENCY_MISMATCH"];
1525
1535
  export type ServiceOrderErrorCode = (typeof SERVICE_ORDER_ERROR_CODES)[number];
1526
1536
  export {};
@@ -298,6 +298,11 @@ export const SERVICE_ORDER_ERROR_CODES = [
298
298
  'WARRANTY_BELOW_LEGAL_MINIMUM',
299
299
  'TECHNICIAN_NOT_FOUND',
300
300
  'TECHNICIAN_NOT_ELIGIBLE',
301
+ // The customer tracking link (`mode: 'trackingLink'`) — see `SERVICE_TRACKING_OPERATOR_ERROR_CODES`
302
+ 'SERVICE_TRACKING_DISABLED',
303
+ 'SERVICE_TRACKING_NO_ADDRESS',
304
+ 'SERVICE_TRACKING_LINK_LAPSED',
305
+ 'ADMIN_REQUIRED',
301
306
  'CUSTODY_ILLEGAL_TRANSITION',
302
307
  'SERVICE_ORDER_BILLABLE_FROZEN',
303
308
  'SERVICE_ORDER_EDIT_CHANGED',
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Customer service-order tracking — the page a customer opens from a link a
3
+ * shop sends (`/servicio/{handle}`), and the same view for a signed-in customer
4
+ * on their account.
5
+ *
6
+ * The HANDLE is 16 base62 characters (~95 bits), stored server-side and a
7
+ * bearer credential over exactly ONE service order of one store. It authorises
8
+ * the read (`GET /services/tracking?handle=`) and the current presupuesto PDF
9
+ * (`GET /services/tracking?handle=&mode=quote-pdf`), and nothing else. Every
10
+ * earlier link of an order dies when staff revoke it. A link stops reading
11
+ * `serviceTrackingLinkDaysAfterClose` days (platform global, default 90) after
12
+ * the order reached a terminal status.
13
+ *
14
+ * The gate is `ecommerce.config.serviceTracking` AND the `workshop` module on.
15
+ * With the gate off, staff cannot mint and the signed-in reads refuse, but a
16
+ * link minted earlier keeps reading (STORE_MODULES rule 4).
17
+ */
18
+ /**
19
+ * The refusals the PUBLIC tracking routes answer themselves.
20
+ *
21
+ * - SERVICE_TRACKING_TOKEN_INVALID (401): every reason a handle cannot be
22
+ * honoured — missing, malformed, unknown, revoked, past the lifetime,
23
+ * presented on another store's host or with no store host at all, or naming
24
+ * an order that is gone or disabled — with one identical body, so a handle is
25
+ * never an oracle.
26
+ * - SERVICE_QUOTE_NOT_FOUND (404, `mode=quote-pdf` only): the order has no
27
+ * current presupuesto a customer was sent.
28
+ */
29
+ export declare const SERVICE_TRACKING_ERROR_CODES: readonly ["SERVICE_TRACKING_TOKEN_INVALID", "SERVICE_QUOTE_NOT_FOUND"];
30
+ export type ServiceTrackingErrorCode = (typeof SERVICE_TRACKING_ERROR_CODES)[number];
31
+ /**
32
+ * The refusals of the signed-in reads (`GET /user?mode=service-orders` and
33
+ * `?mode=service-order&serviceOrderId=`).
34
+ *
35
+ * - SERVICE_TRACKING_DISABLED (403): the store's gate is off.
36
+ * - SERVICE_ORDER_NOT_FOUND (404): no such order, a disabled one, or one that
37
+ * belongs to another customer — one answer for all three.
38
+ */
39
+ export declare const SERVICE_TRACKING_ACCOUNT_ERROR_CODES: readonly ["SERVICE_TRACKING_DISABLED", "SERVICE_ORDER_NOT_FOUND"];
40
+ export type ServiceTrackingAccountErrorCode = (typeof SERVICE_TRACKING_ACCOUNT_ERROR_CODES)[number];
41
+ /**
42
+ * The refusals of the staff `POST /services { mode: 'trackingLink' }`, beside
43
+ * the router's own (`ROLE_FORBIDDEN`, `VALIDATION_FAILED`, `SERVICE_ORDER_NOT_FOUND`).
44
+ *
45
+ * - SERVICE_TRACKING_DISABLED (403, mint only): the store's gate is off.
46
+ * - SERVICE_TRACKING_NO_ADDRESS (409, mint only): the store has no public
47
+ * storefront address to build the link on (no slug, or public links off).
48
+ * - SERVICE_TRACKING_LINK_LAPSED (409, mint only): the order closed more than
49
+ * `serviceTrackingLinkDaysAfterClose` days ago, so a link would not read.
50
+ * - ADMIN_REQUIRED (403, revoke only): revoking takes ADMIN, SUPERVISOR or MANAGER.
51
+ */
52
+ export declare const SERVICE_TRACKING_OPERATOR_ERROR_CODES: readonly ["SERVICE_TRACKING_DISABLED", "SERVICE_TRACKING_NO_ADDRESS", "SERVICE_TRACKING_LINK_LAPSED", "ADMIN_REQUIRED"];
53
+ export type ServiceTrackingOperatorErrorCode = (typeof SERVICE_TRACKING_OPERATOR_ERROR_CODES)[number];
54
+ /** `POST /services { mode: 'trackingLink' }` actions. */
55
+ export declare const SERVICE_TRACKING_LINK_ACTIONS: readonly ["mint", "revoke"];
56
+ /** The storefront path a tracking link opens: `/servicio/{handle}`. */
57
+ export declare const SERVICE_TRACKING_PATH_PREFIX: "/servicio/";
58
+ /** The handle's exact shape: 16 base62 characters. */
59
+ export declare const SERVICE_TRACKING_HANDLE_RE: RegExp;
60
+ declare global {
61
+ type ServiceTrackingLinkAction = (typeof SERVICE_TRACKING_LINK_ACTIONS)[number];
62
+ /** `ServiceOrder.trackingLink` — what staff see of the link; the handle never rides it. */
63
+ interface ServiceTrackingLinkState {
64
+ /** Unix ms the current link was minted. */
65
+ mintedAt: number;
66
+ /** Unix ms every earlier link was revoked; removed by the next mint. */
67
+ revokedAt?: number;
68
+ }
69
+ /** `POST /services { mode: 'trackingLink', action: 'mint' }` — any staff who can open the order. */
70
+ interface ServiceTrackingLinkMintRequest {
71
+ mode: 'trackingLink';
72
+ action: 'mint';
73
+ serviceOrderId: string;
74
+ }
75
+ /**
76
+ * `POST /services { mode: 'trackingLink', action: 'revoke' }` — ADMIN,
77
+ * SUPERVISOR or MANAGER, never under impersonation. Kills every earlier link;
78
+ * the next mint answers a new one.
79
+ */
80
+ interface ServiceTrackingLinkRevokeRequest {
81
+ mode: 'trackingLink';
82
+ action: 'revoke';
83
+ serviceOrderId: string;
84
+ }
85
+ type ServiceTrackingLinkRequest = ServiceTrackingLinkMintRequest | ServiceTrackingLinkRevokeRequest;
86
+ /** The mint answer's `data`: the link at the current generation (one link per generation, so a repeat mint answers the same URL). */
87
+ interface ServiceTrackingLinkMintResult {
88
+ url: string;
89
+ trackingLink: ServiceTrackingLinkState;
90
+ }
91
+ /** The revoke answer's `data`. `trackingLink` is absent when the order never had a link (nothing is written on it then). */
92
+ interface ServiceTrackingLinkRevokeResult {
93
+ trackingLink?: ServiceTrackingLinkState;
94
+ }
95
+ /**
96
+ * `POST /services/tracking/recover` body (strict): ask for the tracking link of
97
+ * one service ticket. Always `202` with one fixed body, whether or not anything
98
+ * matched; a match mails the live link to the address STORED on the ticket's
99
+ * customer (never this one). Only a malformed body answers otherwise (`400`).
100
+ */
101
+ interface ServiceTrackingRecoverRequest {
102
+ /** The ticket number the shop printed on the order: digits, at least 6. */
103
+ ticketNumber: string;
104
+ email: string;
105
+ }
106
+ /** One step of the status history as the customer sees it — no operator, no note. */
107
+ interface ServiceTrackingTimelineEntry {
108
+ status: ServiceStatus;
109
+ /** Unix ms. */
110
+ at: number;
111
+ }
112
+ /** The equipment as taken in. Every field is optional; the serial travels as its last four characters only. */
113
+ interface ServiceTrackingEquipment {
114
+ type?: string;
115
+ brand?: string;
116
+ model?: string;
117
+ serialLast4?: string;
118
+ accessories?: string[];
119
+ condition?: string;
120
+ reportedIssue?: string;
121
+ }
122
+ /** One material the presupuesto proposes — no product id, no SKU, no money. */
123
+ interface ServiceTrackingQuotePart {
124
+ name: string;
125
+ quantity: number;
126
+ condition: PartCondition;
127
+ }
128
+ /**
129
+ * The current presupuesto as the customer was sent it — never a draft, never
130
+ * a superseded version. `status` is that version's own: `sent` (awaiting a
131
+ * decision), `approved`, `rejected` or `expired`.
132
+ */
133
+ interface ServiceTrackingQuote {
134
+ quoteId: string;
135
+ status: Exclude<ServiceQuoteStatus, 'draft' | 'superseded'>;
136
+ laborCost?: number;
137
+ partsCost?: number;
138
+ amount: number;
139
+ /** The version's own stamp, else the order's. */
140
+ currency: string;
141
+ /** Unix ms. */
142
+ quotedAt?: number;
143
+ /** Unix ms the offer lapses (Ley 24.240 art. 21(g)). */
144
+ expiresAt?: number;
145
+ parts: ServiceTrackingQuotePart[];
146
+ /** Unix ms of the approval or the rejection. */
147
+ decidedAt?: number;
148
+ }
149
+ /** Whether the customer may decide the presupuesto online. */
150
+ interface ServiceTrackingDecision {
151
+ /** `false` until the online decision ships. */
152
+ canDecide: boolean;
153
+ /** Whether an approval needs the 6-digit code sent to the contact on file. */
154
+ approveNeedsCode: boolean;
155
+ }
156
+ /** The customer's contact as the shop holds it, masked. */
157
+ interface ServiceTrackingContact {
158
+ firstName: string;
159
+ emailMasked?: string;
160
+ phoneMasked?: string;
161
+ }
162
+ /** The shop, as the page names it. `contact` is the storefront's published contact (empty when the shop publishes none). */
163
+ interface ServiceTrackingStore {
164
+ name: string;
165
+ logoUrl?: string;
166
+ contact: StorefrontPublicContact;
167
+ }
168
+ /**
169
+ * The tracking view, built by ALLOW-LIST. Never carries operator notes,
170
+ * diagnosis notes, merchant part costs, work logs, the technician, any user
171
+ * or customer id, a rejection note, a draft or a superseded quote version.
172
+ */
173
+ interface ServiceTrackingView {
174
+ ticketNumber: string;
175
+ serviceType: ServiceType;
176
+ status: ServiceStatus;
177
+ /** The status history, oldest first. */
178
+ timeline: ServiceTrackingTimelineEntry[];
179
+ /** Present only while work is blocked. */
180
+ hold?: {
181
+ reason: ServiceHoldReason;
182
+ expectedUntil?: number;
183
+ };
184
+ custody: ServiceCustody;
185
+ /** Unix ms. */
186
+ promisedAt?: number;
187
+ /** Unix ms. */
188
+ readyAt?: number;
189
+ equipment: ServiceTrackingEquipment;
190
+ /** What was actually wrong, as told to the customer. */
191
+ faultFound?: string;
192
+ quote?: ServiceTrackingQuote;
193
+ /** Unix ms. */
194
+ warrantyExpiresAt?: number;
195
+ decision: ServiceTrackingDecision;
196
+ contact: ServiceTrackingContact;
197
+ store: ServiceTrackingStore;
198
+ }
199
+ /** One row of `GET /user?mode=service-orders`. */
200
+ interface ServiceTrackingAccountListItem {
201
+ serviceOrderId: string;
202
+ ticketNumber: string;
203
+ serviceType: ServiceType;
204
+ status: ServiceStatus;
205
+ /** Unix ms. */
206
+ createdAt: number;
207
+ /** Unix ms. */
208
+ promisedAt?: number;
209
+ equipment: Pick<ServiceTrackingEquipment, 'type' | 'brand' | 'model'>;
210
+ }
211
+ /** `GET /user?mode=service-orders` `data`. `truncated` when more orders exist than were returned. */
212
+ interface ServiceTrackingAccountList {
213
+ serviceOrders: ServiceTrackingAccountListItem[];
214
+ truncated: boolean;
215
+ }
216
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Customer service-order tracking — the page a customer opens from a link a
3
+ * shop sends (`/servicio/{handle}`), and the same view for a signed-in customer
4
+ * on their account.
5
+ *
6
+ * The HANDLE is 16 base62 characters (~95 bits), stored server-side and a
7
+ * bearer credential over exactly ONE service order of one store. It authorises
8
+ * the read (`GET /services/tracking?handle=`) and the current presupuesto PDF
9
+ * (`GET /services/tracking?handle=&mode=quote-pdf`), and nothing else. Every
10
+ * earlier link of an order dies when staff revoke it. A link stops reading
11
+ * `serviceTrackingLinkDaysAfterClose` days (platform global, default 90) after
12
+ * the order reached a terminal status.
13
+ *
14
+ * The gate is `ecommerce.config.serviceTracking` AND the `workshop` module on.
15
+ * With the gate off, staff cannot mint and the signed-in reads refuse, but a
16
+ * link minted earlier keeps reading (STORE_MODULES rule 4).
17
+ */
18
+ /**
19
+ * The refusals the PUBLIC tracking routes answer themselves.
20
+ *
21
+ * - SERVICE_TRACKING_TOKEN_INVALID (401): every reason a handle cannot be
22
+ * honoured — missing, malformed, unknown, revoked, past the lifetime,
23
+ * presented on another store's host or with no store host at all, or naming
24
+ * an order that is gone or disabled — with one identical body, so a handle is
25
+ * never an oracle.
26
+ * - SERVICE_QUOTE_NOT_FOUND (404, `mode=quote-pdf` only): the order has no
27
+ * current presupuesto a customer was sent.
28
+ */
29
+ export const SERVICE_TRACKING_ERROR_CODES = ['SERVICE_TRACKING_TOKEN_INVALID', 'SERVICE_QUOTE_NOT_FOUND'];
30
+ /**
31
+ * The refusals of the signed-in reads (`GET /user?mode=service-orders` and
32
+ * `?mode=service-order&serviceOrderId=`).
33
+ *
34
+ * - SERVICE_TRACKING_DISABLED (403): the store's gate is off.
35
+ * - SERVICE_ORDER_NOT_FOUND (404): no such order, a disabled one, or one that
36
+ * belongs to another customer — one answer for all three.
37
+ */
38
+ export const SERVICE_TRACKING_ACCOUNT_ERROR_CODES = ['SERVICE_TRACKING_DISABLED', 'SERVICE_ORDER_NOT_FOUND'];
39
+ /**
40
+ * The refusals of the staff `POST /services { mode: 'trackingLink' }`, beside
41
+ * the router's own (`ROLE_FORBIDDEN`, `VALIDATION_FAILED`, `SERVICE_ORDER_NOT_FOUND`).
42
+ *
43
+ * - SERVICE_TRACKING_DISABLED (403, mint only): the store's gate is off.
44
+ * - SERVICE_TRACKING_NO_ADDRESS (409, mint only): the store has no public
45
+ * storefront address to build the link on (no slug, or public links off).
46
+ * - SERVICE_TRACKING_LINK_LAPSED (409, mint only): the order closed more than
47
+ * `serviceTrackingLinkDaysAfterClose` days ago, so a link would not read.
48
+ * - ADMIN_REQUIRED (403, revoke only): revoking takes ADMIN, SUPERVISOR or MANAGER.
49
+ */
50
+ export const SERVICE_TRACKING_OPERATOR_ERROR_CODES = [
51
+ 'SERVICE_TRACKING_DISABLED',
52
+ 'SERVICE_TRACKING_NO_ADDRESS',
53
+ 'SERVICE_TRACKING_LINK_LAPSED',
54
+ 'ADMIN_REQUIRED',
55
+ ];
56
+ /** `POST /services { mode: 'trackingLink' }` actions. */
57
+ export const SERVICE_TRACKING_LINK_ACTIONS = ['mint', 'revoke'];
58
+ /** The storefront path a tracking link opens: `/servicio/{handle}`. */
59
+ export const SERVICE_TRACKING_PATH_PREFIX = '/servicio/';
60
+ /** The handle's exact shape: 16 base62 characters. */
61
+ export const SERVICE_TRACKING_HANDLE_RE = /^[0-9A-Za-z]{16}$/;
package/dist/store.d.ts CHANGED
@@ -182,6 +182,19 @@ declare global {
182
182
  * frame), so the storefront can offer the request.
183
183
  */
184
184
  wholesaleRequests?: boolean;
185
+ /**
186
+ * Whether the shop's customers can follow their service orders online: the
187
+ * tracking link (`/servicio/{handle}`) staff mint with
188
+ * `POST /services { mode: 'trackingLink' }`, and the signed-in
189
+ * `GET /user?mode=service-orders`. Absent or `false` = off. Honoured only
190
+ * while the `workshop` module is on (`config.modules.workshop !== false`).
191
+ * Turning it off later stops new links and the signed-in reads; links
192
+ * already minted keep reading (STORE_MODULES rule 4). Written by
193
+ * `PATCH /store` (ADMIN) and `PUT /platform/stores/{storeId}` (MANAGER).
194
+ * SENT TO SHOPPERS as the verdict (web `GET /store` and the customer
195
+ * `stores` frame): stored `true` AND the workshop module on.
196
+ */
197
+ serviceTracking?: boolean;
185
198
  /**
186
199
  * Whether the shop sells to shoppers without an account (server guest
187
200
  * cart, guest checkout). Absent means ON: a shop opts out by storing
@@ -260,7 +273,7 @@ declare global {
260
273
  * (Responsable Inscripto) refuses 409 NET_PLUS_IVA_REQUIRES_RI; nothing written.
261
274
  */
262
275
  interface EcommercePatchInput {
263
- config?: Pick<NonNullable<Ecommerce['config']>, 'showDefaultPriceList' | 'newCustomerPriceList' | 'registrationMode' | 'wholesaleRequests' | 'paymentHoldMinutes'> & StorefrontLiveSettingsPatch;
276
+ config?: Pick<NonNullable<Ecommerce['config']>, 'showDefaultPriceList' | 'newCustomerPriceList' | 'registrationMode' | 'wholesaleRequests' | 'serviceTracking' | 'paymentHoldMinutes'> & StorefrontLiveSettingsPatch;
264
277
  sidebar?: Ecommerce['sidebar'];
265
278
  home?: Omit<NonNullable<Ecommerce['home']>, 'displayOrders' | 'displayProfile'>;
266
279
  themeColors?: Ecommerce['themeColors'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "platform-types",
3
- "version": "1.10.851",
3
+ "version": "1.10.853",
4
4
  "description": "Shared wire and entity contracts for the platform.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",