platform-types 1.10.792 → 1.10.794
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/index.js +1 -0
- package/dist/cjs/notification.js +20 -1
- package/dist/cjs/presupuesto.js +8 -0
- package/dist/cjs/quoteRequest.js +63 -0
- package/dist/cjs/storefrontDesign.js +2 -0
- package/dist/cjs/storefrontDesignRegistry.js +4 -0
- package/dist/customer.d.ts +35 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/notification.d.ts +25 -2
- package/dist/notification.js +20 -1
- package/dist/presupuesto.d.ts +18 -1
- package/dist/presupuesto.js +8 -0
- package/dist/quoteRequest.d.ts +120 -0
- package/dist/quoteRequest.js +60 -0
- package/dist/storefrontDesign.d.ts +25 -2
- package/dist/storefrontDesign.js +2 -0
- package/dist/storefrontDesignRegistry.d.ts +184 -0
- package/dist/storefrontDesignRegistry.js +4 -0
- package/package.json +1 -1
package/dist/cjs/index.js
CHANGED
|
@@ -55,6 +55,7 @@ __exportStar(require("./favorite.js"), exports);
|
|
|
55
55
|
__exportStar(require("./fiscalConditions.js"), exports);
|
|
56
56
|
__exportStar(require("./gating.js"), exports);
|
|
57
57
|
__exportStar(require("./guestAttach.js"), exports);
|
|
58
|
+
__exportStar(require("./quoteRequest.js"), exports);
|
|
58
59
|
__exportStar(require("./guestOrderStatus.js"), exports);
|
|
59
60
|
__exportStar(require("./holdingCost.js"), exports);
|
|
60
61
|
__exportStar(require("./demo.js"), exports);
|
package/dist/cjs/notification.js
CHANGED
|
@@ -6,7 +6,8 @@ exports.WEB_NOTIFICATIONS_MAX_LIMIT = exports.CUSTOMER_NOTIFICATION_TYPES = expo
|
|
|
6
6
|
// legacy opt-ins and explicit channel maps remain source data on USER rows.
|
|
7
7
|
// Addressed ERROR / ML_FACTURADOR_COLLISION / ML_SELLER_SWITCHED /
|
|
8
8
|
// ML_CONNECTION_BROKEN / MENTION / CUSTOMER_PENDING_APPROVAL /
|
|
9
|
-
// PAYMENT_ATTEMPT_RESOLUTION / CUSTOMER_WHOLESALE_REQUEST do not select a
|
|
9
|
+
// PAYMENT_ATTEMPT_RESOLUTION / CUSTOMER_WHOLESALE_REQUEST / STOREFRONT_QUOTE_REQUEST do not select a
|
|
10
|
+
// producer subscriber audience;
|
|
10
11
|
// the consumer still reads the live USER row for each delivery channel.
|
|
11
12
|
// AFIP_CERT_EXPIRY is seeded on the founding user and uses the subscriber index.
|
|
12
13
|
// Exported as a real enum consumed by api and app; adding an indexed type
|
|
@@ -217,6 +218,24 @@ var NotificationTypeEnum;
|
|
|
217
218
|
* audience — the bell would reach the buyer's own storefront socket).
|
|
218
219
|
*/
|
|
219
220
|
NotificationTypeEnum["CUSTOMER_WHOLESALE_REQUEST"] = "CUSTOMER_WHOLESALE_REQUEST";
|
|
221
|
+
/**
|
|
222
|
+
* A shopper sent a quote request from a storefront `quoteRequest` section
|
|
223
|
+
* (web `POST /quote-requests`) and it waits in the operator inbox
|
|
224
|
+
* (`GET /quote-requests`). The bell names nobody — the request's contact
|
|
225
|
+
* data is PII and NOTIF# rows outlive an erasure.
|
|
226
|
+
*
|
|
227
|
+
* ⚠️ ADMIN-ONLY, and its own preference key. The producer fans out to every
|
|
228
|
+
* non-disabled ADMIN of the store (`listActiveAdmins`), the same recipients
|
|
229
|
+
* as `CUSTOMER_PENDING_APPROVAL`. No legacy opt-in scan: the consumer
|
|
230
|
+
* enforces explicit type/channel preferences
|
|
231
|
+
* (`notificationPreferences.STOREFRONT_QUOTE_REQUEST`), default-on when
|
|
232
|
+
* absent. Additive — no backfill or consumer migration owed.
|
|
233
|
+
*
|
|
234
|
+
* ⚠️ Carries `quoteRequestRef` and NEVER a top-level `customerId` (an
|
|
235
|
+
* audience — the bell would reach a signed-in requester's own storefront
|
|
236
|
+
* socket).
|
|
237
|
+
*/
|
|
238
|
+
NotificationTypeEnum["STOREFRONT_QUOTE_REQUEST"] = "STOREFRONT_QUOTE_REQUEST";
|
|
220
239
|
})(NotificationTypeEnum || (exports.NotificationTypeEnum = NotificationTypeEnum = {}));
|
|
221
240
|
/**
|
|
222
241
|
* The notification types a CUSTOMER bell can carry today; each links through
|
package/dist/cjs/presupuesto.js
CHANGED
|
@@ -132,6 +132,11 @@ exports.PRESUPUESTO_IMMUTABLE_STATUSES = ['rejected', 'expired'];
|
|
|
132
132
|
* ⚠️ `GET` has no such gate.
|
|
133
133
|
* - `INVALID_CURSOR` · 400 — a malformed `?startKey=`, or one minted against a
|
|
134
134
|
* different store or index. Read path only.
|
|
135
|
+
* - `QUOTE_REQUEST_NOT_FOUND` · 404 — a create naming a `quoteRequestId` this
|
|
136
|
+
* store has no request for. Nothing is written and no number is spent.
|
|
137
|
+
* - `QUOTE_REQUEST_ALREADY_LINKED` · 409 — a create naming a quote request that a
|
|
138
|
+
* presupuesto already converted, found by the read before the write or by the
|
|
139
|
+
* write's own condition when two creates race. No presupuesto is written.
|
|
135
140
|
* - `PRODUCT_COST_UNKNOWN` · 400 — a conversion naming a product whose catalogue
|
|
136
141
|
* row states no `cost`, refused rather than booking an order with a COGS
|
|
137
142
|
* nobody can state. The same body the POS checkout renders.
|
|
@@ -176,4 +181,7 @@ exports.PRESUPUESTO_ERROR_CODES = [
|
|
|
176
181
|
// The per-sale cap refusal every sale entry point shares (`ProductSaleLimitRefusal`).
|
|
177
182
|
'PRODUCT_SALE_LIMIT_EXCEEDED',
|
|
178
183
|
'PRODUCT_SALE_LIMIT_INVALID',
|
|
184
|
+
// The create's storefront quote-request link (`quoteRequestId`).
|
|
185
|
+
'QUOTE_REQUEST_NOT_FOUND',
|
|
186
|
+
'QUOTE_REQUEST_ALREADY_LINKED',
|
|
179
187
|
];
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Storefront quote requests — a shopper (guest or signed-in) asks the shop for a
|
|
4
|
+
* quote from a `quoteRequest` storefront section; the operator reads it in the
|
|
5
|
+
* back office and turns it into a Presupuesto.
|
|
6
|
+
*
|
|
7
|
+
* Web (public, bound origin only): `POST /quote-requests`.
|
|
8
|
+
* App (ADMIN, SUPERVISOR, MANAGER): `GET /quote-requests` (list and read) and
|
|
9
|
+
* `POST /quote-requests { mode: 'status' }`. A Presupuesto created with
|
|
10
|
+
* `quoteRequestId` links the request (`POST /presupuestos`).
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.QUOTE_REQUEST_RECAPTCHA_ACTION = exports.QUOTE_REQUEST_LIMITS = exports.QUOTE_REQUEST_OPTIONAL_FIELDS = exports.QUOTE_REQUEST_STATUSES = exports.QUOTE_REQUEST_ERROR_CODES = void 0;
|
|
14
|
+
/**
|
|
15
|
+
* The refusals of the quote-request routes.
|
|
16
|
+
*
|
|
17
|
+
* - INVALID_QUOTE_REQUEST (400): a body over 8 KiB, malformed or off-schema; a guest
|
|
18
|
+
* without `contact`; `items` when no placed `quoteRequest` section allows them
|
|
19
|
+
* (`fieldErrors` names `items`); a guest `contact.phone` / `company` / `cuit` no
|
|
20
|
+
* placed section lists in `fields` (names `contact.<field>` — refused, never
|
|
21
|
+
* dropped); or an `items[i]` naming a product that does not exist or is not
|
|
22
|
+
* offered on the storefront (names `items.<i>.productId`).
|
|
23
|
+
* - CAPTCHA_INVALID (403): the `x-captcha-token` header is missing, invalid or
|
|
24
|
+
* scored too low. One body whatever the reason.
|
|
25
|
+
* - ORIGIN_STORE_MISMATCH (403): the request's Origin is not bound to a shop, or
|
|
26
|
+
* is bound to another shop than the one it names. Nothing is stored.
|
|
27
|
+
* - QUOTE_REQUESTS_DISABLED (403): the shop's live publication has no enabled
|
|
28
|
+
* `quoteRequest` section on an enabled page — it never placed the form, or
|
|
29
|
+
* unpublished it. Nothing is stored.
|
|
30
|
+
* - QUOTE_REQUEST_LIMIT (429): the shop's daily cap for guests, or the hourly
|
|
31
|
+
* cool-down of the guest's address or the signed-in buyer's account, is spent.
|
|
32
|
+
* Nothing is stored.
|
|
33
|
+
* - QUOTE_REQUEST_NOT_FOUND (404): app routes, an unknown `quoteRequestId`.
|
|
34
|
+
* - QUOTE_REQUEST_ALREADY_LINKED (409): `POST /presupuestos` naming a request
|
|
35
|
+
* another Presupuesto already converted. No Presupuesto is written. Also the
|
|
36
|
+
* app `POST /quote-requests { mode: 'status' }` on a converted request: its
|
|
37
|
+
* status belongs to the Presupuesto that converted it and no longer changes.
|
|
38
|
+
*/
|
|
39
|
+
exports.QUOTE_REQUEST_ERROR_CODES = [
|
|
40
|
+
'INVALID_QUOTE_REQUEST',
|
|
41
|
+
'CAPTCHA_INVALID',
|
|
42
|
+
'ORIGIN_STORE_MISMATCH',
|
|
43
|
+
'QUOTE_REQUESTS_DISABLED',
|
|
44
|
+
'QUOTE_REQUEST_LIMIT',
|
|
45
|
+
'QUOTE_REQUEST_NOT_FOUND',
|
|
46
|
+
'QUOTE_REQUEST_ALREADY_LINKED',
|
|
47
|
+
];
|
|
48
|
+
exports.QUOTE_REQUEST_STATUSES = ['new', 'in-progress', 'converted', 'dismissed'];
|
|
49
|
+
/** The optional contact fields a `quoteRequest` section may ask for. */
|
|
50
|
+
exports.QUOTE_REQUEST_OPTIONAL_FIELDS = ['phone', 'company', 'cuit'];
|
|
51
|
+
/** Bounds of the web write. */
|
|
52
|
+
exports.QUOTE_REQUEST_LIMITS = {
|
|
53
|
+
message: 2000,
|
|
54
|
+
items: 50,
|
|
55
|
+
/** The shared base-quantity ceiling (`baseQuantitySchema`), six decimal places. */
|
|
56
|
+
itemQuantity: 1_000_000,
|
|
57
|
+
name: 120,
|
|
58
|
+
company: 120,
|
|
59
|
+
email: 254,
|
|
60
|
+
phone: 40,
|
|
61
|
+
};
|
|
62
|
+
/** The reCAPTCHA action the storefront executes for the web write. */
|
|
63
|
+
exports.QUOTE_REQUEST_RECAPTCHA_ACTION = 'quote_request';
|
|
@@ -61,6 +61,10 @@ exports.STOREFRONT_DESIGN_SETTINGS = {
|
|
|
61
61
|
layoutDensity: choice('layoutDensity', ['comfortable', 'dense'], 'comfortable', 'Densidad', 'Elegí cuánto espacio dejás entre los elementos de toda la tienda.'),
|
|
62
62
|
showBrand: toggle('showBrand', false, 'Mostrar marca', 'Mostrar la marca en las tarjetas de productos.'),
|
|
63
63
|
showSku: toggle('showSku', false, 'Mostrar SKU', 'Mostrar el código SKU en las tarjetas de productos.'),
|
|
64
|
+
showTierHint: toggle('showTierHint', true, 'Mostrar precios por cantidad', 'Muestra en las tarjetas el aviso de precio por cantidad, cuando el producto lo tiene.'),
|
|
65
|
+
showCompareAt: toggle('showCompareAt', true, 'Mostrar precio anterior', 'Muestra en las tarjetas el precio anterior tachado, cuando el producto lo tiene.'),
|
|
66
|
+
showStockBadge: toggle('showStockBadge', true, 'Mostrar avisos de stock', 'Oculta los avisos de stock en las tarjetas. Si la tienda oculta las cantidades, este ajuste no las muestra.'),
|
|
67
|
+
showQuickAdd: toggle('showQuickAdd', true, 'Mostrar botón Agregar', 'Muestra el botón Agregar en las tarjetas. Las filas de productos siempre lo muestran.'),
|
|
64
68
|
};
|
|
65
69
|
const isStorefrontDesignSettingKey = (key) => Object.hasOwn(exports.STOREFRONT_DESIGN_SETTINGS, key);
|
|
66
70
|
exports.isStorefrontDesignSettingKey = isStorefrontDesignSettingKey;
|
package/dist/customer.d.ts
CHANGED
|
@@ -1273,6 +1273,17 @@ declare global {
|
|
|
1273
1273
|
* the request flow).
|
|
1274
1274
|
*/
|
|
1275
1275
|
wholesaleRequests?: WholesaleRequestExportEntry[];
|
|
1276
|
+
/**
|
|
1277
|
+
* The subject's storefront quote requests, newest first, on BOTH surfaces:
|
|
1278
|
+
* the ones they sent signed in under their own id plus any filed under a
|
|
1279
|
+
* merged-away id folded into them (the same folded ids, and the same cap, as
|
|
1280
|
+
* the financial collections). Each is the request as the operator reads it —
|
|
1281
|
+
* the contact copied from their account, the message, the items and its
|
|
1282
|
+
* status. A request sent as a guest carries no customer id and is not
|
|
1283
|
+
* reachable from here. Absent when there is none (and from servers predating
|
|
1284
|
+
* storefront quote requests).
|
|
1285
|
+
*/
|
|
1286
|
+
quoteRequests?: QuoteRequest[];
|
|
1276
1287
|
/**
|
|
1277
1288
|
* Per COLLECTION, and honest: `true` means the read stopped before the
|
|
1278
1289
|
* end of a partition, folded financial IDs were omitted at the cap, or whole
|
|
@@ -1302,6 +1313,12 @@ declare global {
|
|
|
1302
1313
|
* may be missing.
|
|
1303
1314
|
*/
|
|
1304
1315
|
wholesaleRequests?: boolean;
|
|
1316
|
+
/**
|
|
1317
|
+
* Present when `quoteRequests` is, or when merged-away ids were cut at the
|
|
1318
|
+
* folded-id cap — then `true`: a request filed under an omitted id, or
|
|
1319
|
+
* past the per-export request cap, may be missing.
|
|
1320
|
+
*/
|
|
1321
|
+
quoteRequests?: boolean;
|
|
1305
1322
|
};
|
|
1306
1323
|
}
|
|
1307
1324
|
/**
|
|
@@ -1609,6 +1626,24 @@ declare global {
|
|
|
1609
1626
|
* (`WebAnonymizeCustomerResult`).
|
|
1610
1627
|
*/
|
|
1611
1628
|
rmaEraseComplete: boolean;
|
|
1629
|
+
/**
|
|
1630
|
+
* Storefront quote requests the subject sent signed in
|
|
1631
|
+
* (`QUOTEREQUEST#{storeId}`), DELETED by this erasure — the whole row goes:
|
|
1632
|
+
* it holds their contact and free text. Found through the per-customer
|
|
1633
|
+
* pointer row, which goes last. A Presupuesto raised from one keeps its
|
|
1634
|
+
* `sourceQuoteRequestId`, now dangling. Optional only so the field is
|
|
1635
|
+
* additive — every erasure from this version on sets it.
|
|
1636
|
+
*/
|
|
1637
|
+
quoteRequestsErased?: number;
|
|
1638
|
+
/**
|
|
1639
|
+
* `false` when the subject's quote requests could not be read or deleted
|
|
1640
|
+
* to the end, so one may remain. Re-issuing the erasure re-runs the step;
|
|
1641
|
+
* BOTH erasure handlers write a deduped `ERROR` row
|
|
1642
|
+
* (`CUSTOMER_ANONYMIZE_QUOTE_REQUESTS_INCOMPLETE`). On BOTH wires — the
|
|
1643
|
+
* subject's own data. Optional only so the field is additive; only a
|
|
1644
|
+
* measured `true` is a finished step.
|
|
1645
|
+
*/
|
|
1646
|
+
quoteRequestEraseComplete?: boolean;
|
|
1612
1647
|
/**
|
|
1613
1648
|
* The subject's `ORDER#` rows whose frozen recipient this erasure scrubbed —
|
|
1614
1649
|
* `customer` reduced to `{ customerId }`, `deliveryAddress` removed, the
|
package/dist/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ export * from './favorite.ts';
|
|
|
31
31
|
export * from './fiscalConditions.ts';
|
|
32
32
|
export * from './gating.ts';
|
|
33
33
|
export * from './guestAttach.ts';
|
|
34
|
+
export * from './quoteRequest.ts';
|
|
34
35
|
export * from './guestOrderStatus.ts';
|
|
35
36
|
export * from './holdingCost.ts';
|
|
36
37
|
export * from './demo.ts';
|
package/dist/index.js
CHANGED
|
@@ -39,6 +39,7 @@ export * from "./favorite.js";
|
|
|
39
39
|
export * from "./fiscalConditions.js";
|
|
40
40
|
export * from "./gating.js";
|
|
41
41
|
export * from "./guestAttach.js";
|
|
42
|
+
export * from "./quoteRequest.js";
|
|
42
43
|
export * from "./guestOrderStatus.js";
|
|
43
44
|
export * from "./holdingCost.js";
|
|
44
45
|
export * from "./demo.js";
|
package/dist/notification.d.ts
CHANGED
|
@@ -195,7 +195,25 @@ export declare enum NotificationTypeEnum {
|
|
|
195
195
|
* ⚠️ Carries `wholesaleRequestRef` and NEVER a top-level `customerId` (an
|
|
196
196
|
* audience — the bell would reach the buyer's own storefront socket).
|
|
197
197
|
*/
|
|
198
|
-
CUSTOMER_WHOLESALE_REQUEST = "CUSTOMER_WHOLESALE_REQUEST"
|
|
198
|
+
CUSTOMER_WHOLESALE_REQUEST = "CUSTOMER_WHOLESALE_REQUEST",
|
|
199
|
+
/**
|
|
200
|
+
* A shopper sent a quote request from a storefront `quoteRequest` section
|
|
201
|
+
* (web `POST /quote-requests`) and it waits in the operator inbox
|
|
202
|
+
* (`GET /quote-requests`). The bell names nobody — the request's contact
|
|
203
|
+
* data is PII and NOTIF# rows outlive an erasure.
|
|
204
|
+
*
|
|
205
|
+
* ⚠️ ADMIN-ONLY, and its own preference key. The producer fans out to every
|
|
206
|
+
* non-disabled ADMIN of the store (`listActiveAdmins`), the same recipients
|
|
207
|
+
* as `CUSTOMER_PENDING_APPROVAL`. No legacy opt-in scan: the consumer
|
|
208
|
+
* enforces explicit type/channel preferences
|
|
209
|
+
* (`notificationPreferences.STOREFRONT_QUOTE_REQUEST`), default-on when
|
|
210
|
+
* absent. Additive — no backfill or consumer migration owed.
|
|
211
|
+
*
|
|
212
|
+
* ⚠️ Carries `quoteRequestRef` and NEVER a top-level `customerId` (an
|
|
213
|
+
* audience — the bell would reach a signed-in requester's own storefront
|
|
214
|
+
* socket).
|
|
215
|
+
*/
|
|
216
|
+
STOREFRONT_QUOTE_REQUEST = "STOREFRONT_QUOTE_REQUEST"
|
|
199
217
|
}
|
|
200
218
|
/**
|
|
201
219
|
* The notification types a CUSTOMER bell can carry today; each links through
|
|
@@ -313,6 +331,11 @@ declare global {
|
|
|
313
331
|
* an audience — see {@link WholesaleRequestRef}.
|
|
314
332
|
*/
|
|
315
333
|
wholesaleRequestRef?: WholesaleRequestRef;
|
|
334
|
+
/**
|
|
335
|
+
* `STOREFRONT_QUOTE_REQUEST` only: which request to open. A POINTER, not
|
|
336
|
+
* an audience — see {@link QuoteRequestRef}. Operator surfaces only.
|
|
337
|
+
*/
|
|
338
|
+
quoteRequestRef?: QuoteRequestRef;
|
|
316
339
|
/** `MENTION` only: the colleague who wrote the mention (a snapshot). */
|
|
317
340
|
actor?: NotificationActor;
|
|
318
341
|
userId?: string;
|
|
@@ -376,7 +399,7 @@ declare global {
|
|
|
376
399
|
* customer socket carry — the stored row minus the operator-only pointers.
|
|
377
400
|
* A union keyed on `type`; `ORDER` is its only member today.
|
|
378
401
|
*/
|
|
379
|
-
type CustomerNotification = Omit<NotificationInterface, 'cartRef' | 'pendingCustomerRef' | 'wholesaleRequestRef' | 'TableName' | 'type' | 'orderId'> & {
|
|
402
|
+
type CustomerNotification = Omit<NotificationInterface, 'cartRef' | 'pendingCustomerRef' | 'wholesaleRequestRef' | 'quoteRequestRef' | 'TableName' | 'type' | 'orderId'> & {
|
|
380
403
|
type: NotificationTypeEnum.ORDER;
|
|
381
404
|
/** Set on every customer row: the order the bell is about. */
|
|
382
405
|
orderId: string;
|
package/dist/notification.js
CHANGED
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
// legacy opt-ins and explicit channel maps remain source data on USER rows.
|
|
4
4
|
// Addressed ERROR / ML_FACTURADOR_COLLISION / ML_SELLER_SWITCHED /
|
|
5
5
|
// ML_CONNECTION_BROKEN / MENTION / CUSTOMER_PENDING_APPROVAL /
|
|
6
|
-
// PAYMENT_ATTEMPT_RESOLUTION / CUSTOMER_WHOLESALE_REQUEST do not select a
|
|
6
|
+
// PAYMENT_ATTEMPT_RESOLUTION / CUSTOMER_WHOLESALE_REQUEST / STOREFRONT_QUOTE_REQUEST do not select a
|
|
7
|
+
// producer subscriber audience;
|
|
7
8
|
// the consumer still reads the live USER row for each delivery channel.
|
|
8
9
|
// AFIP_CERT_EXPIRY is seeded on the founding user and uses the subscriber index.
|
|
9
10
|
// Exported as a real enum consumed by api and app; adding an indexed type
|
|
@@ -214,6 +215,24 @@ export var NotificationTypeEnum;
|
|
|
214
215
|
* audience — the bell would reach the buyer's own storefront socket).
|
|
215
216
|
*/
|
|
216
217
|
NotificationTypeEnum["CUSTOMER_WHOLESALE_REQUEST"] = "CUSTOMER_WHOLESALE_REQUEST";
|
|
218
|
+
/**
|
|
219
|
+
* A shopper sent a quote request from a storefront `quoteRequest` section
|
|
220
|
+
* (web `POST /quote-requests`) and it waits in the operator inbox
|
|
221
|
+
* (`GET /quote-requests`). The bell names nobody — the request's contact
|
|
222
|
+
* data is PII and NOTIF# rows outlive an erasure.
|
|
223
|
+
*
|
|
224
|
+
* ⚠️ ADMIN-ONLY, and its own preference key. The producer fans out to every
|
|
225
|
+
* non-disabled ADMIN of the store (`listActiveAdmins`), the same recipients
|
|
226
|
+
* as `CUSTOMER_PENDING_APPROVAL`. No legacy opt-in scan: the consumer
|
|
227
|
+
* enforces explicit type/channel preferences
|
|
228
|
+
* (`notificationPreferences.STOREFRONT_QUOTE_REQUEST`), default-on when
|
|
229
|
+
* absent. Additive — no backfill or consumer migration owed.
|
|
230
|
+
*
|
|
231
|
+
* ⚠️ Carries `quoteRequestRef` and NEVER a top-level `customerId` (an
|
|
232
|
+
* audience — the bell would reach a signed-in requester's own storefront
|
|
233
|
+
* socket).
|
|
234
|
+
*/
|
|
235
|
+
NotificationTypeEnum["STOREFRONT_QUOTE_REQUEST"] = "STOREFRONT_QUOTE_REQUEST";
|
|
217
236
|
})(NotificationTypeEnum || (NotificationTypeEnum = {}));
|
|
218
237
|
/**
|
|
219
238
|
* The notification types a CUSTOMER bell can carry today; each links through
|
package/dist/presupuesto.d.ts
CHANGED
|
@@ -135,6 +135,18 @@ declare global {
|
|
|
135
135
|
* write rather than minting a duplicate order.
|
|
136
136
|
*/
|
|
137
137
|
convertedOrderId?: string;
|
|
138
|
+
/**
|
|
139
|
+
* The storefront quote request (`QuoteRequest.quoteRequestId`) this
|
|
140
|
+
* presupuesto was raised from — `POST /presupuestos` with `quoteRequestId`.
|
|
141
|
+
* Written in the SAME transaction that stamps `linkedPresupuestoId` and
|
|
142
|
+
* `status: 'converted'` on the request, so the two halves of the link
|
|
143
|
+
* cannot disagree. Absent on a presupuesto raised from scratch.
|
|
144
|
+
*
|
|
145
|
+
* ⚠️ The request can disappear later — a customer erasure deletes their
|
|
146
|
+
* requests and a guest request expires — so a reader must treat a dangling
|
|
147
|
+
* id as "the request is gone", never as an error.
|
|
148
|
+
*/
|
|
149
|
+
sourceQuoteRequestId?: string;
|
|
138
150
|
createdAt: number;
|
|
139
151
|
updatedAt?: number;
|
|
140
152
|
/** Lowercase '#'-joined write-side index. Internal; not part of the read contract. */
|
|
@@ -226,6 +238,11 @@ export declare const PRESUPUESTO_IMMUTABLE_STATUSES: readonly ["rejected", "expi
|
|
|
226
238
|
* ⚠️ `GET` has no such gate.
|
|
227
239
|
* - `INVALID_CURSOR` · 400 — a malformed `?startKey=`, or one minted against a
|
|
228
240
|
* different store or index. Read path only.
|
|
241
|
+
* - `QUOTE_REQUEST_NOT_FOUND` · 404 — a create naming a `quoteRequestId` this
|
|
242
|
+
* store has no request for. Nothing is written and no number is spent.
|
|
243
|
+
* - `QUOTE_REQUEST_ALREADY_LINKED` · 409 — a create naming a quote request that a
|
|
244
|
+
* presupuesto already converted, found by the read before the write or by the
|
|
245
|
+
* write's own condition when two creates race. No presupuesto is written.
|
|
229
246
|
* - `PRODUCT_COST_UNKNOWN` · 400 — a conversion naming a product whose catalogue
|
|
230
247
|
* row states no `cost`, refused rather than booking an order with a COGS
|
|
231
248
|
* nobody can state. The same body the POS checkout renders.
|
|
@@ -246,6 +263,6 @@ export declare const PRESUPUESTO_IMMUTABLE_STATUSES: readonly ["rejected", "expi
|
|
|
246
263
|
* operator can act on is the distinct-product ceiling those items derive
|
|
247
264
|
* from, and the two refuse at exactly the same point.
|
|
248
265
|
*/
|
|
249
|
-
export declare const PRESUPUESTO_ERROR_CODES: readonly ["PRESUPUESTO_NOT_FOUND", "VALIDATION_FAILED", "ADMIN_REQUIRED", "INVALID_CURSOR", "PRODUCT_COST_UNKNOWN", "PRESUPUESTO_NOT_MUTABLE", "PRESUPUESTO_ILLEGAL_TRANSITION", "PRESUPUESTO_ALREADY_CONVERTED", "PRESUPUESTO_NOT_APPROVED", "PRESUPUESTO_TOO_MANY_PRODUCTS", "TRANSACTION_ITEMS_LIMIT_REACHED", "PRODUCT_NOT_FOUND", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_QUANTITY_UNREPRESENTABLE", "UNIT_REVISION_STALE", "STOCK INSUFICIENTE", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID"];
|
|
266
|
+
export declare const PRESUPUESTO_ERROR_CODES: readonly ["PRESUPUESTO_NOT_FOUND", "VALIDATION_FAILED", "ADMIN_REQUIRED", "INVALID_CURSOR", "PRODUCT_COST_UNKNOWN", "PRESUPUESTO_NOT_MUTABLE", "PRESUPUESTO_ILLEGAL_TRANSITION", "PRESUPUESTO_ALREADY_CONVERTED", "PRESUPUESTO_NOT_APPROVED", "PRESUPUESTO_TOO_MANY_PRODUCTS", "TRANSACTION_ITEMS_LIMIT_REACHED", "PRODUCT_NOT_FOUND", "UNIT_QUANTITY_NOT_WHOLE", "UNIT_QUANTITY_UNREPRESENTABLE", "UNIT_REVISION_STALE", "STOCK INSUFICIENTE", "PRODUCT_SALE_LIMIT_EXCEEDED", "PRODUCT_SALE_LIMIT_INVALID", "QUOTE_REQUEST_NOT_FOUND", "QUOTE_REQUEST_ALREADY_LINKED"];
|
|
250
267
|
export type PresupuestoErrorCode = (typeof PRESUPUESTO_ERROR_CODES)[number];
|
|
251
268
|
export {};
|
package/dist/presupuesto.js
CHANGED
|
@@ -129,6 +129,11 @@ export const PRESUPUESTO_IMMUTABLE_STATUSES = ['rejected', 'expired'];
|
|
|
129
129
|
* ⚠️ `GET` has no such gate.
|
|
130
130
|
* - `INVALID_CURSOR` · 400 — a malformed `?startKey=`, or one minted against a
|
|
131
131
|
* different store or index. Read path only.
|
|
132
|
+
* - `QUOTE_REQUEST_NOT_FOUND` · 404 — a create naming a `quoteRequestId` this
|
|
133
|
+
* store has no request for. Nothing is written and no number is spent.
|
|
134
|
+
* - `QUOTE_REQUEST_ALREADY_LINKED` · 409 — a create naming a quote request that a
|
|
135
|
+
* presupuesto already converted, found by the read before the write or by the
|
|
136
|
+
* write's own condition when two creates race. No presupuesto is written.
|
|
132
137
|
* - `PRODUCT_COST_UNKNOWN` · 400 — a conversion naming a product whose catalogue
|
|
133
138
|
* row states no `cost`, refused rather than booking an order with a COGS
|
|
134
139
|
* nobody can state. The same body the POS checkout renders.
|
|
@@ -173,4 +178,7 @@ export const PRESUPUESTO_ERROR_CODES = [
|
|
|
173
178
|
// The per-sale cap refusal every sale entry point shares (`ProductSaleLimitRefusal`).
|
|
174
179
|
'PRODUCT_SALE_LIMIT_EXCEEDED',
|
|
175
180
|
'PRODUCT_SALE_LIMIT_INVALID',
|
|
181
|
+
// The create's storefront quote-request link (`quoteRequestId`).
|
|
182
|
+
'QUOTE_REQUEST_NOT_FOUND',
|
|
183
|
+
'QUOTE_REQUEST_ALREADY_LINKED',
|
|
176
184
|
];
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storefront quote requests — a shopper (guest or signed-in) asks the shop for a
|
|
3
|
+
* quote from a `quoteRequest` storefront section; the operator reads it in the
|
|
4
|
+
* back office and turns it into a Presupuesto.
|
|
5
|
+
*
|
|
6
|
+
* Web (public, bound origin only): `POST /quote-requests`.
|
|
7
|
+
* App (ADMIN, SUPERVISOR, MANAGER): `GET /quote-requests` (list and read) and
|
|
8
|
+
* `POST /quote-requests { mode: 'status' }`. A Presupuesto created with
|
|
9
|
+
* `quoteRequestId` links the request (`POST /presupuestos`).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The refusals of the quote-request routes.
|
|
13
|
+
*
|
|
14
|
+
* - INVALID_QUOTE_REQUEST (400): a body over 8 KiB, malformed or off-schema; a guest
|
|
15
|
+
* without `contact`; `items` when no placed `quoteRequest` section allows them
|
|
16
|
+
* (`fieldErrors` names `items`); a guest `contact.phone` / `company` / `cuit` no
|
|
17
|
+
* placed section lists in `fields` (names `contact.<field>` — refused, never
|
|
18
|
+
* dropped); or an `items[i]` naming a product that does not exist or is not
|
|
19
|
+
* offered on the storefront (names `items.<i>.productId`).
|
|
20
|
+
* - CAPTCHA_INVALID (403): the `x-captcha-token` header is missing, invalid or
|
|
21
|
+
* scored too low. One body whatever the reason.
|
|
22
|
+
* - ORIGIN_STORE_MISMATCH (403): the request's Origin is not bound to a shop, or
|
|
23
|
+
* is bound to another shop than the one it names. Nothing is stored.
|
|
24
|
+
* - QUOTE_REQUESTS_DISABLED (403): the shop's live publication has no enabled
|
|
25
|
+
* `quoteRequest` section on an enabled page — it never placed the form, or
|
|
26
|
+
* unpublished it. Nothing is stored.
|
|
27
|
+
* - QUOTE_REQUEST_LIMIT (429): the shop's daily cap for guests, or the hourly
|
|
28
|
+
* cool-down of the guest's address or the signed-in buyer's account, is spent.
|
|
29
|
+
* Nothing is stored.
|
|
30
|
+
* - QUOTE_REQUEST_NOT_FOUND (404): app routes, an unknown `quoteRequestId`.
|
|
31
|
+
* - QUOTE_REQUEST_ALREADY_LINKED (409): `POST /presupuestos` naming a request
|
|
32
|
+
* another Presupuesto already converted. No Presupuesto is written. Also the
|
|
33
|
+
* app `POST /quote-requests { mode: 'status' }` on a converted request: its
|
|
34
|
+
* status belongs to the Presupuesto that converted it and no longer changes.
|
|
35
|
+
*/
|
|
36
|
+
export declare const QUOTE_REQUEST_ERROR_CODES: readonly ["INVALID_QUOTE_REQUEST", "CAPTCHA_INVALID", "ORIGIN_STORE_MISMATCH", "QUOTE_REQUESTS_DISABLED", "QUOTE_REQUEST_LIMIT", "QUOTE_REQUEST_NOT_FOUND", "QUOTE_REQUEST_ALREADY_LINKED"];
|
|
37
|
+
export declare const QUOTE_REQUEST_STATUSES: readonly ["new", "in-progress", "converted", "dismissed"];
|
|
38
|
+
/** The optional contact fields a `quoteRequest` section may ask for. */
|
|
39
|
+
export declare const QUOTE_REQUEST_OPTIONAL_FIELDS: readonly ["phone", "company", "cuit"];
|
|
40
|
+
/** Bounds of the web write. */
|
|
41
|
+
export declare const QUOTE_REQUEST_LIMITS: {
|
|
42
|
+
readonly message: 2000;
|
|
43
|
+
readonly items: 50;
|
|
44
|
+
/** The shared base-quantity ceiling (`baseQuantitySchema`), six decimal places. */
|
|
45
|
+
readonly itemQuantity: 1000000;
|
|
46
|
+
readonly name: 120;
|
|
47
|
+
readonly company: 120;
|
|
48
|
+
readonly email: 254;
|
|
49
|
+
readonly phone: 40;
|
|
50
|
+
};
|
|
51
|
+
/** The reCAPTCHA action the storefront executes for the web write. */
|
|
52
|
+
export declare const QUOTE_REQUEST_RECAPTCHA_ACTION = "quote_request";
|
|
53
|
+
declare global {
|
|
54
|
+
type QuoteRequestErrorCode = (typeof QUOTE_REQUEST_ERROR_CODES)[number];
|
|
55
|
+
type QuoteRequestStatus = (typeof QUOTE_REQUEST_STATUSES)[number];
|
|
56
|
+
type QuoteRequestOptionalField = (typeof QUOTE_REQUEST_OPTIONAL_FIELDS)[number];
|
|
57
|
+
interface QuoteRequestContact {
|
|
58
|
+
name: string;
|
|
59
|
+
email: string;
|
|
60
|
+
phone?: string;
|
|
61
|
+
company?: string;
|
|
62
|
+
/** Digits only, 11 when present. */
|
|
63
|
+
cuit?: string;
|
|
64
|
+
}
|
|
65
|
+
interface QuoteRequestItem {
|
|
66
|
+
productId: string;
|
|
67
|
+
quantity: number;
|
|
68
|
+
/** The product's name when the request was sent — never a price. */
|
|
69
|
+
name: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Web `POST /quote-requests` body. The tenant is the request's bound Origin,
|
|
73
|
+
* never `x-store`; the reCAPTCHA token rides the `x-captcha-token` header.
|
|
74
|
+
*
|
|
75
|
+
* - `contact` is REQUIRED for a guest and IGNORED for a signed-in buyer, whose
|
|
76
|
+
* contact is copied from their account. A guest's `phone`, `company` and `cuit`
|
|
77
|
+
* are accepted only when a placed section lists them in `fields`.
|
|
78
|
+
* - `items` is accepted only when a placed section sets `allowItems`.
|
|
79
|
+
* - `website` is a honeypot the storefront renders hidden and leaves empty: when
|
|
80
|
+
* filled, the request answers 201 with a `quoteRequestId` and stores nothing.
|
|
81
|
+
*/
|
|
82
|
+
interface QuoteRequestCreateInput {
|
|
83
|
+
contact?: QuoteRequestContact;
|
|
84
|
+
message: string;
|
|
85
|
+
items?: {
|
|
86
|
+
productId: string;
|
|
87
|
+
quantity: number;
|
|
88
|
+
}[];
|
|
89
|
+
website?: string;
|
|
90
|
+
}
|
|
91
|
+
/** Web `POST /quote-requests` 201 `data`. */
|
|
92
|
+
interface QuoteRequestCreateResult {
|
|
93
|
+
quoteRequestId: string;
|
|
94
|
+
}
|
|
95
|
+
/** The stored request, as the app routes answer it. */
|
|
96
|
+
interface QuoteRequest {
|
|
97
|
+
quoteRequestId: string;
|
|
98
|
+
status: QuoteRequestStatus;
|
|
99
|
+
/** Set only for a signed-in buyer, from the bearer. */
|
|
100
|
+
customerId?: string;
|
|
101
|
+
contact: QuoteRequestContact;
|
|
102
|
+
message: string;
|
|
103
|
+
items?: QuoteRequestItem[];
|
|
104
|
+
/** The Presupuesto that converted this request. */
|
|
105
|
+
linkedPresupuestoId?: string;
|
|
106
|
+
createdAt: number;
|
|
107
|
+
updatedAt: number;
|
|
108
|
+
}
|
|
109
|
+
/** App `POST /quote-requests { mode: 'status' }` body. `converted` is set only by a Presupuesto create. */
|
|
110
|
+
interface QuoteRequestStatusInput {
|
|
111
|
+
mode: 'status';
|
|
112
|
+
quoteRequestId: string;
|
|
113
|
+
status: Exclude<QuoteRequestStatus, 'converted'>;
|
|
114
|
+
}
|
|
115
|
+
/** What a `STOREFRONT_QUOTE_REQUEST` operator bell points at. */
|
|
116
|
+
interface QuoteRequestRef {
|
|
117
|
+
quoteRequestId: string;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storefront quote requests — a shopper (guest or signed-in) asks the shop for a
|
|
3
|
+
* quote from a `quoteRequest` storefront section; the operator reads it in the
|
|
4
|
+
* back office and turns it into a Presupuesto.
|
|
5
|
+
*
|
|
6
|
+
* Web (public, bound origin only): `POST /quote-requests`.
|
|
7
|
+
* App (ADMIN, SUPERVISOR, MANAGER): `GET /quote-requests` (list and read) and
|
|
8
|
+
* `POST /quote-requests { mode: 'status' }`. A Presupuesto created with
|
|
9
|
+
* `quoteRequestId` links the request (`POST /presupuestos`).
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* The refusals of the quote-request routes.
|
|
13
|
+
*
|
|
14
|
+
* - INVALID_QUOTE_REQUEST (400): a body over 8 KiB, malformed or off-schema; a guest
|
|
15
|
+
* without `contact`; `items` when no placed `quoteRequest` section allows them
|
|
16
|
+
* (`fieldErrors` names `items`); a guest `contact.phone` / `company` / `cuit` no
|
|
17
|
+
* placed section lists in `fields` (names `contact.<field>` — refused, never
|
|
18
|
+
* dropped); or an `items[i]` naming a product that does not exist or is not
|
|
19
|
+
* offered on the storefront (names `items.<i>.productId`).
|
|
20
|
+
* - CAPTCHA_INVALID (403): the `x-captcha-token` header is missing, invalid or
|
|
21
|
+
* scored too low. One body whatever the reason.
|
|
22
|
+
* - ORIGIN_STORE_MISMATCH (403): the request's Origin is not bound to a shop, or
|
|
23
|
+
* is bound to another shop than the one it names. Nothing is stored.
|
|
24
|
+
* - QUOTE_REQUESTS_DISABLED (403): the shop's live publication has no enabled
|
|
25
|
+
* `quoteRequest` section on an enabled page — it never placed the form, or
|
|
26
|
+
* unpublished it. Nothing is stored.
|
|
27
|
+
* - QUOTE_REQUEST_LIMIT (429): the shop's daily cap for guests, or the hourly
|
|
28
|
+
* cool-down of the guest's address or the signed-in buyer's account, is spent.
|
|
29
|
+
* Nothing is stored.
|
|
30
|
+
* - QUOTE_REQUEST_NOT_FOUND (404): app routes, an unknown `quoteRequestId`.
|
|
31
|
+
* - QUOTE_REQUEST_ALREADY_LINKED (409): `POST /presupuestos` naming a request
|
|
32
|
+
* another Presupuesto already converted. No Presupuesto is written. Also the
|
|
33
|
+
* app `POST /quote-requests { mode: 'status' }` on a converted request: its
|
|
34
|
+
* status belongs to the Presupuesto that converted it and no longer changes.
|
|
35
|
+
*/
|
|
36
|
+
export const QUOTE_REQUEST_ERROR_CODES = [
|
|
37
|
+
'INVALID_QUOTE_REQUEST',
|
|
38
|
+
'CAPTCHA_INVALID',
|
|
39
|
+
'ORIGIN_STORE_MISMATCH',
|
|
40
|
+
'QUOTE_REQUESTS_DISABLED',
|
|
41
|
+
'QUOTE_REQUEST_LIMIT',
|
|
42
|
+
'QUOTE_REQUEST_NOT_FOUND',
|
|
43
|
+
'QUOTE_REQUEST_ALREADY_LINKED',
|
|
44
|
+
];
|
|
45
|
+
export const QUOTE_REQUEST_STATUSES = ['new', 'in-progress', 'converted', 'dismissed'];
|
|
46
|
+
/** The optional contact fields a `quoteRequest` section may ask for. */
|
|
47
|
+
export const QUOTE_REQUEST_OPTIONAL_FIELDS = ['phone', 'company', 'cuit'];
|
|
48
|
+
/** Bounds of the web write. */
|
|
49
|
+
export const QUOTE_REQUEST_LIMITS = {
|
|
50
|
+
message: 2000,
|
|
51
|
+
items: 50,
|
|
52
|
+
/** The shared base-quantity ceiling (`baseQuantitySchema`), six decimal places. */
|
|
53
|
+
itemQuantity: 1_000_000,
|
|
54
|
+
name: 120,
|
|
55
|
+
company: 120,
|
|
56
|
+
email: 254,
|
|
57
|
+
phone: 40,
|
|
58
|
+
};
|
|
59
|
+
/** The reCAPTCHA action the storefront executes for the web write. */
|
|
60
|
+
export const QUOTE_REQUEST_RECAPTCHA_ACTION = 'quote_request';
|
|
@@ -72,7 +72,7 @@ export declare const STOREFRONT_DESIGN_LIMITS: {
|
|
|
72
72
|
*/
|
|
73
73
|
export declare const STOREFRONT_PAGE_SLUG_RE: RegExp;
|
|
74
74
|
export declare const isStorefrontPageSlug: (value: unknown) => value is string;
|
|
75
|
-
export declare const STOREFRONT_SECTION_TYPES: readonly ["banner", "imageText", "products", "categories", "brands", "text", "faq", "benefits", "contact", "paymentDelivery", "logoWall", "gallery"];
|
|
75
|
+
export declare const STOREFRONT_SECTION_TYPES: readonly ["banner", "imageText", "products", "categories", "brands", "text", "faq", "benefits", "contact", "paymentDelivery", "logoWall", "gallery", "quoteRequest", "customerRequest"];
|
|
76
76
|
/**
|
|
77
77
|
* The section types a page may repeat, each up to `STOREFRONT_DESIGN_LIMITS.repeatableSectionsPerType`
|
|
78
78
|
* times (disabled sections count), so a Home can show offers and new arrivals together. Every other
|
|
@@ -171,7 +171,7 @@ declare global {
|
|
|
171
171
|
};
|
|
172
172
|
products: {
|
|
173
173
|
source?: StorefrontDesignProductSource;
|
|
174
|
-
layout?: 'row' | 'grid';
|
|
174
|
+
layout?: 'row' | 'grid' | 'list';
|
|
175
175
|
count?: number;
|
|
176
176
|
heading?: string;
|
|
177
177
|
/**
|
|
@@ -259,6 +259,29 @@ declare global {
|
|
|
259
259
|
caption?: string;
|
|
260
260
|
}[];
|
|
261
261
|
};
|
|
262
|
+
/**
|
|
263
|
+
* «Pedí un presupuesto»: the storefront form behind web `POST /quote-requests`. `fields` lists
|
|
264
|
+
* the optional contact fields it asks for, each at most once; `allowItems` lets the shopper
|
|
265
|
+
* list products and quantities. Nothing is required to publish. Once per page.
|
|
266
|
+
* The server enforces the placed sections: with no enabled `quoteRequest` section on
|
|
267
|
+
* an enabled published page the write is `403 QUOTE_REQUESTS_DISABLED`; a guest field
|
|
268
|
+
* no placed section lists, or `items` when none sets `allowItems`, is `400`.
|
|
269
|
+
*/
|
|
270
|
+
quoteRequest: {
|
|
271
|
+
heading?: string;
|
|
272
|
+
body?: string;
|
|
273
|
+
fields?: QuoteRequestOptionalField[];
|
|
274
|
+
allowItems?: boolean;
|
|
275
|
+
};
|
|
276
|
+
/**
|
|
277
|
+
* «Quiero ser cliente mayorista»: a placement of the wholesale request (`POST /user`
|
|
278
|
+
* `{ mode: 'wholesale-request' }`), never a second intake. Copy only: what it renders is fixed
|
|
279
|
+
* by the shopper's and the shop's state, never by content. Once per page.
|
|
280
|
+
*/
|
|
281
|
+
customerRequest: {
|
|
282
|
+
heading?: string;
|
|
283
|
+
body?: string;
|
|
284
|
+
};
|
|
262
285
|
}
|
|
263
286
|
type StorefrontDesignAudience = (typeof STOREFRONT_DESIGN_AUDIENCES)[number];
|
|
264
287
|
/**
|
package/dist/storefrontDesign.js
CHANGED
|
@@ -414,6 +414,98 @@ export declare const STOREFRONT_DESIGN_SETTINGS: {
|
|
|
414
414
|
};
|
|
415
415
|
readonly ownership: "storefront-design";
|
|
416
416
|
};
|
|
417
|
+
readonly showTierHint: {
|
|
418
|
+
readonly key: "showTierHint";
|
|
419
|
+
readonly defaultValue: boolean;
|
|
420
|
+
readonly valueType: "boolean";
|
|
421
|
+
readonly valueSchema: {
|
|
422
|
+
readonly type: "boolean";
|
|
423
|
+
};
|
|
424
|
+
readonly description: string;
|
|
425
|
+
readonly literal: {
|
|
426
|
+
readonly kind: "text";
|
|
427
|
+
readonly label: string;
|
|
428
|
+
readonly help: string;
|
|
429
|
+
};
|
|
430
|
+
readonly scope: "storefront";
|
|
431
|
+
readonly allowedLayers: readonly ["GLOBAL", "WEB", "WEB#store"];
|
|
432
|
+
readonly audience: "public";
|
|
433
|
+
readonly lifecycle: "release-owned";
|
|
434
|
+
readonly storage: {
|
|
435
|
+
readonly policy: "GLOBALS";
|
|
436
|
+
readonly override: "design.settings";
|
|
437
|
+
};
|
|
438
|
+
readonly ownership: "storefront-design";
|
|
439
|
+
};
|
|
440
|
+
readonly showCompareAt: {
|
|
441
|
+
readonly key: "showCompareAt";
|
|
442
|
+
readonly defaultValue: boolean;
|
|
443
|
+
readonly valueType: "boolean";
|
|
444
|
+
readonly valueSchema: {
|
|
445
|
+
readonly type: "boolean";
|
|
446
|
+
};
|
|
447
|
+
readonly description: string;
|
|
448
|
+
readonly literal: {
|
|
449
|
+
readonly kind: "text";
|
|
450
|
+
readonly label: string;
|
|
451
|
+
readonly help: string;
|
|
452
|
+
};
|
|
453
|
+
readonly scope: "storefront";
|
|
454
|
+
readonly allowedLayers: readonly ["GLOBAL", "WEB", "WEB#store"];
|
|
455
|
+
readonly audience: "public";
|
|
456
|
+
readonly lifecycle: "release-owned";
|
|
457
|
+
readonly storage: {
|
|
458
|
+
readonly policy: "GLOBALS";
|
|
459
|
+
readonly override: "design.settings";
|
|
460
|
+
};
|
|
461
|
+
readonly ownership: "storefront-design";
|
|
462
|
+
};
|
|
463
|
+
readonly showStockBadge: {
|
|
464
|
+
readonly key: "showStockBadge";
|
|
465
|
+
readonly defaultValue: boolean;
|
|
466
|
+
readonly valueType: "boolean";
|
|
467
|
+
readonly valueSchema: {
|
|
468
|
+
readonly type: "boolean";
|
|
469
|
+
};
|
|
470
|
+
readonly description: string;
|
|
471
|
+
readonly literal: {
|
|
472
|
+
readonly kind: "text";
|
|
473
|
+
readonly label: string;
|
|
474
|
+
readonly help: string;
|
|
475
|
+
};
|
|
476
|
+
readonly scope: "storefront";
|
|
477
|
+
readonly allowedLayers: readonly ["GLOBAL", "WEB", "WEB#store"];
|
|
478
|
+
readonly audience: "public";
|
|
479
|
+
readonly lifecycle: "release-owned";
|
|
480
|
+
readonly storage: {
|
|
481
|
+
readonly policy: "GLOBALS";
|
|
482
|
+
readonly override: "design.settings";
|
|
483
|
+
};
|
|
484
|
+
readonly ownership: "storefront-design";
|
|
485
|
+
};
|
|
486
|
+
readonly showQuickAdd: {
|
|
487
|
+
readonly key: "showQuickAdd";
|
|
488
|
+
readonly defaultValue: boolean;
|
|
489
|
+
readonly valueType: "boolean";
|
|
490
|
+
readonly valueSchema: {
|
|
491
|
+
readonly type: "boolean";
|
|
492
|
+
};
|
|
493
|
+
readonly description: string;
|
|
494
|
+
readonly literal: {
|
|
495
|
+
readonly kind: "text";
|
|
496
|
+
readonly label: string;
|
|
497
|
+
readonly help: string;
|
|
498
|
+
};
|
|
499
|
+
readonly scope: "storefront";
|
|
500
|
+
readonly allowedLayers: readonly ["GLOBAL", "WEB", "WEB#store"];
|
|
501
|
+
readonly audience: "public";
|
|
502
|
+
readonly lifecycle: "release-owned";
|
|
503
|
+
readonly storage: {
|
|
504
|
+
readonly policy: "GLOBALS";
|
|
505
|
+
readonly override: "design.settings";
|
|
506
|
+
};
|
|
507
|
+
readonly ownership: "storefront-design";
|
|
508
|
+
};
|
|
417
509
|
};
|
|
418
510
|
type SettingValue<T> = T extends {
|
|
419
511
|
valueSchema: {
|
|
@@ -822,6 +914,98 @@ export declare const STOREFRONT_DESIGN_REGISTRY: {
|
|
|
822
914
|
};
|
|
823
915
|
readonly ownership: "storefront-design";
|
|
824
916
|
};
|
|
917
|
+
readonly showTierHint: {
|
|
918
|
+
readonly key: "showTierHint";
|
|
919
|
+
readonly defaultValue: boolean;
|
|
920
|
+
readonly valueType: "boolean";
|
|
921
|
+
readonly valueSchema: {
|
|
922
|
+
readonly type: "boolean";
|
|
923
|
+
};
|
|
924
|
+
readonly description: string;
|
|
925
|
+
readonly literal: {
|
|
926
|
+
readonly kind: "text";
|
|
927
|
+
readonly label: string;
|
|
928
|
+
readonly help: string;
|
|
929
|
+
};
|
|
930
|
+
readonly scope: "storefront";
|
|
931
|
+
readonly allowedLayers: readonly ["GLOBAL", "WEB", "WEB#store"];
|
|
932
|
+
readonly audience: "public";
|
|
933
|
+
readonly lifecycle: "release-owned";
|
|
934
|
+
readonly storage: {
|
|
935
|
+
readonly policy: "GLOBALS";
|
|
936
|
+
readonly override: "design.settings";
|
|
937
|
+
};
|
|
938
|
+
readonly ownership: "storefront-design";
|
|
939
|
+
};
|
|
940
|
+
readonly showCompareAt: {
|
|
941
|
+
readonly key: "showCompareAt";
|
|
942
|
+
readonly defaultValue: boolean;
|
|
943
|
+
readonly valueType: "boolean";
|
|
944
|
+
readonly valueSchema: {
|
|
945
|
+
readonly type: "boolean";
|
|
946
|
+
};
|
|
947
|
+
readonly description: string;
|
|
948
|
+
readonly literal: {
|
|
949
|
+
readonly kind: "text";
|
|
950
|
+
readonly label: string;
|
|
951
|
+
readonly help: string;
|
|
952
|
+
};
|
|
953
|
+
readonly scope: "storefront";
|
|
954
|
+
readonly allowedLayers: readonly ["GLOBAL", "WEB", "WEB#store"];
|
|
955
|
+
readonly audience: "public";
|
|
956
|
+
readonly lifecycle: "release-owned";
|
|
957
|
+
readonly storage: {
|
|
958
|
+
readonly policy: "GLOBALS";
|
|
959
|
+
readonly override: "design.settings";
|
|
960
|
+
};
|
|
961
|
+
readonly ownership: "storefront-design";
|
|
962
|
+
};
|
|
963
|
+
readonly showStockBadge: {
|
|
964
|
+
readonly key: "showStockBadge";
|
|
965
|
+
readonly defaultValue: boolean;
|
|
966
|
+
readonly valueType: "boolean";
|
|
967
|
+
readonly valueSchema: {
|
|
968
|
+
readonly type: "boolean";
|
|
969
|
+
};
|
|
970
|
+
readonly description: string;
|
|
971
|
+
readonly literal: {
|
|
972
|
+
readonly kind: "text";
|
|
973
|
+
readonly label: string;
|
|
974
|
+
readonly help: string;
|
|
975
|
+
};
|
|
976
|
+
readonly scope: "storefront";
|
|
977
|
+
readonly allowedLayers: readonly ["GLOBAL", "WEB", "WEB#store"];
|
|
978
|
+
readonly audience: "public";
|
|
979
|
+
readonly lifecycle: "release-owned";
|
|
980
|
+
readonly storage: {
|
|
981
|
+
readonly policy: "GLOBALS";
|
|
982
|
+
readonly override: "design.settings";
|
|
983
|
+
};
|
|
984
|
+
readonly ownership: "storefront-design";
|
|
985
|
+
};
|
|
986
|
+
readonly showQuickAdd: {
|
|
987
|
+
readonly key: "showQuickAdd";
|
|
988
|
+
readonly defaultValue: boolean;
|
|
989
|
+
readonly valueType: "boolean";
|
|
990
|
+
readonly valueSchema: {
|
|
991
|
+
readonly type: "boolean";
|
|
992
|
+
};
|
|
993
|
+
readonly description: string;
|
|
994
|
+
readonly literal: {
|
|
995
|
+
readonly kind: "text";
|
|
996
|
+
readonly label: string;
|
|
997
|
+
readonly help: string;
|
|
998
|
+
};
|
|
999
|
+
readonly scope: "storefront";
|
|
1000
|
+
readonly allowedLayers: readonly ["GLOBAL", "WEB", "WEB#store"];
|
|
1001
|
+
readonly audience: "public";
|
|
1002
|
+
readonly lifecycle: "release-owned";
|
|
1003
|
+
readonly storage: {
|
|
1004
|
+
readonly policy: "GLOBALS";
|
|
1005
|
+
readonly override: "design.settings";
|
|
1006
|
+
};
|
|
1007
|
+
readonly ownership: "storefront-design";
|
|
1008
|
+
};
|
|
825
1009
|
};
|
|
826
1010
|
readonly content: {
|
|
827
1011
|
readonly schema: "StorefrontDesignV1";
|
|
@@ -58,6 +58,10 @@ export const STOREFRONT_DESIGN_SETTINGS = {
|
|
|
58
58
|
layoutDensity: choice('layoutDensity', ['comfortable', 'dense'], 'comfortable', 'Densidad', 'Elegí cuánto espacio dejás entre los elementos de toda la tienda.'),
|
|
59
59
|
showBrand: toggle('showBrand', false, 'Mostrar marca', 'Mostrar la marca en las tarjetas de productos.'),
|
|
60
60
|
showSku: toggle('showSku', false, 'Mostrar SKU', 'Mostrar el código SKU en las tarjetas de productos.'),
|
|
61
|
+
showTierHint: toggle('showTierHint', true, 'Mostrar precios por cantidad', 'Muestra en las tarjetas el aviso de precio por cantidad, cuando el producto lo tiene.'),
|
|
62
|
+
showCompareAt: toggle('showCompareAt', true, 'Mostrar precio anterior', 'Muestra en las tarjetas el precio anterior tachado, cuando el producto lo tiene.'),
|
|
63
|
+
showStockBadge: toggle('showStockBadge', true, 'Mostrar avisos de stock', 'Oculta los avisos de stock en las tarjetas. Si la tienda oculta las cantidades, este ajuste no las muestra.'),
|
|
64
|
+
showQuickAdd: toggle('showQuickAdd', true, 'Mostrar botón Agregar', 'Muestra el botón Agregar en las tarjetas. Las filas de productos siempre lo muestran.'),
|
|
61
65
|
};
|
|
62
66
|
export const isStorefrontDesignSettingKey = (key) => Object.hasOwn(STOREFRONT_DESIGN_SETTINGS, key);
|
|
63
67
|
export const validateStorefrontSettingValue = (schema, value) => {
|