sinfactura-types 1.10.576 → 1.10.577

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.
@@ -7,14 +7,24 @@
7
7
  * products of the store, and how many of each, make up one unit. It never
8
8
  * carries a price, a tax rate or a stock figure, and saving one moves no stock.
9
9
  *
10
- * ⚠️ Kit SALES do not exist yet. While a product holds an `active` recipe it is
11
- * refused as a new or increased sale line on every channel (counter, storefront,
12
- * service, marketplace) with the shared `409 PRODUCT_NOT_AVAILABLE`, with stock
13
- * control on or off, and it cannot be linked to or reactivated on MercadoLibre.
14
- * Retiring the recipe makes it an ordinary product again.
10
+ * A kit with an `active` recipe sells only on the channels in
11
+ * `KIT_SALE_CHANNELS`. There the order keeps ONE priced line for the kit, while
12
+ * the sale consumes the recipe's components from stock, and the line freezes the
13
+ * recipe it consumed (`OrderLine.kit`). Cancelling or returning that line gives
14
+ * back exactly the frozen components, whatever the recipe says later. Every
15
+ * other channel (storefront, service, marketplace, quote conversion) refuses an
16
+ * active kit with the shared `409 PRODUCT_NOT_AVAILABLE`, with stock control on
17
+ * or off, and it cannot be linked to or reactivated on MercadoLibre. Retiring
18
+ * the recipe makes it an ordinary product again.
15
19
  */
16
20
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.KIT_COMPONENT_MAX_QUANTITY = exports.KIT_RECIPE_MAX_COMPONENTS = void 0;
21
+ exports.KIT_COMPONENT_MAX_QUANTITY = exports.KIT_RECIPE_MAX_COMPONENTS = exports.KIT_SALE_CHANNELS = void 0;
22
+ /**
23
+ * The channels that sell a kit by consuming its components. Only the counter
24
+ * (the operator basket and `POST /orders`, which the app's POS and the mobile
25
+ * app share) does today.
26
+ */
27
+ exports.KIT_SALE_CHANNELS = ['counter'];
18
28
  /**
19
29
  * Most components one recipe names. A save commits the kit, its new revision and
20
30
  * every component's usage row in ONE transaction, so this is bounded by
package/dist/cjs/order.js CHANGED
@@ -251,6 +251,11 @@ exports.orderFulfilmentProgress = orderFulfilmentProgress;
251
251
  * `mode: 'deposit-refund'`, see `OrderDepositRefundRequest`. Nothing was
252
252
  * written. `DEPOSIT_ALREADY_REFUNDED`'s `data` carries
253
253
  * `OrderDepositRefundManualData` when the refund on the ledger was non-cash.
254
+ * - `KIT_RECIPE_CHANGED` · 409 — a counter sale of a kit whose recipe was
255
+ * saved again or retired after the sale read it; `productIds` names the kits.
256
+ * Nothing was written; re-read the basket and retry.
257
+ * - `ORDER_HAS_KIT_LINES` · 409 — `mode: 'edit'` on an order holding a kit line
258
+ * (`CartLine.kit`). Cancel or return the order instead. Nothing was written.
254
259
  *
255
260
  * Shipment refusals (`mode: 'shipment' | 'shipment-void'`), nothing written on
256
261
  * any of them:
@@ -359,4 +364,8 @@ exports.ORDER_ERROR_CODES = [
359
364
  // `POST /orders { mode: 'deposit-refund' }` — see `OrderDepositRefundRequest`.
360
365
  'DEPOSIT_NOT_FOUND',
361
366
  'DEPOSIT_ALREADY_REFUNDED',
367
+ // A kit's recipe changed or was retired between reading it and the sale's commit.
368
+ 'KIT_RECIPE_CHANGED',
369
+ // `mode: 'edit'` on an order holding a kit line; cancel or return it instead.
370
+ 'ORDER_HAS_KIT_LINES',
362
371
  ];
@@ -6,12 +6,22 @@
6
6
  * products of the store, and how many of each, make up one unit. It never
7
7
  * carries a price, a tax rate or a stock figure, and saving one moves no stock.
8
8
  *
9
- * ⚠️ Kit SALES do not exist yet. While a product holds an `active` recipe it is
10
- * refused as a new or increased sale line on every channel (counter, storefront,
11
- * service, marketplace) with the shared `409 PRODUCT_NOT_AVAILABLE`, with stock
12
- * control on or off, and it cannot be linked to or reactivated on MercadoLibre.
13
- * Retiring the recipe makes it an ordinary product again.
9
+ * A kit with an `active` recipe sells only on the channels in
10
+ * `KIT_SALE_CHANNELS`. There the order keeps ONE priced line for the kit, while
11
+ * the sale consumes the recipe's components from stock, and the line freezes the
12
+ * recipe it consumed (`OrderLine.kit`). Cancelling or returning that line gives
13
+ * back exactly the frozen components, whatever the recipe says later. Every
14
+ * other channel (storefront, service, marketplace, quote conversion) refuses an
15
+ * active kit with the shared `409 PRODUCT_NOT_AVAILABLE`, with stock control on
16
+ * or off, and it cannot be linked to or reactivated on MercadoLibre. Retiring
17
+ * the recipe makes it an ordinary product again.
14
18
  */
19
+ /**
20
+ * The channels that sell a kit by consuming its components. Only the counter
21
+ * (the operator basket and `POST /orders`, which the app's POS and the mobile
22
+ * app share) does today.
23
+ */
24
+ export declare const KIT_SALE_CHANNELS: readonly ["counter"];
15
25
  /**
16
26
  * Most components one recipe names. A save commits the kit, its new revision and
17
27
  * every component's usage row in ONE transaction, so this is bounded by
@@ -22,13 +32,19 @@ export declare const KIT_RECIPE_MAX_COMPONENTS = 30;
22
32
  export declare const KIT_COMPONENT_MAX_QUANTITY = 1000000;
23
33
  declare global {
24
34
  /**
25
- * - `active` — the product is a kit and is sold nowhere until kit sales exist.
35
+ * - `active` — the product is a kit, sold only on `KIT_SALE_CHANNELS`.
26
36
  * - `retired` — the recipe was withdrawn; the product is an ordinary product
27
37
  * again. Its revisions stay readable.
28
38
  */
29
39
  type KitRecipeStatus = 'active' | 'retired';
30
- /** Whether the kit can be sold. Only `unsupported` exists today. */
31
- type KitSaleSupport = 'unsupported';
40
+ /**
41
+ * Where an active kit can be sold.
42
+ *
43
+ * - `channels` — on the channels `KitRecipeDetail.saleChannels` names, and
44
+ * refused on every other one.
45
+ * - `unsupported` — nowhere. Answered for a retired recipe.
46
+ */
47
+ type KitSaleSupport = 'channels' | 'unsupported';
32
48
  /**
33
49
  * `Product.kitRecipe` — where the product's recipe stands. Server-owned: only
34
50
  * `POST /catalog/kits` writes it, and `POST /products` drops it. Absent means
@@ -80,6 +96,34 @@ declare global {
80
96
  /** The kit's newest revision, to send as `expectedRevision`. */
81
97
  currentRevision: number;
82
98
  saleSupport: KitSaleSupport;
99
+ /** The channels that sell this kit. Empty when `saleSupport` is `unsupported`. */
100
+ saleChannels: SaleChannel[];
101
+ }
102
+ /**
103
+ * One component a kit line consumed, frozen on the order line at create.
104
+ */
105
+ interface OrderLineKitComponent {
106
+ productId: string;
107
+ /** Units consumed per kit unit, as the recipe said at the sale. */
108
+ quantity: number;
109
+ /**
110
+ * One unit's cost in the ORDER's currency, converted at the order's frozen
111
+ * rate. Absent when the component had no usable cost at the sale. The kit
112
+ * line's `cost` is the sum of these times `quantity`.
113
+ */
114
+ cost?: number;
115
+ }
116
+ /**
117
+ * `OrderLine.kit` — the recipe a kit line consumed, frozen at the sale.
118
+ * Server-owned and operator-only: only an order create on a kit sale channel
119
+ * writes it, a client-sent `kit` is dropped, and every shopper-facing copy
120
+ * omits it. Cancelling or returning the line reverses these components, never
121
+ * the kit's current recipe.
122
+ */
123
+ interface OrderLineKit {
124
+ /** The recipe revision the sale consumed. */
125
+ revision: number;
126
+ components: OrderLineKitComponent[];
83
127
  }
84
128
  /**
85
129
  * `POST /catalog/kits` `mode: 'save'` — writes a new active revision holding
package/dist/kitRecipe.js CHANGED
@@ -6,12 +6,22 @@
6
6
  * products of the store, and how many of each, make up one unit. It never
7
7
  * carries a price, a tax rate or a stock figure, and saving one moves no stock.
8
8
  *
9
- * ⚠️ Kit SALES do not exist yet. While a product holds an `active` recipe it is
10
- * refused as a new or increased sale line on every channel (counter, storefront,
11
- * service, marketplace) with the shared `409 PRODUCT_NOT_AVAILABLE`, with stock
12
- * control on or off, and it cannot be linked to or reactivated on MercadoLibre.
13
- * Retiring the recipe makes it an ordinary product again.
9
+ * A kit with an `active` recipe sells only on the channels in
10
+ * `KIT_SALE_CHANNELS`. There the order keeps ONE priced line for the kit, while
11
+ * the sale consumes the recipe's components from stock, and the line freezes the
12
+ * recipe it consumed (`OrderLine.kit`). Cancelling or returning that line gives
13
+ * back exactly the frozen components, whatever the recipe says later. Every
14
+ * other channel (storefront, service, marketplace, quote conversion) refuses an
15
+ * active kit with the shared `409 PRODUCT_NOT_AVAILABLE`, with stock control on
16
+ * or off, and it cannot be linked to or reactivated on MercadoLibre. Retiring
17
+ * the recipe makes it an ordinary product again.
14
18
  */
19
+ /**
20
+ * The channels that sell a kit by consuming its components. Only the counter
21
+ * (the operator basket and `POST /orders`, which the app's POS and the mobile
22
+ * app share) does today.
23
+ */
24
+ export const KIT_SALE_CHANNELS = ['counter'];
15
25
  /**
16
26
  * Most components one recipe names. A save commits the kit, its new revision and
17
27
  * every component's usage row in ONE transaction, so this is bounded by
package/dist/order.d.ts CHANGED
@@ -282,6 +282,19 @@ declare global {
282
282
  * shipments existed, forward-only, never backfilled.
283
283
  */
284
284
  fulfilledQuantity?: number;
285
+ /**
286
+ * The kit recipe this line consumed — see `OrderLineKit`. Present only on a
287
+ * line that sold an active kit on a kit sale channel.
288
+ *
289
+ * ⚠️ **Server-owned and operator-only.** Only the order create that froze
290
+ * it keeps it (`stripServerOwnedLineFields`), and every shopper-facing
291
+ * copy drops it, since it carries each component's cost.
292
+ *
293
+ * ⚠️ A line is a kit line because it CARRIES this, never because its
294
+ * product is a kit today: a product sold before its recipe existed reverses
295
+ * its own stock.
296
+ */
297
+ kit?: OrderLineKit;
285
298
  }
286
299
  /**
287
300
  * A shipment's lifecycle. A void marks the SHIPMENT row `voided` (kept as
@@ -2292,6 +2305,11 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
2292
2305
  * `mode: 'deposit-refund'`, see `OrderDepositRefundRequest`. Nothing was
2293
2306
  * written. `DEPOSIT_ALREADY_REFUNDED`'s `data` carries
2294
2307
  * `OrderDepositRefundManualData` when the refund on the ledger was non-cash.
2308
+ * - `KIT_RECIPE_CHANGED` · 409 — a counter sale of a kit whose recipe was
2309
+ * saved again or retired after the sale read it; `productIds` names the kits.
2310
+ * Nothing was written; re-read the basket and retry.
2311
+ * - `ORDER_HAS_KIT_LINES` · 409 — `mode: 'edit'` on an order holding a kit line
2312
+ * (`CartLine.kit`). Cancel or return the order instead. Nothing was written.
2295
2313
  *
2296
2314
  * Shipment refusals (`mode: 'shipment' | 'shipment-void'`), nothing written on
2297
2315
  * any of them:
@@ -2335,6 +2353,6 @@ export declare const orderFulfilmentProgress: (order: OrderFulfilmentProgressInp
2335
2353
  * `SUBSCRIPTION_READONLY`) sit on the order CREATE leg only: an edit is not a new
2336
2354
  * order, so `bareOrderPostHandler` routes past `requireMetered` entirely.
2337
2355
  */
2338
- 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_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED"];
2356
+ 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_REFERENCE_IS_LINKED_PAYMENT", "DEPOSIT_DUPLICATE_REFERENCE", "PAYMENT_REFERENCED_BY_DEPOSIT", "ORDER_HAS_UNREFUNDED_DEPOSIT", "DEPOSIT_NOT_FOUND", "DEPOSIT_ALREADY_REFUNDED", "KIT_RECIPE_CHANGED", "ORDER_HAS_KIT_LINES"];
2339
2357
  export type OrderErrorCode = (typeof ORDER_ERROR_CODES)[number];
2340
2358
  export {};
package/dist/order.js CHANGED
@@ -244,6 +244,11 @@ export const orderFulfilmentProgress = (order) => {
244
244
  * `mode: 'deposit-refund'`, see `OrderDepositRefundRequest`. Nothing was
245
245
  * written. `DEPOSIT_ALREADY_REFUNDED`'s `data` carries
246
246
  * `OrderDepositRefundManualData` when the refund on the ledger was non-cash.
247
+ * - `KIT_RECIPE_CHANGED` · 409 — a counter sale of a kit whose recipe was
248
+ * saved again or retired after the sale read it; `productIds` names the kits.
249
+ * Nothing was written; re-read the basket and retry.
250
+ * - `ORDER_HAS_KIT_LINES` · 409 — `mode: 'edit'` on an order holding a kit line
251
+ * (`CartLine.kit`). Cancel or return the order instead. Nothing was written.
247
252
  *
248
253
  * Shipment refusals (`mode: 'shipment' | 'shipment-void'`), nothing written on
249
254
  * any of them:
@@ -352,4 +357,8 @@ export const ORDER_ERROR_CODES = [
352
357
  // `POST /orders { mode: 'deposit-refund' }` — see `OrderDepositRefundRequest`.
353
358
  'DEPOSIT_NOT_FOUND',
354
359
  'DEPOSIT_ALREADY_REFUNDED',
360
+ // A kit's recipe changed or was retired between reading it and the sale's commit.
361
+ 'KIT_RECIPE_CHANGED',
362
+ // `mode: 'edit'` on an order holding a kit line; cancel or return it instead.
363
+ 'ORDER_HAS_KIT_LINES',
355
364
  ];
package/dist/product.d.ts CHANGED
@@ -670,12 +670,14 @@ declare global {
670
670
  * Where this product's kit recipe stands. Server-owned: only
671
671
  * `POST /catalog/kits` writes it, and `POST /products` drops it.
672
672
  *
673
- * `status: 'active'` makes the product a kit, and a kit is sold nowhere
674
- * yet: a new or increased sale line is refused `409 PRODUCT_NOT_AVAILABLE`
675
- * on every channel, with stock control on or off, and it cannot be linked to
676
- * or reactivated on MercadoLibre. Its own price, tax rate, `limit` and
677
- * stock are kept untouched. `retired`, or absent, is an ordinary product.
678
- * Operator-only: never in a shopper projection.
673
+ * `status: 'active'` makes the product a kit. A kit sells only on
674
+ * `KIT_SALE_CHANNELS`, where the sale prices it as one line and consumes its
675
+ * components from stock instead of its own `stock`. Every other channel
676
+ * refuses a new or increased sale line `409 PRODUCT_NOT_AVAILABLE`, with
677
+ * stock control on or off, and it cannot be linked to or reactivated on
678
+ * MercadoLibre. Its own price, tax rate and `limit` still apply to the
679
+ * kit line. `retired`, or absent, is an ordinary product. Operator-only:
680
+ * never in a shopper projection.
679
681
  */
680
682
  kitRecipe?: ProductKitRecipePointer;
681
683
  model?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sinfactura-types",
3
- "version": "1.10.576",
3
+ "version": "1.10.577",
4
4
  "description": "Shared wire and entity contracts for the SINFACTURA platform.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",