@fiado/type-kit 3.261.0 → 3.264.0

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.
Files changed (30) hide show
  1. package/bin/identity/dtos/PeopleResponse.d.ts +9 -0
  2. package/bin/retailCatalog/dtos/requests/InventoryLensQuery.d.ts +13 -0
  3. package/bin/retailCatalog/dtos/requests/InventoryLensQuery.js +30 -0
  4. package/bin/retailCatalog/dtos/responses/InventoryLensResponse.d.ts +106 -0
  5. package/bin/retailCatalog/dtos/responses/InventoryLensResponse.js +2 -0
  6. package/bin/retailCatalog/enums/InventoryLensFilterEnum.d.ts +21 -0
  7. package/bin/retailCatalog/enums/InventoryLensFilterEnum.js +25 -0
  8. package/bin/retailCatalog/enums/InventoryLensUnavailableReasonEnum.d.ts +14 -0
  9. package/bin/retailCatalog/enums/InventoryLensUnavailableReasonEnum.js +18 -0
  10. package/bin/retailCatalog/enums/InventoryTransferReasonEnum.d.ts +11 -0
  11. package/bin/retailCatalog/enums/InventoryTransferReasonEnum.js +15 -0
  12. package/bin/retailCatalog/index.d.ts +5 -0
  13. package/bin/retailCatalog/index.js +6 -0
  14. package/bin/retailWizard/events/SaleCancelledV2.d.ts +20 -0
  15. package/bin/retailWizard/events/SaleCancelledV2.js +2 -0
  16. package/bin/retailWizard/events/SaleCompletedV2.d.ts +41 -0
  17. package/bin/retailWizard/events/SaleCompletedV2.js +2 -0
  18. package/bin/retailWizard/index.d.ts +2 -0
  19. package/bin/retailWizard/index.js +2 -0
  20. package/package.json +1 -1
  21. package/src/identity/dtos/PeopleResponse.ts +9 -0
  22. package/src/retailCatalog/dtos/requests/InventoryLensQuery.ts +16 -0
  23. package/src/retailCatalog/dtos/responses/InventoryLensResponse.ts +123 -0
  24. package/src/retailCatalog/enums/InventoryLensFilterEnum.ts +21 -0
  25. package/src/retailCatalog/enums/InventoryLensUnavailableReasonEnum.ts +14 -0
  26. package/src/retailCatalog/enums/InventoryTransferReasonEnum.ts +11 -0
  27. package/src/retailCatalog/index.ts +7 -0
  28. package/src/retailWizard/events/SaleCancelledV2.ts +20 -0
  29. package/src/retailWizard/events/SaleCompletedV2.ts +42 -0
  30. package/src/retailWizard/index.ts +2 -0
@@ -102,7 +102,16 @@ export declare class PeopleResponse {
102
102
  externalReferenceId: string | null;
103
103
  SSN_ITINRequired: boolean | null;
104
104
  hasSSN_ITIN: boolean | null;
105
+ /**
106
+ * @deprecated Typo histórico (tres `p`). NADIE escribe este campo:
107
+ * fiado-identity-lambda persiste `geoApproved` (una `p`), que es lo que
108
+ * está en DynamoDB. Quien lea este campo obtiene siempre `undefined`.
109
+ * Usar `geoApproved`. Se conserva solo para no romper a los consumidores
110
+ * que todavía lo referencian.
111
+ */
105
112
  geoAppproved?: boolean | null;
113
+ /** Geolocalización aprobada. `null` = no evaluada; solo `false` bloquea. */
114
+ geoApproved?: boolean | null;
106
115
  cnbvManualApproval?: ManualApproval | null;
107
116
  minorManualApproval?: ManualApproval | null;
108
117
  };
@@ -0,0 +1,13 @@
1
+ import { InventoryLensFilterEnum } from '../../enums/InventoryLensFilterEnum';
2
+ /**
3
+ * Query string de `GET /backoffice/inventory/lens`. SureKeep Fase 3 — pista Retail.
4
+ *
5
+ * `filter` es **obligatorio** a propósito: no hay un tab «por defecto» razonable, y caer a uno en
6
+ * silencio le devolvería al front una vista que no pidió. Un filtro ausente o desconocido es un 400.
7
+ *
8
+ * No lleva `retailerId`: el scope del endpoint es LEVEL_1 y el retailer se **impone desde el token**,
9
+ * nunca se acepta del request (si viajara, sería un IDOR entre cadenas).
10
+ */
11
+ export declare class InventoryLensQuery {
12
+ filter: InventoryLensFilterEnum;
13
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.InventoryLensQuery = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ const InventoryLensFilterEnum_1 = require("../../enums/InventoryLensFilterEnum");
15
+ /**
16
+ * Query string de `GET /backoffice/inventory/lens`. SureKeep Fase 3 — pista Retail.
17
+ *
18
+ * `filter` es **obligatorio** a propósito: no hay un tab «por defecto» razonable, y caer a uno en
19
+ * silencio le devolvería al front una vista que no pidió. Un filtro ausente o desconocido es un 400.
20
+ *
21
+ * No lleva `retailerId`: el scope del endpoint es LEVEL_1 y el retailer se **impone desde el token**,
22
+ * nunca se acepta del request (si viajara, sería un IDOR entre cadenas).
23
+ */
24
+ class InventoryLensQuery {
25
+ }
26
+ exports.InventoryLensQuery = InventoryLensQuery;
27
+ __decorate([
28
+ (0, class_validator_1.IsEnum)(InventoryLensFilterEnum_1.InventoryLensFilterEnum),
29
+ __metadata("design:type", String)
30
+ ], InventoryLensQuery.prototype, "filter", void 0);
@@ -0,0 +1,106 @@
1
+ import type { InventoryLensFilterEnum } from '../../enums/InventoryLensFilterEnum';
2
+ import type { InventoryLensUnavailableReasonEnum } from '../../enums/InventoryLensUnavailableReasonEnum';
3
+ import type { InventoryTransferReasonEnum } from '../../enums/InventoryTransferReasonEnum';
4
+ /**
5
+ * Los contadores que la pantalla «Inventario» del Admin VL pinta arriba, siempre — los cuatro viajan
6
+ * con cualquier `filter`, porque las tarjetas no cambian al cambiar de tab.
7
+ * SureKeep Fase 3 — pista Retail.
8
+ *
9
+ * ⚠️ **No hay contador de `gap`.** El mockup pinta cinco tarjetas, pero la quinta compara contra las
10
+ * ventas de LUGA (INT6) y no se puede calcular. Se omite en vez de mandar un cero mentiroso.
11
+ */
12
+ export interface InventoryLensCounters {
13
+ /** Unidades `AVAILABLE` del retailer, sumadas sobre todas las tiendas. */
14
+ totalStock: number;
15
+ /** SKUs distintos del catálogo del retailer — el subtítulo de la tarjeta de stock. */
16
+ distinctSkus: number;
17
+ /** Pares (SKU, tienda) en stock crítico. */
18
+ critical: number;
19
+ /** Pares (SKU, tienda) sin rotación o recién llegados sin venta. */
20
+ stale: number;
21
+ /** Traspasos sugeridos entre tiendas. */
22
+ transfers: number;
23
+ }
24
+ /**
25
+ * Una fila de los tabs `critical` y `stale`: un SKU **en una tienda concreta**. El mismo SKU aparece
26
+ * una vez por cada tienda donde vive, porque la acción (traspasar, promocionar) es por tienda.
27
+ */
28
+ export interface InventoryLensSkuItem {
29
+ sku: string;
30
+ productId: string;
31
+ brand: string;
32
+ model: string;
33
+ capacity: string;
34
+ storeId: string;
35
+ /** Unidades `AVAILABLE` de este SKU en esta tienda. */
36
+ stock: number;
37
+ /**
38
+ * Días sin vender este SKU, medidos sobre **todo el retailer** (no por tienda) — es la definición
39
+ * del mockup, donde la rotación es un atributo del producto.
40
+ *
41
+ * Si el SKU nunca se vendió no hay `soldAt` del que restar: se cae a los días desde el ingreso más
42
+ * antiguo del SKU en el retailer, que es la cota inferior honesta de «cuánto lleva sin venderse».
43
+ */
44
+ rotationDays: number;
45
+ /** Días desde que este SKU entró a ESTA tienda (el lote más reciente). */
46
+ daysSinceArrival: number;
47
+ /** Fecha ISO-8601 de ese ingreso. */
48
+ arrivedAt: string;
49
+ /** El lote llegó hace menos de 7 días. */
50
+ recentArrival: boolean;
51
+ /** `rotationDays > 90`. */
52
+ noRotation90d: boolean;
53
+ /** No hubo ninguna venta del SKU posterior a su ingreso a esta tienda. */
54
+ noSaleSinceArrival: boolean;
55
+ /** `0 < stock < 3`. */
56
+ criticalStock: boolean;
57
+ /** Unidades de este SKU vendidas hoy en esta tienda, **financiadas por SureKeep**. */
58
+ soldTodayUnits: number;
59
+ /** Precio de contado en centavos (`listPriceCents`, o `basePriceCents` si no hay lista). */
60
+ cashPriceCents: number;
61
+ }
62
+ /** Una fila del tab `transfers`: mover unidades de un SKU de una tienda con excedente a una en crítico. */
63
+ export interface InventoryLensTransferSuggestion {
64
+ sku: string;
65
+ productId: string;
66
+ brand: string;
67
+ model: string;
68
+ /** Tienda con excedente (≥ 5 unidades del SKU). */
69
+ fromStoreId: string;
70
+ fromStoreStock: number;
71
+ /** Tienda en stock crítico. */
72
+ toStoreId: string;
73
+ toStoreStock: number;
74
+ /** Unidades sugeridas: `min(floor(fromStoreStock / 3), 3)`. */
75
+ units: number;
76
+ reason: InventoryTransferReasonEnum;
77
+ }
78
+ /** Fila del lente — el tipo depende del tab pedido. */
79
+ export type InventoryLensItem = InventoryLensSkuItem | InventoryLensTransferSuggestion;
80
+ /**
81
+ * `GET /backoffice/inventory/lens?filter=…` — la pantalla «Inventario» del Portal Admin VentasLuga.
82
+ * SureKeep Fase 3 — pista Retail.
83
+ *
84
+ * Es una **lente, no un clon** (D11): se sirve de solo lectura sobre el inventario propio y ninguna
85
+ * acción de la pantalla muta nada — los botones son deep links al ERP de LUGA. El inventario lo mueve
86
+ * La Central, no SureKeep.
87
+ *
88
+ * `counters` viaja siempre, con cualquier `filter`. `items` trae el tab pedido.
89
+ */
90
+ export interface InventoryLensResponse {
91
+ /** El tab que se resolvió — eco del query, para que el front no se confunda de pestaña. */
92
+ filter: InventoryLensFilterEnum;
93
+ counters: InventoryLensCounters;
94
+ /** Filas del tab. Vacío cuando `unavailable` es `true`. */
95
+ items: InventoryLensItem[];
96
+ /**
97
+ * `true` cuando el tab **no se puede calcular** (hoy solo `filter=gap`).
98
+ *
99
+ * ⚠️ El front DEBE distinguirlo de una lista vacía normal: `unavailable: true` significa «este
100
+ * comparativo necesita la integración con La Central», no «no hay gap». Pintar un cero acá sería
101
+ * dar por buena una medición que nunca se hizo.
102
+ */
103
+ unavailable?: boolean;
104
+ /** Por qué no se pudo. Presente solo junto a `unavailable: true`. */
105
+ reason?: InventoryLensUnavailableReasonEnum;
106
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Los cuatro tabs de la pantalla «Inventario» del Portal Admin VentasLuga (B-INV).
3
+ * SureKeep Fase 3 — pista Retail.
4
+ *
5
+ * El valor viaja como query string en `GET /backoffice/inventory/lens?filter=…`, así que son las
6
+ * cadenas literales del mockup, no SCREAMING_CASE.
7
+ *
8
+ * ⚠️ `GAP` está en el contrato pero **no se puede calcular**: compara las ventas de LUGA contra las
9
+ * que financia SureKeep, y el lado LUGA llega por La Central (INT6), cuyo spec todavía no existe.
10
+ * El endpoint lo acepta y responde con `unavailable: true` — ver `InventoryLensResponse`.
11
+ */
12
+ export declare enum InventoryLensFilterEnum {
13
+ /** SKUs con stock por agotarse en una tienda. */
14
+ CRITICAL = "critical",
15
+ /** SKUs sin rotación, o recién llegados que todavía no venden. */
16
+ STALE = "stale",
17
+ /** Top vendidos en LUGA que SureKeep no financia. **No disponible** (INT6). */
18
+ GAP = "gap",
19
+ /** Desbalance de stock del mismo SKU entre tiendas. */
20
+ TRANSFERS = "transfers"
21
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InventoryLensFilterEnum = void 0;
4
+ /**
5
+ * Los cuatro tabs de la pantalla «Inventario» del Portal Admin VentasLuga (B-INV).
6
+ * SureKeep Fase 3 — pista Retail.
7
+ *
8
+ * El valor viaja como query string en `GET /backoffice/inventory/lens?filter=…`, así que son las
9
+ * cadenas literales del mockup, no SCREAMING_CASE.
10
+ *
11
+ * ⚠️ `GAP` está en el contrato pero **no se puede calcular**: compara las ventas de LUGA contra las
12
+ * que financia SureKeep, y el lado LUGA llega por La Central (INT6), cuyo spec todavía no existe.
13
+ * El endpoint lo acepta y responde con `unavailable: true` — ver `InventoryLensResponse`.
14
+ */
15
+ var InventoryLensFilterEnum;
16
+ (function (InventoryLensFilterEnum) {
17
+ /** SKUs con stock por agotarse en una tienda. */
18
+ InventoryLensFilterEnum["CRITICAL"] = "critical";
19
+ /** SKUs sin rotación, o recién llegados que todavía no venden. */
20
+ InventoryLensFilterEnum["STALE"] = "stale";
21
+ /** Top vendidos en LUGA que SureKeep no financia. **No disponible** (INT6). */
22
+ InventoryLensFilterEnum["GAP"] = "gap";
23
+ /** Desbalance de stock del mismo SKU entre tiendas. */
24
+ InventoryLensFilterEnum["TRANSFERS"] = "transfers";
25
+ })(InventoryLensFilterEnum || (exports.InventoryLensFilterEnum = InventoryLensFilterEnum = {}));
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Por qué un tab del lente de inventario no se puede calcular. SureKeep Fase 3 — pista Retail.
3
+ *
4
+ * Existe para que el front distinga **«no lo puedo calcular»** de **«calculé y dio cero»**. Un tab
5
+ * que no se puede servir viaja con `items: []` + `unavailable: true` + este motivo; sin él, el cero
6
+ * se leería como un dato bueno y la pantalla mentiría.
7
+ */
8
+ export declare enum InventoryLensUnavailableReasonEnum {
9
+ /**
10
+ * El tab necesita las ventas de LUGA, que llegan por La Central (INT6). La integración no está
11
+ * especificada todavía, así que el dato no existe — no es que valga cero.
12
+ */
13
+ INT6_NOT_AVAILABLE = "INT6_NOT_AVAILABLE"
14
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InventoryLensUnavailableReasonEnum = void 0;
4
+ /**
5
+ * Por qué un tab del lente de inventario no se puede calcular. SureKeep Fase 3 — pista Retail.
6
+ *
7
+ * Existe para que el front distinga **«no lo puedo calcular»** de **«calculé y dio cero»**. Un tab
8
+ * que no se puede servir viaja con `items: []` + `unavailable: true` + este motivo; sin él, el cero
9
+ * se leería como un dato bueno y la pantalla mentiría.
10
+ */
11
+ var InventoryLensUnavailableReasonEnum;
12
+ (function (InventoryLensUnavailableReasonEnum) {
13
+ /**
14
+ * El tab necesita las ventas de LUGA, que llegan por La Central (INT6). La integración no está
15
+ * especificada todavía, así que el dato no existe — no es que valga cero.
16
+ */
17
+ InventoryLensUnavailableReasonEnum["INT6_NOT_AVAILABLE"] = "INT6_NOT_AVAILABLE";
18
+ })(InventoryLensUnavailableReasonEnum || (exports.InventoryLensUnavailableReasonEnum = InventoryLensUnavailableReasonEnum = {}));
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Motivo por el que el lente sugiere mover unidades de una tienda a otra. SureKeep Fase 3 — pista Retail.
3
+ *
4
+ * ⚠️ El mockup rotula el motivo como «Stock crítico + demanda hoy», pero la **demanda** sale de las
5
+ * ventas de LUGA (INT6, no disponible). Acá solo se declara la mitad que sí se puede probar con
6
+ * datos propios: la tienda destino está en crítico y hay otra con excedente del mismo SKU.
7
+ */
8
+ export declare enum InventoryTransferReasonEnum {
9
+ /** El destino tiene stock crítico y el origen tiene excedente del mismo SKU. */
10
+ CRITICAL_STOCK_AT_DESTINATION = "CRITICAL_STOCK_AT_DESTINATION"
11
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InventoryTransferReasonEnum = void 0;
4
+ /**
5
+ * Motivo por el que el lente sugiere mover unidades de una tienda a otra. SureKeep Fase 3 — pista Retail.
6
+ *
7
+ * ⚠️ El mockup rotula el motivo como «Stock crítico + demanda hoy», pero la **demanda** sale de las
8
+ * ventas de LUGA (INT6, no disponible). Acá solo se declara la mitad que sí se puede probar con
9
+ * datos propios: la tienda destino está en crítico y hay otra con excedente del mismo SKU.
10
+ */
11
+ var InventoryTransferReasonEnum;
12
+ (function (InventoryTransferReasonEnum) {
13
+ /** El destino tiene stock crítico y el origen tiene excedente del mismo SKU. */
14
+ InventoryTransferReasonEnum["CRITICAL_STOCK_AT_DESTINATION"] = "CRITICAL_STOCK_AT_DESTINATION";
15
+ })(InventoryTransferReasonEnum || (exports.InventoryTransferReasonEnum = InventoryTransferReasonEnum = {}));
@@ -3,6 +3,9 @@ export * from './enums/ProductStatusEnum';
3
3
  export * from './enums/InventoryItemStatusEnum';
4
4
  export * from './enums/MdmProviderEnum';
5
5
  export * from './enums/MdmLockModeEnum';
6
+ export * from './enums/InventoryLensFilterEnum';
7
+ export * from './enums/InventoryLensUnavailableReasonEnum';
8
+ export * from './enums/InventoryTransferReasonEnum';
6
9
  export * from './constants/SkuPattern';
7
10
  export * from './validators/IsMdmCoherentConstraint';
8
11
  export * from './dtos/Product';
@@ -14,9 +17,11 @@ export * from './dtos/requests/ListProductsQuery';
14
17
  export * from './dtos/requests/RegisterInventoryRequest';
15
18
  export * from './dtos/requests/TransferInventoryRequest';
16
19
  export * from './dtos/requests/ChangeInventoryStatusRequest';
20
+ export * from './dtos/requests/InventoryLensQuery';
17
21
  export * from './dtos/responses/ProductResponse';
18
22
  export * from './dtos/responses/InventoryItemResponse';
19
23
  export * from './dtos/responses/ImportCsvFailure';
20
24
  export * from './dtos/responses/ImportCsvResult';
25
+ export * from './dtos/responses/InventoryLensResponse';
21
26
  export * from './dtos/validation/ValidateProductResponse';
22
27
  export * from './dtos/validation/ValidateInventoryResponse';
@@ -19,6 +19,10 @@ __exportStar(require("./enums/ProductStatusEnum"), exports);
19
19
  __exportStar(require("./enums/InventoryItemStatusEnum"), exports);
20
20
  __exportStar(require("./enums/MdmProviderEnum"), exports);
21
21
  __exportStar(require("./enums/MdmLockModeEnum"), exports);
22
+ // F3 — lente de inventario del Portal Admin VentasLuga
23
+ __exportStar(require("./enums/InventoryLensFilterEnum"), exports);
24
+ __exportStar(require("./enums/InventoryLensUnavailableReasonEnum"), exports);
25
+ __exportStar(require("./enums/InventoryTransferReasonEnum"), exports);
22
26
  // Constantes del dominio
23
27
  __exportStar(require("./constants/SkuPattern"), exports);
24
28
  // Validators custom
@@ -34,11 +38,13 @@ __exportStar(require("./dtos/requests/ListProductsQuery"), exports);
34
38
  __exportStar(require("./dtos/requests/RegisterInventoryRequest"), exports);
35
39
  __exportStar(require("./dtos/requests/TransferInventoryRequest"), exports);
36
40
  __exportStar(require("./dtos/requests/ChangeInventoryStatusRequest"), exports);
41
+ __exportStar(require("./dtos/requests/InventoryLensQuery"), exports);
37
42
  // Response DTOs
38
43
  __exportStar(require("./dtos/responses/ProductResponse"), exports);
39
44
  __exportStar(require("./dtos/responses/InventoryItemResponse"), exports);
40
45
  __exportStar(require("./dtos/responses/ImportCsvFailure"), exports);
41
46
  __exportStar(require("./dtos/responses/ImportCsvResult"), exports);
47
+ __exportStar(require("./dtos/responses/InventoryLensResponse"), exports);
42
48
  // Validation DTOs (shapes de endpoints privados)
43
49
  __exportStar(require("./dtos/validation/ValidateProductResponse"), exports);
44
50
  __exportStar(require("./dtos/validation/ValidateInventoryResponse"), exports);
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Emitido al cancelar una venta, en la MISMA `TransactWriteItems` de la cancelación.
3
+ * SureKeep Fase 3 — pista Retail.
4
+ *
5
+ * **La V1 NO se toca** (tiene consumers en producción). La V2 se emite además y es la que consume el
6
+ * motor de comisiones, que necesita el `sellerRetailUserId` para saber a QUIÉN revertirle la comisión
7
+ * y el `soldAt` para saber en qué CORTE se había liquidado.
8
+ *
9
+ * ⚠️ `tenantId` NO va en el payload: viaja en el sobre del outbox.
10
+ */
11
+ export interface SaleCancelledV2 {
12
+ saleId: string;
13
+ /** A quién se le revierte la comisión. */
14
+ sellerRetailUserId: string;
15
+ /** Fecha de la venta ORIGINAL — identifica el corte en el que se había liquidado. */
16
+ soldAt: string;
17
+ reason: string;
18
+ cancelledAt: string;
19
+ occurredAt: string;
20
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,41 @@
1
+ import type { SaleTypeEnum } from '../enums/SaleTypeEnum';
2
+ import type { ExternalProviderEnum } from '../enums/ExternalProviderEnum';
3
+ /**
4
+ * Emitido al cerrar una venta, en la MISMA `TransactWriteItems` del cierre (patrón Outbox).
5
+ * SureKeep Fase 3 — pista Retail.
6
+ *
7
+ * **La V1 NO se toca:** ya tiene consumers en producción (La Central, datalake). La V2 se emite
8
+ * ADEMÁS, en la misma transacción, y es la que consume el motor de comisiones — que necesita saber
9
+ * QUIÉN vendió (`sellerRetailUserId`), CÓMO se financió (`type` + `externalProvider`) y de qué MARCA
10
+ * era el equipo (`brand`), tres datos que la V1 no lleva.
11
+ *
12
+ * ⚠️ `tenantId` NO va en el payload: ya viaja en el sobre del outbox (`OutboxEventPublisher`).
13
+ * Duplicarlo abriría la puerta a que los dos discrepen.
14
+ *
15
+ * ⚠️ NO hay `lines[]`: una `RetailSale` es de UN solo producto (D16) y se comisiona la venta, no un
16
+ * renglón. Modelarlo como array sugeriría un carrito que el wizard no tiene.
17
+ */
18
+ export interface SaleCompletedV2 {
19
+ saleId: string;
20
+ folio: string;
21
+ retailerId: string;
22
+ storeId: string;
23
+ /** Quién vendió — el eje del cálculo de comisión. Es lo que más falta en la V1. */
24
+ sellerRetailUserId: string;
25
+ retailCustomerId: string;
26
+ sku: string;
27
+ /** Marca del equipo, del snapshot congelado al cerrar. `null` si no se pudo resolver. */
28
+ brand: string | null;
29
+ imei: string | null;
30
+ /** Lo COBRADO en caja. En contado == precio del equipo; en CREDIT es SOLO el enganche. */
31
+ amountCents: number;
32
+ /** Precio de lista del equipo — la base de comisión. `null` en ventas sin el dato. */
33
+ equipmentPriceCents: number | null;
34
+ downPaymentCents: number | null;
35
+ creditId: string | null;
36
+ type: SaleTypeEnum;
37
+ /** Proveedor externo cuando `type = EXTERNAL_REFERRAL`; `null` en contado y crédito propio. */
38
+ externalProvider: ExternalProviderEnum | null;
39
+ soldAt: string;
40
+ occurredAt: string;
41
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -92,4 +92,6 @@ export * from './dtos/responses/BackofficeSalesKpisResponse';
92
92
  export * from './dtos/responses/BackofficeReportsResponse';
93
93
  export * from './events/SaleCompletedV1';
94
94
  export * from './events/SaleCancelledV1';
95
+ export * from './events/SaleCompletedV2';
96
+ export * from './events/SaleCancelledV2';
95
97
  export * from './events/SessionExpiredV1';
@@ -121,4 +121,6 @@ __exportStar(require("./dtos/responses/BackofficeReportsResponse"), exports);
121
121
  // Contratos de eventos (PascalCase + sufijo V1)
122
122
  __exportStar(require("./events/SaleCompletedV1"), exports);
123
123
  __exportStar(require("./events/SaleCancelledV1"), exports);
124
+ __exportStar(require("./events/SaleCompletedV2"), exports);
125
+ __exportStar(require("./events/SaleCancelledV2"), exports);
124
126
  __exportStar(require("./events/SessionExpiredV1"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.261.0",
3
+ "version": "3.264.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -105,7 +105,16 @@ export class PeopleResponse {
105
105
  externalReferenceId:string | null;
106
106
  SSN_ITINRequired:boolean | null;
107
107
  hasSSN_ITIN:boolean | null;
108
+ /**
109
+ * @deprecated Typo histórico (tres `p`). NADIE escribe este campo:
110
+ * fiado-identity-lambda persiste `geoApproved` (una `p`), que es lo que
111
+ * está en DynamoDB. Quien lea este campo obtiene siempre `undefined`.
112
+ * Usar `geoApproved`. Se conserva solo para no romper a los consumidores
113
+ * que todavía lo referencian.
114
+ */
108
115
  geoAppproved?:boolean | null;
116
+ /** Geolocalización aprobada. `null` = no evaluada; solo `false` bloquea. */
117
+ geoApproved?:boolean | null;
109
118
  cnbvManualApproval?: ManualApproval | null;
110
119
  minorManualApproval?: ManualApproval | null;
111
120
 
@@ -0,0 +1,16 @@
1
+ import { IsEnum } from 'class-validator';
2
+ import { InventoryLensFilterEnum } from '../../enums/InventoryLensFilterEnum';
3
+
4
+ /**
5
+ * Query string de `GET /backoffice/inventory/lens`. SureKeep Fase 3 — pista Retail.
6
+ *
7
+ * `filter` es **obligatorio** a propósito: no hay un tab «por defecto» razonable, y caer a uno en
8
+ * silencio le devolvería al front una vista que no pidió. Un filtro ausente o desconocido es un 400.
9
+ *
10
+ * No lleva `retailerId`: el scope del endpoint es LEVEL_1 y el retailer se **impone desde el token**,
11
+ * nunca se acepta del request (si viajara, sería un IDOR entre cadenas).
12
+ */
13
+ export class InventoryLensQuery {
14
+ @IsEnum(InventoryLensFilterEnum)
15
+ filter!: InventoryLensFilterEnum;
16
+ }
@@ -0,0 +1,123 @@
1
+ import type { InventoryLensFilterEnum } from '../../enums/InventoryLensFilterEnum';
2
+ import type { InventoryLensUnavailableReasonEnum } from '../../enums/InventoryLensUnavailableReasonEnum';
3
+ import type { InventoryTransferReasonEnum } from '../../enums/InventoryTransferReasonEnum';
4
+
5
+ /**
6
+ * Los contadores que la pantalla «Inventario» del Admin VL pinta arriba, siempre — los cuatro viajan
7
+ * con cualquier `filter`, porque las tarjetas no cambian al cambiar de tab.
8
+ * SureKeep Fase 3 — pista Retail.
9
+ *
10
+ * ⚠️ **No hay contador de `gap`.** El mockup pinta cinco tarjetas, pero la quinta compara contra las
11
+ * ventas de LUGA (INT6) y no se puede calcular. Se omite en vez de mandar un cero mentiroso.
12
+ */
13
+ export interface InventoryLensCounters {
14
+ /** Unidades `AVAILABLE` del retailer, sumadas sobre todas las tiendas. */
15
+ totalStock: number;
16
+ /** SKUs distintos del catálogo del retailer — el subtítulo de la tarjeta de stock. */
17
+ distinctSkus: number;
18
+ /** Pares (SKU, tienda) en stock crítico. */
19
+ critical: number;
20
+ /** Pares (SKU, tienda) sin rotación o recién llegados sin venta. */
21
+ stale: number;
22
+ /** Traspasos sugeridos entre tiendas. */
23
+ transfers: number;
24
+ }
25
+
26
+ /**
27
+ * Una fila de los tabs `critical` y `stale`: un SKU **en una tienda concreta**. El mismo SKU aparece
28
+ * una vez por cada tienda donde vive, porque la acción (traspasar, promocionar) es por tienda.
29
+ */
30
+ export interface InventoryLensSkuItem {
31
+ sku: string;
32
+ productId: string;
33
+ brand: string;
34
+ model: string;
35
+ capacity: string;
36
+ storeId: string;
37
+
38
+ /** Unidades `AVAILABLE` de este SKU en esta tienda. */
39
+ stock: number;
40
+
41
+ /**
42
+ * Días sin vender este SKU, medidos sobre **todo el retailer** (no por tienda) — es la definición
43
+ * del mockup, donde la rotación es un atributo del producto.
44
+ *
45
+ * Si el SKU nunca se vendió no hay `soldAt` del que restar: se cae a los días desde el ingreso más
46
+ * antiguo del SKU en el retailer, que es la cota inferior honesta de «cuánto lleva sin venderse».
47
+ */
48
+ rotationDays: number;
49
+
50
+ /** Días desde que este SKU entró a ESTA tienda (el lote más reciente). */
51
+ daysSinceArrival: number;
52
+ /** Fecha ISO-8601 de ese ingreso. */
53
+ arrivedAt: string;
54
+
55
+ /** El lote llegó hace menos de 7 días. */
56
+ recentArrival: boolean;
57
+ /** `rotationDays > 90`. */
58
+ noRotation90d: boolean;
59
+ /** No hubo ninguna venta del SKU posterior a su ingreso a esta tienda. */
60
+ noSaleSinceArrival: boolean;
61
+ /** `0 < stock < 3`. */
62
+ criticalStock: boolean;
63
+
64
+ /** Unidades de este SKU vendidas hoy en esta tienda, **financiadas por SureKeep**. */
65
+ soldTodayUnits: number;
66
+
67
+ /** Precio de contado en centavos (`listPriceCents`, o `basePriceCents` si no hay lista). */
68
+ cashPriceCents: number;
69
+ }
70
+
71
+ /** Una fila del tab `transfers`: mover unidades de un SKU de una tienda con excedente a una en crítico. */
72
+ export interface InventoryLensTransferSuggestion {
73
+ sku: string;
74
+ productId: string;
75
+ brand: string;
76
+ model: string;
77
+
78
+ /** Tienda con excedente (≥ 5 unidades del SKU). */
79
+ fromStoreId: string;
80
+ fromStoreStock: number;
81
+ /** Tienda en stock crítico. */
82
+ toStoreId: string;
83
+ toStoreStock: number;
84
+
85
+ /** Unidades sugeridas: `min(floor(fromStoreStock / 3), 3)`. */
86
+ units: number;
87
+ reason: InventoryTransferReasonEnum;
88
+ }
89
+
90
+ /** Fila del lente — el tipo depende del tab pedido. */
91
+ export type InventoryLensItem = InventoryLensSkuItem | InventoryLensTransferSuggestion;
92
+
93
+ /**
94
+ * `GET /backoffice/inventory/lens?filter=…` — la pantalla «Inventario» del Portal Admin VentasLuga.
95
+ * SureKeep Fase 3 — pista Retail.
96
+ *
97
+ * Es una **lente, no un clon** (D11): se sirve de solo lectura sobre el inventario propio y ninguna
98
+ * acción de la pantalla muta nada — los botones son deep links al ERP de LUGA. El inventario lo mueve
99
+ * La Central, no SureKeep.
100
+ *
101
+ * `counters` viaja siempre, con cualquier `filter`. `items` trae el tab pedido.
102
+ */
103
+ export interface InventoryLensResponse {
104
+ /** El tab que se resolvió — eco del query, para que el front no se confunda de pestaña. */
105
+ filter: InventoryLensFilterEnum;
106
+
107
+ counters: InventoryLensCounters;
108
+
109
+ /** Filas del tab. Vacío cuando `unavailable` es `true`. */
110
+ items: InventoryLensItem[];
111
+
112
+ /**
113
+ * `true` cuando el tab **no se puede calcular** (hoy solo `filter=gap`).
114
+ *
115
+ * ⚠️ El front DEBE distinguirlo de una lista vacía normal: `unavailable: true` significa «este
116
+ * comparativo necesita la integración con La Central», no «no hay gap». Pintar un cero acá sería
117
+ * dar por buena una medición que nunca se hizo.
118
+ */
119
+ unavailable?: boolean;
120
+
121
+ /** Por qué no se pudo. Presente solo junto a `unavailable: true`. */
122
+ reason?: InventoryLensUnavailableReasonEnum;
123
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Los cuatro tabs de la pantalla «Inventario» del Portal Admin VentasLuga (B-INV).
3
+ * SureKeep Fase 3 — pista Retail.
4
+ *
5
+ * El valor viaja como query string en `GET /backoffice/inventory/lens?filter=…`, así que son las
6
+ * cadenas literales del mockup, no SCREAMING_CASE.
7
+ *
8
+ * ⚠️ `GAP` está en el contrato pero **no se puede calcular**: compara las ventas de LUGA contra las
9
+ * que financia SureKeep, y el lado LUGA llega por La Central (INT6), cuyo spec todavía no existe.
10
+ * El endpoint lo acepta y responde con `unavailable: true` — ver `InventoryLensResponse`.
11
+ */
12
+ export enum InventoryLensFilterEnum {
13
+ /** SKUs con stock por agotarse en una tienda. */
14
+ CRITICAL = 'critical',
15
+ /** SKUs sin rotación, o recién llegados que todavía no venden. */
16
+ STALE = 'stale',
17
+ /** Top vendidos en LUGA que SureKeep no financia. **No disponible** (INT6). */
18
+ GAP = 'gap',
19
+ /** Desbalance de stock del mismo SKU entre tiendas. */
20
+ TRANSFERS = 'transfers',
21
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Por qué un tab del lente de inventario no se puede calcular. SureKeep Fase 3 — pista Retail.
3
+ *
4
+ * Existe para que el front distinga **«no lo puedo calcular»** de **«calculé y dio cero»**. Un tab
5
+ * que no se puede servir viaja con `items: []` + `unavailable: true` + este motivo; sin él, el cero
6
+ * se leería como un dato bueno y la pantalla mentiría.
7
+ */
8
+ export enum InventoryLensUnavailableReasonEnum {
9
+ /**
10
+ * El tab necesita las ventas de LUGA, que llegan por La Central (INT6). La integración no está
11
+ * especificada todavía, así que el dato no existe — no es que valga cero.
12
+ */
13
+ INT6_NOT_AVAILABLE = 'INT6_NOT_AVAILABLE',
14
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Motivo por el que el lente sugiere mover unidades de una tienda a otra. SureKeep Fase 3 — pista Retail.
3
+ *
4
+ * ⚠️ El mockup rotula el motivo como «Stock crítico + demanda hoy», pero la **demanda** sale de las
5
+ * ventas de LUGA (INT6, no disponible). Acá solo se declara la mitad que sí se puede probar con
6
+ * datos propios: la tienda destino está en crítico y hay otra con excedente del mismo SKU.
7
+ */
8
+ export enum InventoryTransferReasonEnum {
9
+ /** El destino tiene stock crítico y el origen tiene excedente del mismo SKU. */
10
+ CRITICAL_STOCK_AT_DESTINATION = 'CRITICAL_STOCK_AT_DESTINATION',
11
+ }
@@ -4,6 +4,11 @@ export * from './enums/InventoryItemStatusEnum';
4
4
  export * from './enums/MdmProviderEnum';
5
5
  export * from './enums/MdmLockModeEnum';
6
6
 
7
+ // F3 — lente de inventario del Portal Admin VentasLuga
8
+ export * from './enums/InventoryLensFilterEnum';
9
+ export * from './enums/InventoryLensUnavailableReasonEnum';
10
+ export * from './enums/InventoryTransferReasonEnum';
11
+
7
12
  // Constantes del dominio
8
13
  export * from './constants/SkuPattern';
9
14
 
@@ -22,12 +27,14 @@ export * from './dtos/requests/ListProductsQuery';
22
27
  export * from './dtos/requests/RegisterInventoryRequest';
23
28
  export * from './dtos/requests/TransferInventoryRequest';
24
29
  export * from './dtos/requests/ChangeInventoryStatusRequest';
30
+ export * from './dtos/requests/InventoryLensQuery';
25
31
 
26
32
  // Response DTOs
27
33
  export * from './dtos/responses/ProductResponse';
28
34
  export * from './dtos/responses/InventoryItemResponse';
29
35
  export * from './dtos/responses/ImportCsvFailure';
30
36
  export * from './dtos/responses/ImportCsvResult';
37
+ export * from './dtos/responses/InventoryLensResponse';
31
38
 
32
39
  // Validation DTOs (shapes de endpoints privados)
33
40
  export * from './dtos/validation/ValidateProductResponse';
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Emitido al cancelar una venta, en la MISMA `TransactWriteItems` de la cancelación.
3
+ * SureKeep Fase 3 — pista Retail.
4
+ *
5
+ * **La V1 NO se toca** (tiene consumers en producción). La V2 se emite además y es la que consume el
6
+ * motor de comisiones, que necesita el `sellerRetailUserId` para saber a QUIÉN revertirle la comisión
7
+ * y el `soldAt` para saber en qué CORTE se había liquidado.
8
+ *
9
+ * ⚠️ `tenantId` NO va en el payload: viaja en el sobre del outbox.
10
+ */
11
+ export interface SaleCancelledV2 {
12
+ saleId: string;
13
+ /** A quién se le revierte la comisión. */
14
+ sellerRetailUserId: string;
15
+ /** Fecha de la venta ORIGINAL — identifica el corte en el que se había liquidado. */
16
+ soldAt: string;
17
+ reason: string;
18
+ cancelledAt: string;
19
+ occurredAt: string;
20
+ }
@@ -0,0 +1,42 @@
1
+ import type { SaleTypeEnum } from '../enums/SaleTypeEnum';
2
+ import type { ExternalProviderEnum } from '../enums/ExternalProviderEnum';
3
+
4
+ /**
5
+ * Emitido al cerrar una venta, en la MISMA `TransactWriteItems` del cierre (patrón Outbox).
6
+ * SureKeep Fase 3 — pista Retail.
7
+ *
8
+ * **La V1 NO se toca:** ya tiene consumers en producción (La Central, datalake). La V2 se emite
9
+ * ADEMÁS, en la misma transacción, y es la que consume el motor de comisiones — que necesita saber
10
+ * QUIÉN vendió (`sellerRetailUserId`), CÓMO se financió (`type` + `externalProvider`) y de qué MARCA
11
+ * era el equipo (`brand`), tres datos que la V1 no lleva.
12
+ *
13
+ * ⚠️ `tenantId` NO va en el payload: ya viaja en el sobre del outbox (`OutboxEventPublisher`).
14
+ * Duplicarlo abriría la puerta a que los dos discrepen.
15
+ *
16
+ * ⚠️ NO hay `lines[]`: una `RetailSale` es de UN solo producto (D16) y se comisiona la venta, no un
17
+ * renglón. Modelarlo como array sugeriría un carrito que el wizard no tiene.
18
+ */
19
+ export interface SaleCompletedV2 {
20
+ saleId: string;
21
+ folio: string;
22
+ retailerId: string;
23
+ storeId: string;
24
+ /** Quién vendió — el eje del cálculo de comisión. Es lo que más falta en la V1. */
25
+ sellerRetailUserId: string;
26
+ retailCustomerId: string;
27
+ sku: string;
28
+ /** Marca del equipo, del snapshot congelado al cerrar. `null` si no se pudo resolver. */
29
+ brand: string | null;
30
+ imei: string | null;
31
+ /** Lo COBRADO en caja. En contado == precio del equipo; en CREDIT es SOLO el enganche. */
32
+ amountCents: number;
33
+ /** Precio de lista del equipo — la base de comisión. `null` en ventas sin el dato. */
34
+ equipmentPriceCents: number | null;
35
+ downPaymentCents: number | null;
36
+ creditId: string | null;
37
+ type: SaleTypeEnum;
38
+ /** Proveedor externo cuando `type = EXTERNAL_REFERRAL`; `null` en contado y crédito propio. */
39
+ externalProvider: ExternalProviderEnum | null;
40
+ soldAt: string;
41
+ occurredAt: string;
42
+ }
@@ -116,4 +116,6 @@ export * from './dtos/responses/BackofficeReportsResponse';
116
116
  // Contratos de eventos (PascalCase + sufijo V1)
117
117
  export * from './events/SaleCompletedV1';
118
118
  export * from './events/SaleCancelledV1';
119
+ export * from './events/SaleCompletedV2';
120
+ export * from './events/SaleCancelledV2';
119
121
  export * from './events/SessionExpiredV1';