@fiado/type-kit 3.364.0 → 3.366.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 (33) hide show
  1. package/bin/loanCredit/dtos/requests/OriginateLoanCreditRequest.d.ts +8 -0
  2. package/bin/loanCredit/dtos/requests/OriginateLoanCreditRequest.js +12 -0
  3. package/bin/loanOfferings/dtos/PromotionEffect.d.ts +2 -2
  4. package/bin/loanOfferings/dtos/requests/CreatePromotionRequest.d.ts +2 -0
  5. package/bin/loanOfferings/dtos/requests/CreatePromotionRequest.js +7 -0
  6. package/bin/loanOfferings/dtos/requests/PromotionEffectInput.d.ts +2 -2
  7. package/bin/loanOfferings/dtos/requests/SimulateCreditPlanRequest.d.ts +8 -0
  8. package/bin/loanOfferings/dtos/requests/SimulateCreditPlanRequest.js +16 -0
  9. package/bin/loanOfferings/dtos/requests/UpdatePromotionRequest.d.ts +2 -0
  10. package/bin/loanOfferings/dtos/requests/UpdatePromotionRequest.js +7 -0
  11. package/bin/loanOfferings/dtos/responses/PromotionResponse.d.ts +2 -0
  12. package/bin/loanOfferings/dtos/responses/SimulationResultResponse.d.ts +18 -0
  13. package/bin/retailWizard/dtos/WizardSessionLookupEntry.d.ts +27 -0
  14. package/bin/retailWizard/dtos/WizardSessionLookupEntry.js +2 -0
  15. package/bin/retailWizard/dtos/responses/WizardSessionLookupResponse.d.ts +9 -0
  16. package/bin/retailWizard/dtos/responses/WizardSessionLookupResponse.js +2 -0
  17. package/bin/retailWizard/enums/WizardSessionLookupStatusEnum.d.ts +14 -0
  18. package/bin/retailWizard/enums/WizardSessionLookupStatusEnum.js +18 -0
  19. package/bin/retailWizard/index.d.ts +3 -0
  20. package/bin/retailWizard/index.js +4 -0
  21. package/package.json +1 -1
  22. package/src/loanCredit/dtos/requests/OriginateLoanCreditRequest.ts +16 -0
  23. package/src/loanOfferings/dtos/PromotionEffect.ts +2 -2
  24. package/src/loanOfferings/dtos/requests/CreatePromotionRequest.ts +7 -0
  25. package/src/loanOfferings/dtos/requests/PromotionEffectInput.ts +2 -2
  26. package/src/loanOfferings/dtos/requests/SimulateCreditPlanRequest.ts +17 -1
  27. package/src/loanOfferings/dtos/requests/UpdatePromotionRequest.ts +7 -0
  28. package/src/loanOfferings/dtos/responses/PromotionResponse.ts +2 -0
  29. package/src/loanOfferings/dtos/responses/SimulationResultResponse.ts +20 -0
  30. package/src/retailWizard/dtos/WizardSessionLookupEntry.ts +28 -0
  31. package/src/retailWizard/dtos/responses/WizardSessionLookupResponse.ts +10 -0
  32. package/src/retailWizard/enums/WizardSessionLookupStatusEnum.ts +14 -0
  33. package/src/retailWizard/index.ts +5 -0
@@ -28,4 +28,12 @@ export declare class OriginateLoanCreditRequest {
28
28
  clientLevelAtOrigination?: ClientLevelEnum;
29
29
  /** IMEI del equipo si ya se conoce (también puede fijarse en el paso 09 vía activate-check). */
30
30
  imei?: string;
31
+ /**
32
+ * Tienda donde se vende. El motor la persiste y la reenvía al simulador del catálogo en cada
33
+ * cotización — al RE-cotizar el wizard no la vuelve a mandar, así que sin guardarla la venta
34
+ * perdería su promoción a mitad del paso 06.
35
+ */
36
+ storeId?: string;
37
+ /** SKU del equipo, por el mismo motivo que `storeId`: resuelve promociones acotadas por producto. */
38
+ productSku?: string;
31
39
  }
@@ -89,3 +89,15 @@ __decorate([
89
89
  (0, class_validator_1.IsString)(),
90
90
  __metadata("design:type", String)
91
91
  ], OriginateLoanCreditRequest.prototype, "imei", void 0);
92
+ __decorate([
93
+ (0, class_transformer_1.Expose)(),
94
+ (0, class_validator_1.IsOptional)(),
95
+ (0, class_validator_1.IsString)(),
96
+ __metadata("design:type", String)
97
+ ], OriginateLoanCreditRequest.prototype, "storeId", void 0);
98
+ __decorate([
99
+ (0, class_transformer_1.Expose)(),
100
+ (0, class_validator_1.IsOptional)(),
101
+ (0, class_validator_1.IsString)(),
102
+ __metadata("design:type", String)
103
+ ], OriginateLoanCreditRequest.prototype, "productSku", void 0);
@@ -4,11 +4,11 @@
4
4
  * igual que `CreditPlan`.
5
5
  */
6
6
  export interface PromotionEffect {
7
- /** Puntos de enganche que se restan al mínimo del plan (decimal sobre 1: `0.05` = 5 puntos). */
7
+ /** Delta NEGATIVO sobre el enganche mínimo del plan (`-0.20` = veinte puntos menos). */
8
8
  downPaymentDeltaPct: number | null;
9
9
  /** Bono que se abona a la tarjeta PCF al activar el crédito. */
10
10
  pcfBonusCents: number | null;
11
- /** TNA que reemplaza a la del plan (decimal: `2.10` = 210%). */
11
+ /** TNA que reemplaza a la del plan, siempre hacia abajo (`1.80` = 180% en vez de 200%). */
12
12
  tnaOverride: number | null;
13
13
  /** Techo de monto financiable que reemplaza al del plan. */
14
14
  maxAmountOverrideCents: number | null;
@@ -14,6 +14,8 @@ export declare class CreatePromotionRequest {
14
14
  targetLevels: CreditPlanLevelEnum[];
15
15
  /** SKUs alcanzados; ausente o `null` = todos los productos. */
16
16
  productSkus?: string[] | null;
17
+ /** Tiendas alcanzadas. `null` o ausente = todas. */
18
+ storeIds?: string[] | null;
17
19
  validFrom?: string | null;
18
20
  validUntil?: string | null;
19
21
  /**
@@ -57,6 +57,13 @@ __decorate([
57
57
  (0, class_validator_1.IsString)({ each: true }),
58
58
  __metadata("design:type", Array)
59
59
  ], CreatePromotionRequest.prototype, "productSkus", void 0);
60
+ __decorate([
61
+ (0, class_transformer_1.Expose)(),
62
+ (0, class_validator_1.IsOptional)(),
63
+ (0, class_validator_1.IsArray)(),
64
+ (0, class_validator_1.IsString)({ each: true }),
65
+ __metadata("design:type", Array)
66
+ ], CreatePromotionRequest.prototype, "storeIds", void 0);
60
67
  __decorate([
61
68
  (0, class_transformer_1.Expose)(),
62
69
  (0, class_validator_1.IsOptional)(),
@@ -4,11 +4,11 @@
4
4
  * clave — las valida el lambda con 422: son reglas del negocio sobre un body bien formado.
5
5
  */
6
6
  export declare class PromotionEffectInput {
7
- /** Puntos de enganche a restar del mínimo del plan (decimal sobre 1). */
7
+ /** Delta NEGATIVO sobre el enganche mínimo (`-0.20` = veinte puntos menos); rango [-1, 0]. */
8
8
  downPaymentDeltaPct?: number | null;
9
9
  /** Bono a la tarjeta PCF, en cents. */
10
10
  pcfBonusCents?: number | null;
11
- /** TNA que reemplaza a la del plan (decimal); rango de negocio [2.00, 2.60]. */
11
+ /** TNA que reemplaza a la del plan, hacia abajo (`1.80` = 180%); rango [0, 2.60]. */
12
12
  tnaOverride?: number | null;
13
13
  /** Techo de monto financiable que reemplaza al del plan, en cents. */
14
14
  maxAmountOverrideCents?: number | null;
@@ -2,10 +2,18 @@
2
2
  * Body de POST /private/credit-plans/:planId/simulate y query de GET /credit-plans/:planId/simulator.
3
3
  * Entradas del simulador de cuota (flow 06 §6.1.4). `productPriceCents` en cents; `downPaymentPct`
4
4
  * decimal sobre 1. `customerSciScore` opcional: si viene, se valida contra el rango SCI del plan.
5
+ *
6
+ * `storeId` y `productSku` describen DÓNDE y QUÉ se está vendiendo: con ellos el simulador resuelve
7
+ * qué promoción aplica. Sin ellos, las promociones acotadas a una tienda o a un SKU quedan fuera —
8
+ * el simulador no adivina, y dar un beneficio que no corresponde es peor que no darlo.
5
9
  */
6
10
  export declare class SimulateCreditPlanRequest {
7
11
  productPriceCents: number;
8
12
  downPaymentPct: number;
9
13
  termWeeks: number;
10
14
  customerSciScore?: number;
15
+ /** Tienda donde se vende. Sin él no se resuelven las promociones acotadas por tienda. */
16
+ storeId?: string;
17
+ /** SKU del equipo. Sin él no se resuelven las promociones acotadas por producto. */
18
+ productSku?: string;
11
19
  }
@@ -16,6 +16,10 @@ const class_validator_1 = require("class-validator");
16
16
  * Body de POST /private/credit-plans/:planId/simulate y query de GET /credit-plans/:planId/simulator.
17
17
  * Entradas del simulador de cuota (flow 06 §6.1.4). `productPriceCents` en cents; `downPaymentPct`
18
18
  * decimal sobre 1. `customerSciScore` opcional: si viene, se valida contra el rango SCI del plan.
19
+ *
20
+ * `storeId` y `productSku` describen DÓNDE y QUÉ se está vendiendo: con ellos el simulador resuelve
21
+ * qué promoción aplica. Sin ellos, las promociones acotadas a una tienda o a un SKU quedan fuera —
22
+ * el simulador no adivina, y dar un beneficio que no corresponde es peor que no darlo.
19
23
  */
20
24
  class SimulateCreditPlanRequest {
21
25
  }
@@ -47,3 +51,15 @@ __decorate([
47
51
  (0, class_validator_1.Max)(100),
48
52
  __metadata("design:type", Number)
49
53
  ], SimulateCreditPlanRequest.prototype, "customerSciScore", void 0);
54
+ __decorate([
55
+ (0, class_transformer_1.Expose)(),
56
+ (0, class_validator_1.IsOptional)(),
57
+ (0, class_validator_1.IsString)(),
58
+ __metadata("design:type", String)
59
+ ], SimulateCreditPlanRequest.prototype, "storeId", void 0);
60
+ __decorate([
61
+ (0, class_transformer_1.Expose)(),
62
+ (0, class_validator_1.IsOptional)(),
63
+ (0, class_validator_1.IsString)(),
64
+ __metadata("design:type", String)
65
+ ], SimulateCreditPlanRequest.prototype, "productSku", void 0);
@@ -12,6 +12,8 @@ export declare class UpdatePromotionRequest {
12
12
  segmentId?: string;
13
13
  targetLevels?: CreditPlanLevelEnum[];
14
14
  productSkus?: string[] | null;
15
+ /** Tiendas alcanzadas. `null` o ausente = todas. */
16
+ storeIds?: string[] | null;
15
17
  validFrom?: string | null;
16
18
  validUntil?: string | null;
17
19
  budgetMaxCents?: number | null;
@@ -62,6 +62,13 @@ __decorate([
62
62
  (0, class_validator_1.IsString)({ each: true }),
63
63
  __metadata("design:type", Array)
64
64
  ], UpdatePromotionRequest.prototype, "productSkus", void 0);
65
+ __decorate([
66
+ (0, class_transformer_1.Expose)(),
67
+ (0, class_validator_1.IsOptional)(),
68
+ (0, class_validator_1.IsArray)(),
69
+ (0, class_validator_1.IsString)({ each: true }),
70
+ __metadata("design:type", Array)
71
+ ], UpdatePromotionRequest.prototype, "storeIds", void 0);
65
72
  __decorate([
66
73
  (0, class_transformer_1.Expose)(),
67
74
  (0, class_validator_1.IsOptional)(),
@@ -21,6 +21,8 @@ export interface PromotionResponse {
21
21
  targetLevels: CreditPlanLevelEnum[];
22
22
  /** `null` = alcanza a todos los productos. */
23
23
  productSkus: string[] | null;
24
+ /** `null` = alcanza a todas las tiendas. Dimensión «Tienda / canal» del alcance. */
25
+ storeIds: string[] | null;
24
26
  validFrom: string | null;
25
27
  validUntil: string | null;
26
28
  status: PromotionStatusEnum;
@@ -1,3 +1,4 @@
1
+ import { PromotionEffectKindEnum } from '../../enums/PromotionEffectKindEnum';
1
2
  /**
2
3
  * Un renglón de la tabla de amortización (M2 §3.3). Todos los montos en cents.
3
4
  */
@@ -13,6 +14,18 @@ export interface AmortizationRowResponse {
13
14
  /** Saldo insoluto de capital tras aplicar la cuota. */
14
15
  remainingBalanceCents: number;
15
16
  }
17
+ /**
18
+ * Promoción que el simulador aplicó a esta cotización. Sin este bloque la cuota cambia y nadie
19
+ * puede explicar por qué: es lo que hace auditable la regla de que gana una sola promoción.
20
+ */
21
+ export interface AppliedPromotionResponse {
22
+ promotionId: string;
23
+ name: string;
24
+ /** Versión de la promoción al cotizar — el operador la edita y sube. */
25
+ version: number;
26
+ /** Palancas del plan que la promoción pisó. */
27
+ appliedEffects: PromotionEffectKindEnum[];
28
+ }
16
29
  /**
17
30
  * Resultado del simulador de cuota (POST /private/credit-plans/:planId/simulate,
18
31
  * GET /credit-plans/:planId/simulator). Amortización francesa + IVA 16% + comisión de apertura + CAT.
@@ -41,4 +54,9 @@ export interface SimulationResultResponse {
41
54
  /** Costo Anual Total (decimal, ej. 2.87 = 287%). Metodología estándar CONDUSEF (supuesto). */
42
55
  catAnnual: number;
43
56
  schedule: AmortizationRowResponse[];
57
+ /**
58
+ * Promoción aplicada, o `null` si ninguna alcanzaba a esta venta. Los montos de arriba YA la
59
+ * incluyen: es el porqué de la cuota, no un extra a sumar.
60
+ */
61
+ appliedPromotion: AppliedPromotionResponse | null;
44
62
  }
@@ -0,0 +1,27 @@
1
+ import type { WizardSessionLookupStatusEnum } from '../enums/WizardSessionLookupStatusEnum';
2
+ import type { WizardStateEnum } from '../enums/WizardStateEnum';
3
+ import type { WizardStepEnum } from '../enums/WizardStepEnum';
4
+ /**
5
+ * Una entrada del lote de sesiones del wizard: traduce un `wizardSessionId` a la tienda, el cliente
6
+ * y el equipo de esa venta. Campo AUSENTE = «no lo se»; presente en `null` = dato afirmado como nulo.
7
+ */
8
+ export interface WizardSessionLookupEntry {
9
+ wizardSessionId: string;
10
+ status: WizardSessionLookupStatusEnum;
11
+ /** Todos los campos de abajo viajan SOLO con `status: OK`. */
12
+ retailerId?: string;
13
+ storeId?: string;
14
+ /** `null` mientras el KYC no haya dado de alta al cliente. */
15
+ retailCustomerId?: string | null;
16
+ state?: WizardStateEnum;
17
+ currentStep?: WizardStepEnum;
18
+ /** SKU del equipo reservado; `null` si la venta no llego al paso del producto. */
19
+ sku?: string | null;
20
+ /** Ficha comercial CONGELADA al reservar. `null` si no hay equipo reservado. */
21
+ productBrand?: string | null;
22
+ productModel?: string | null;
23
+ productCapacity?: string | null;
24
+ /** La venta que cerro esta sesion; `null` si todavia no cerro. */
25
+ saleId?: string | null;
26
+ folio?: string | null;
27
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,9 @@
1
+ import type { WizardSessionLookupEntry } from '../WizardSessionLookupEntry';
2
+ /**
3
+ * `GET /private/wizard-sessions/batch` — una entrada por cada id pedido, en el MISMO orden.
4
+ * `unavailableCount` hace ruidoso el resultado parcial: sin el, el caller no sabe que le falto algo.
5
+ */
6
+ export interface WizardSessionLookupResponse {
7
+ items: WizardSessionLookupEntry[];
8
+ unavailableCount: number;
9
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Como se resolvio cada id pedido a `GET /private/wizard-sessions/batch`. Hay una entrada por id.
3
+ * `NOT_FOUND` y `UNAVAILABLE` NO son lo mismo: colapsarlos afirma «no tiene» cuando fue «no se leyo».
4
+ */
5
+ export declare enum WizardSessionLookupStatusEnum {
6
+ /** La sesion existe y se leyo completa. */
7
+ OK = "OK",
8
+ /** No existe esa sesion en el silo. Es un dato POSITIVO, no una ausencia. */
9
+ NOT_FOUND = "NOT_FOUND",
10
+ /** No se pudo leer esa sesion. El caller reintenta SOLO ese id. */
11
+ UNAVAILABLE = "UNAVAILABLE",
12
+ /** Ese id no tiene forma de id. Reintentarlo nunca va a servir: el caller lo mando mal. */
13
+ INVALID_ID = "INVALID_ID"
14
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WizardSessionLookupStatusEnum = void 0;
4
+ /**
5
+ * Como se resolvio cada id pedido a `GET /private/wizard-sessions/batch`. Hay una entrada por id.
6
+ * `NOT_FOUND` y `UNAVAILABLE` NO son lo mismo: colapsarlos afirma «no tiene» cuando fue «no se leyo».
7
+ */
8
+ var WizardSessionLookupStatusEnum;
9
+ (function (WizardSessionLookupStatusEnum) {
10
+ /** La sesion existe y se leyo completa. */
11
+ WizardSessionLookupStatusEnum["OK"] = "OK";
12
+ /** No existe esa sesion en el silo. Es un dato POSITIVO, no una ausencia. */
13
+ WizardSessionLookupStatusEnum["NOT_FOUND"] = "NOT_FOUND";
14
+ /** No se pudo leer esa sesion. El caller reintenta SOLO ese id. */
15
+ WizardSessionLookupStatusEnum["UNAVAILABLE"] = "UNAVAILABLE";
16
+ /** Ese id no tiene forma de id. Reintentarlo nunca va a servir: el caller lo mando mal. */
17
+ WizardSessionLookupStatusEnum["INVALID_ID"] = "INVALID_ID";
18
+ })(WizardSessionLookupStatusEnum || (exports.WizardSessionLookupStatusEnum = WizardSessionLookupStatusEnum = {}));
@@ -121,3 +121,6 @@ export * from './events/SaleCancelledV1';
121
121
  export * from './events/SaleCompletedV2';
122
122
  export * from './events/SaleCancelledV2';
123
123
  export * from './events/SessionExpiredV1';
124
+ export * from './enums/WizardSessionLookupStatusEnum';
125
+ export * from './dtos/WizardSessionLookupEntry';
126
+ export * from './dtos/responses/WizardSessionLookupResponse';
@@ -152,3 +152,7 @@ __exportStar(require("./events/SaleCancelledV1"), exports);
152
152
  __exportStar(require("./events/SaleCompletedV2"), exports);
153
153
  __exportStar(require("./events/SaleCancelledV2"), exports);
154
154
  __exportStar(require("./events/SessionExpiredV1"), exports);
155
+ // Lookup privado por lote (GET /private/wizard-sessions/batch)
156
+ __exportStar(require("./enums/WizardSessionLookupStatusEnum"), exports);
157
+ __exportStar(require("./dtos/WizardSessionLookupEntry"), exports);
158
+ __exportStar(require("./dtos/responses/WizardSessionLookupResponse"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.364.0",
3
+ "version": "3.366.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -81,4 +81,20 @@ export class OriginateLoanCreditRequest {
81
81
  @IsOptional()
82
82
  @IsString()
83
83
  imei?: string;
84
+
85
+ /**
86
+ * Tienda donde se vende. El motor la persiste y la reenvía al simulador del catálogo en cada
87
+ * cotización — al RE-cotizar el wizard no la vuelve a mandar, así que sin guardarla la venta
88
+ * perdería su promoción a mitad del paso 06.
89
+ */
90
+ @Expose()
91
+ @IsOptional()
92
+ @IsString()
93
+ storeId?: string;
94
+
95
+ /** SKU del equipo, por el mismo motivo que `storeId`: resuelve promociones acotadas por producto. */
96
+ @Expose()
97
+ @IsOptional()
98
+ @IsString()
99
+ productSku?: string;
84
100
  }
@@ -4,11 +4,11 @@
4
4
  * igual que `CreditPlan`.
5
5
  */
6
6
  export interface PromotionEffect {
7
- /** Puntos de enganche que se restan al mínimo del plan (decimal sobre 1: `0.05` = 5 puntos). */
7
+ /** Delta NEGATIVO sobre el enganche mínimo del plan (`-0.20` = veinte puntos menos). */
8
8
  downPaymentDeltaPct: number | null;
9
9
  /** Bono que se abona a la tarjeta PCF al activar el crédito. */
10
10
  pcfBonusCents: number | null;
11
- /** TNA que reemplaza a la del plan (decimal: `2.10` = 210%). */
11
+ /** TNA que reemplaza a la del plan, siempre hacia abajo (`1.80` = 180% en vez de 200%). */
12
12
  tnaOverride: number | null;
13
13
  /** Techo de monto financiable que reemplaza al del plan. */
14
14
  maxAmountOverrideCents: number | null;
@@ -49,6 +49,13 @@ export class CreatePromotionRequest {
49
49
  @IsString({ each: true })
50
50
  productSkus?: string[] | null;
51
51
 
52
+ /** Tiendas alcanzadas. `null` o ausente = todas. */
53
+ @Expose()
54
+ @IsOptional()
55
+ @IsArray()
56
+ @IsString({ each: true })
57
+ storeIds?: string[] | null;
58
+
52
59
  @Expose()
53
60
  @IsOptional()
54
61
  @IsISO8601()
@@ -7,7 +7,7 @@ import { IsInt, IsNumber, IsOptional } from 'class-validator';
7
7
  * clave — las valida el lambda con 422: son reglas del negocio sobre un body bien formado.
8
8
  */
9
9
  export class PromotionEffectInput {
10
- /** Puntos de enganche a restar del mínimo del plan (decimal sobre 1). */
10
+ /** Delta NEGATIVO sobre el enganche mínimo (`-0.20` = veinte puntos menos); rango [-1, 0]. */
11
11
  @Expose()
12
12
  @IsOptional()
13
13
  @IsNumber()
@@ -19,7 +19,7 @@ export class PromotionEffectInput {
19
19
  @IsInt()
20
20
  pcfBonusCents?: number | null;
21
21
 
22
- /** TNA que reemplaza a la del plan (decimal); rango de negocio [2.00, 2.60]. */
22
+ /** TNA que reemplaza a la del plan, hacia abajo (`1.80` = 180%); rango [0, 2.60]. */
23
23
  @Expose()
24
24
  @IsOptional()
25
25
  @IsNumber()
@@ -1,10 +1,14 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsInt, IsNumber, IsOptional, Max, Min } from 'class-validator';
2
+ import { IsInt, IsNumber, IsOptional, IsString, Max, Min } from 'class-validator';
3
3
 
4
4
  /**
5
5
  * Body de POST /private/credit-plans/:planId/simulate y query de GET /credit-plans/:planId/simulator.
6
6
  * Entradas del simulador de cuota (flow 06 §6.1.4). `productPriceCents` en cents; `downPaymentPct`
7
7
  * decimal sobre 1. `customerSciScore` opcional: si viene, se valida contra el rango SCI del plan.
8
+ *
9
+ * `storeId` y `productSku` describen DÓNDE y QUÉ se está vendiendo: con ellos el simulador resuelve
10
+ * qué promoción aplica. Sin ellos, las promociones acotadas a una tienda o a un SKU quedan fuera —
11
+ * el simulador no adivina, y dar un beneficio que no corresponde es peor que no darlo.
8
12
  */
9
13
  export class SimulateCreditPlanRequest {
10
14
  @Expose()
@@ -29,4 +33,16 @@ export class SimulateCreditPlanRequest {
29
33
  @Min(0)
30
34
  @Max(100)
31
35
  customerSciScore?: number;
36
+
37
+ /** Tienda donde se vende. Sin él no se resuelven las promociones acotadas por tienda. */
38
+ @Expose()
39
+ @IsOptional()
40
+ @IsString()
41
+ storeId?: string;
42
+
43
+ /** SKU del equipo. Sin él no se resuelven las promociones acotadas por producto. */
44
+ @Expose()
45
+ @IsOptional()
46
+ @IsString()
47
+ productSku?: string;
32
48
  }
@@ -52,6 +52,13 @@ export class UpdatePromotionRequest {
52
52
  @IsString({ each: true })
53
53
  productSkus?: string[] | null;
54
54
 
55
+ /** Tiendas alcanzadas. `null` o ausente = todas. */
56
+ @Expose()
57
+ @IsOptional()
58
+ @IsArray()
59
+ @IsString({ each: true })
60
+ storeIds?: string[] | null;
61
+
55
62
  @Expose()
56
63
  @IsOptional()
57
64
  @IsISO8601()
@@ -22,6 +22,8 @@ export interface PromotionResponse {
22
22
  targetLevels: CreditPlanLevelEnum[];
23
23
  /** `null` = alcanza a todos los productos. */
24
24
  productSkus: string[] | null;
25
+ /** `null` = alcanza a todas las tiendas. Dimensión «Tienda / canal» del alcance. */
26
+ storeIds: string[] | null;
25
27
  validFrom: string | null;
26
28
  validUntil: string | null;
27
29
  status: PromotionStatusEnum;
@@ -1,3 +1,5 @@
1
+ import { PromotionEffectKindEnum } from '../../enums/PromotionEffectKindEnum';
2
+
1
3
  /**
2
4
  * Un renglón de la tabla de amortización (M2 §3.3). Todos los montos en cents.
3
5
  */
@@ -14,6 +16,19 @@ export interface AmortizationRowResponse {
14
16
  remainingBalanceCents: number;
15
17
  }
16
18
 
19
+ /**
20
+ * Promoción que el simulador aplicó a esta cotización. Sin este bloque la cuota cambia y nadie
21
+ * puede explicar por qué: es lo que hace auditable la regla de que gana una sola promoción.
22
+ */
23
+ export interface AppliedPromotionResponse {
24
+ promotionId: string;
25
+ name: string;
26
+ /** Versión de la promoción al cotizar — el operador la edita y sube. */
27
+ version: number;
28
+ /** Palancas del plan que la promoción pisó. */
29
+ appliedEffects: PromotionEffectKindEnum[];
30
+ }
31
+
17
32
  /**
18
33
  * Resultado del simulador de cuota (POST /private/credit-plans/:planId/simulate,
19
34
  * GET /credit-plans/:planId/simulator). Amortización francesa + IVA 16% + comisión de apertura + CAT.
@@ -42,4 +57,9 @@ export interface SimulationResultResponse {
42
57
  /** Costo Anual Total (decimal, ej. 2.87 = 287%). Metodología estándar CONDUSEF (supuesto). */
43
58
  catAnnual: number;
44
59
  schedule: AmortizationRowResponse[];
60
+ /**
61
+ * Promoción aplicada, o `null` si ninguna alcanzaba a esta venta. Los montos de arriba YA la
62
+ * incluyen: es el porqué de la cuota, no un extra a sumar.
63
+ */
64
+ appliedPromotion: AppliedPromotionResponse | null;
45
65
  }
@@ -0,0 +1,28 @@
1
+ import type { WizardSessionLookupStatusEnum } from '../enums/WizardSessionLookupStatusEnum';
2
+ import type { WizardStateEnum } from '../enums/WizardStateEnum';
3
+ import type { WizardStepEnum } from '../enums/WizardStepEnum';
4
+
5
+ /**
6
+ * Una entrada del lote de sesiones del wizard: traduce un `wizardSessionId` a la tienda, el cliente
7
+ * y el equipo de esa venta. Campo AUSENTE = «no lo se»; presente en `null` = dato afirmado como nulo.
8
+ */
9
+ export interface WizardSessionLookupEntry {
10
+ wizardSessionId: string;
11
+ status: WizardSessionLookupStatusEnum;
12
+ /** Todos los campos de abajo viajan SOLO con `status: OK`. */
13
+ retailerId?: string;
14
+ storeId?: string;
15
+ /** `null` mientras el KYC no haya dado de alta al cliente. */
16
+ retailCustomerId?: string | null;
17
+ state?: WizardStateEnum;
18
+ currentStep?: WizardStepEnum;
19
+ /** SKU del equipo reservado; `null` si la venta no llego al paso del producto. */
20
+ sku?: string | null;
21
+ /** Ficha comercial CONGELADA al reservar. `null` si no hay equipo reservado. */
22
+ productBrand?: string | null;
23
+ productModel?: string | null;
24
+ productCapacity?: string | null;
25
+ /** La venta que cerro esta sesion; `null` si todavia no cerro. */
26
+ saleId?: string | null;
27
+ folio?: string | null;
28
+ }
@@ -0,0 +1,10 @@
1
+ import type { WizardSessionLookupEntry } from '../WizardSessionLookupEntry';
2
+
3
+ /**
4
+ * `GET /private/wizard-sessions/batch` — una entrada por cada id pedido, en el MISMO orden.
5
+ * `unavailableCount` hace ruidoso el resultado parcial: sin el, el caller no sabe que le falto algo.
6
+ */
7
+ export interface WizardSessionLookupResponse {
8
+ items: WizardSessionLookupEntry[];
9
+ unavailableCount: number;
10
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Como se resolvio cada id pedido a `GET /private/wizard-sessions/batch`. Hay una entrada por id.
3
+ * `NOT_FOUND` y `UNAVAILABLE` NO son lo mismo: colapsarlos afirma «no tiene» cuando fue «no se leyo».
4
+ */
5
+ export enum WizardSessionLookupStatusEnum {
6
+ /** La sesion existe y se leyo completa. */
7
+ OK = 'OK',
8
+ /** No existe esa sesion en el silo. Es un dato POSITIVO, no una ausencia. */
9
+ NOT_FOUND = 'NOT_FOUND',
10
+ /** No se pudo leer esa sesion. El caller reintenta SOLO ese id. */
11
+ UNAVAILABLE = 'UNAVAILABLE',
12
+ /** Ese id no tiene forma de id. Reintentarlo nunca va a servir: el caller lo mando mal. */
13
+ INVALID_ID = 'INVALID_ID',
14
+ }
@@ -148,3 +148,8 @@ export * from './events/SaleCancelledV1';
148
148
  export * from './events/SaleCompletedV2';
149
149
  export * from './events/SaleCancelledV2';
150
150
  export * from './events/SessionExpiredV1';
151
+
152
+ // Lookup privado por lote (GET /private/wizard-sessions/batch)
153
+ export * from './enums/WizardSessionLookupStatusEnum';
154
+ export * from './dtos/WizardSessionLookupEntry';
155
+ export * from './dtos/responses/WizardSessionLookupResponse';