@fiado/type-kit 3.363.0 → 3.365.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 (50) hide show
  1. package/_test_/unit/loanOfferings/promotionRequests.test.ts +62 -0
  2. package/bin/loanCredit/dtos/requests/OriginateLoanCreditRequest.d.ts +8 -0
  3. package/bin/loanCredit/dtos/requests/OriginateLoanCreditRequest.js +12 -0
  4. package/bin/loanOfferings/dtos/PromotionEffect.d.ts +15 -0
  5. package/bin/loanOfferings/dtos/PromotionEffect.js +2 -0
  6. package/bin/loanOfferings/dtos/requests/ChangePromotionStatusRequest.d.ts +10 -0
  7. package/bin/loanOfferings/dtos/requests/ChangePromotionStatusRequest.js +34 -0
  8. package/bin/loanOfferings/dtos/requests/CreatePromotionRequest.d.ts +26 -0
  9. package/bin/loanOfferings/dtos/requests/CreatePromotionRequest.js +84 -0
  10. package/bin/loanOfferings/dtos/requests/PromotionEffectInput.d.ts +15 -0
  11. package/bin/loanOfferings/dtos/requests/PromotionEffectInput.js +46 -0
  12. package/bin/loanOfferings/dtos/requests/SimulateCreditPlanRequest.d.ts +8 -0
  13. package/bin/loanOfferings/dtos/requests/SimulateCreditPlanRequest.js +16 -0
  14. package/bin/loanOfferings/dtos/requests/UpdatePromotionRequest.d.ts +20 -0
  15. package/bin/loanOfferings/dtos/requests/UpdatePromotionRequest.js +89 -0
  16. package/bin/loanOfferings/dtos/responses/PromotionLogEntryResponse.d.ts +17 -0
  17. package/bin/loanOfferings/dtos/responses/PromotionLogEntryResponse.js +2 -0
  18. package/bin/loanOfferings/dtos/responses/PromotionResponse.d.ts +44 -0
  19. package/bin/loanOfferings/dtos/responses/PromotionResponse.js +2 -0
  20. package/bin/loanOfferings/dtos/responses/SimulationResultResponse.d.ts +18 -0
  21. package/bin/loanOfferings/enums/PromotionEffectKindEnum.d.ts +12 -0
  22. package/bin/loanOfferings/enums/PromotionEffectKindEnum.js +16 -0
  23. package/bin/loanOfferings/enums/PromotionLogEventEnum.d.ts +12 -0
  24. package/bin/loanOfferings/enums/PromotionLogEventEnum.js +16 -0
  25. package/bin/loanOfferings/enums/PromotionPhaseEnum.d.ts +11 -0
  26. package/bin/loanOfferings/enums/PromotionPhaseEnum.js +15 -0
  27. package/bin/loanOfferings/enums/PromotionStatusEnum.d.ts +12 -0
  28. package/bin/loanOfferings/enums/PromotionStatusEnum.js +16 -0
  29. package/bin/loanOfferings/index.d.ts +11 -0
  30. package/bin/loanOfferings/index.js +11 -0
  31. package/bin/retailCustomer/dtos/responses/Customer360Response.d.ts +20 -1
  32. package/bin/retailCustomer/dtos/responses/CustomerResponse.d.ts +6 -0
  33. package/package.json +1 -1
  34. package/src/loanCredit/dtos/requests/OriginateLoanCreditRequest.ts +16 -0
  35. package/src/loanOfferings/dtos/PromotionEffect.ts +15 -0
  36. package/src/loanOfferings/dtos/requests/ChangePromotionStatusRequest.ts +19 -0
  37. package/src/loanOfferings/dtos/requests/CreatePromotionRequest.ts +77 -0
  38. package/src/loanOfferings/dtos/requests/PromotionEffectInput.ts +33 -0
  39. package/src/loanOfferings/dtos/requests/SimulateCreditPlanRequest.ts +17 -1
  40. package/src/loanOfferings/dtos/requests/UpdatePromotionRequest.ts +76 -0
  41. package/src/loanOfferings/dtos/responses/PromotionLogEntryResponse.ts +18 -0
  42. package/src/loanOfferings/dtos/responses/PromotionResponse.ts +45 -0
  43. package/src/loanOfferings/dtos/responses/SimulationResultResponse.ts +20 -0
  44. package/src/loanOfferings/enums/PromotionEffectKindEnum.ts +12 -0
  45. package/src/loanOfferings/enums/PromotionLogEventEnum.ts +12 -0
  46. package/src/loanOfferings/enums/PromotionPhaseEnum.ts +11 -0
  47. package/src/loanOfferings/enums/PromotionStatusEnum.ts +12 -0
  48. package/src/loanOfferings/index.ts +11 -0
  49. package/src/retailCustomer/dtos/responses/Customer360Response.ts +21 -1
  50. package/src/retailCustomer/dtos/responses/CustomerResponse.ts +6 -0
@@ -0,0 +1,62 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validate } from 'class-validator';
4
+ import {
5
+ CreatePromotionRequest,
6
+ CreditPlanLevelEnum,
7
+ UpdatePromotionRequest,
8
+ } from '../../../src/loanOfferings/index';
9
+
10
+ /** El alta mínima válida. */
11
+ const base = {
12
+ name: 'Enganche 5 puntos menos',
13
+ description: 'Baja el enganche mínimo cinco puntos en Plata',
14
+ effect: { downPaymentDeltaPct: 0.05 },
15
+ segmentId: 'SEG_SILVER',
16
+ targetLevels: ['SILVER'],
17
+ };
18
+
19
+ const errorProperties = async (
20
+ raw: Record<string, unknown>,
21
+ dtoClass: typeof CreatePromotionRequest | typeof UpdatePromotionRequest = CreatePromotionRequest,
22
+ ): Promise<string[]> => {
23
+ const instance = plainToInstance(dtoClass, raw, { excludeExtraneousValues: true });
24
+ return (await validate(instance as object)).map((error) => error.property);
25
+ };
26
+
27
+ describe('CreatePromotionRequest', () => {
28
+ it('valida con los obligatorios y tipa el nivel al enum', async () => {
29
+ const dto = plainToInstance(CreatePromotionRequest, base, { excludeExtraneousValues: true });
30
+ expect(await validate(dto as object)).toHaveLength(0);
31
+ expect(dto.targetLevels).toEqual([CreditPlanLevelEnum.SILVER]);
32
+ });
33
+
34
+ it('rechaza una fecha que no es ISO 8601', async () => {
35
+ expect(await errorProperties({ ...base, validFrom: 'mañana' })).toContain('validFrom');
36
+ expect(await errorProperties({ ...base, validUntil: '31/12/2026' })).toContain('validUntil');
37
+ expect(await errorProperties({ ...base, validUntil: '' })).toContain('validUntil');
38
+ });
39
+
40
+ it('acepta la fecha desnuda y el instante completo', async () => {
41
+ expect(await errorProperties({ ...base, validUntil: '2026-12-31' })).toHaveLength(0);
42
+ expect(await errorProperties({ ...base, validFrom: '2026-12-31T10:00:00.000Z' })).toHaveLength(0);
43
+ });
44
+
45
+ it('acepta null en las fechas: es vigencia abierta, no una fecha inválida', async () => {
46
+ expect(await errorProperties({ ...base, validFrom: null, validUntil: null })).toHaveLength(0);
47
+ });
48
+
49
+ it('exige al menos un nivel', async () => {
50
+ expect(await errorProperties({ ...base, targetLevels: [] })).toContain('targetLevels');
51
+ });
52
+ });
53
+
54
+ describe('UpdatePromotionRequest', () => {
55
+ it('el parche vacío es válido', async () => {
56
+ expect(await errorProperties({}, UpdatePromotionRequest)).toHaveLength(0);
57
+ });
58
+
59
+ it('rechaza una fecha que no es ISO 8601', async () => {
60
+ expect(await errorProperties({ validUntil: 'el viernes' }, UpdatePromotionRequest)).toContain('validUntil');
61
+ });
62
+ });
@@ -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);
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Palanca que la promoción aplica sobre el plan de crédito. Al menos una clave debe venir presente
3
+ * (el lambda rechaza el efecto vacío con 422). Montos en **cents**; porcentajes y TNA en decimal,
4
+ * igual que `CreditPlan`.
5
+ */
6
+ export interface PromotionEffect {
7
+ /** Delta NEGATIVO sobre el enganche mínimo del plan (`-0.20` = veinte puntos menos). */
8
+ downPaymentDeltaPct: number | null;
9
+ /** Bono que se abona a la tarjeta PCF al activar el crédito. */
10
+ pcfBonusCents: number | null;
11
+ /** TNA que reemplaza a la del plan, siempre hacia abajo (`1.80` = 180% en vez de 200%). */
12
+ tnaOverride: number | null;
13
+ /** Techo de monto financiable que reemplaza al del plan. */
14
+ maxAmountOverrideCents: number | null;
15
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,10 @@
1
+ import { PromotionStatusEnum } from '../../enums/PromotionStatusEnum';
2
+ /**
3
+ * Body de PUT /promotions/:promotionId/status — publicar, pausar, reanudar o vencer.
4
+ * Transiciones válidas: `DRAFT→PUBLISHED`, `PUBLISHED⇄PAUSED`, `PUBLISHED|PAUSED→EXPIRED`.
5
+ * `reason` acompaña la pausa y queda en la bitácora.
6
+ */
7
+ export declare class ChangePromotionStatusRequest {
8
+ status: PromotionStatusEnum;
9
+ reason?: string | null;
10
+ }
@@ -0,0 +1,34 @@
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.ChangePromotionStatusRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const PromotionStatusEnum_1 = require("../../enums/PromotionStatusEnum");
16
+ /**
17
+ * Body de PUT /promotions/:promotionId/status — publicar, pausar, reanudar o vencer.
18
+ * Transiciones válidas: `DRAFT→PUBLISHED`, `PUBLISHED⇄PAUSED`, `PUBLISHED|PAUSED→EXPIRED`.
19
+ * `reason` acompaña la pausa y queda en la bitácora.
20
+ */
21
+ class ChangePromotionStatusRequest {
22
+ }
23
+ exports.ChangePromotionStatusRequest = ChangePromotionStatusRequest;
24
+ __decorate([
25
+ (0, class_transformer_1.Expose)(),
26
+ (0, class_validator_1.IsEnum)(PromotionStatusEnum_1.PromotionStatusEnum),
27
+ __metadata("design:type", String)
28
+ ], ChangePromotionStatusRequest.prototype, "status", void 0);
29
+ __decorate([
30
+ (0, class_transformer_1.Expose)(),
31
+ (0, class_validator_1.IsOptional)(),
32
+ (0, class_validator_1.IsString)(),
33
+ __metadata("design:type", String)
34
+ ], ChangePromotionStatusRequest.prototype, "reason", void 0);
@@ -0,0 +1,26 @@
1
+ import { CreditPlanLevelEnum } from '../../enums/CreditPlanLevelEnum';
2
+ import { PromotionEffectInput } from './PromotionEffectInput';
3
+ /**
4
+ * Body de POST /promotions — alta de una promoción del motor.
5
+ * Nace en `DRAFT`: el estado, `promotionId`, `version`, los contadores de consumo y la auditoría
6
+ * los asigna el lambda y NO viajan en el request. `budgetMaxCents` ausente/`null` = sin tope.
7
+ */
8
+ export declare class CreatePromotionRequest {
9
+ name: string;
10
+ description: string;
11
+ effect: PromotionEffectInput;
12
+ /** Segmento de clientes al que apunta la promoción. */
13
+ segmentId: string;
14
+ targetLevels: CreditPlanLevelEnum[];
15
+ /** SKUs alcanzados; ausente o `null` = todos los productos. */
16
+ productSkus?: string[] | null;
17
+ /** Tiendas alcanzadas. `null` o ausente = todas. */
18
+ storeIds?: string[] | null;
19
+ validFrom?: string | null;
20
+ validUntil?: string | null;
21
+ /**
22
+ * Tope de presupuesto en cents; `null` = sin tope. El signo lo valida el lambda (422): un
23
+ * presupuesto negativo es un request bien formado que el negocio rechaza.
24
+ */
25
+ budgetMaxCents?: number | null;
26
+ }
@@ -0,0 +1,84 @@
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.CreatePromotionRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const CreditPlanLevelEnum_1 = require("../../enums/CreditPlanLevelEnum");
16
+ const PromotionEffectInput_1 = require("./PromotionEffectInput");
17
+ /**
18
+ * Body de POST /promotions — alta de una promoción del motor.
19
+ * Nace en `DRAFT`: el estado, `promotionId`, `version`, los contadores de consumo y la auditoría
20
+ * los asigna el lambda y NO viajan en el request. `budgetMaxCents` ausente/`null` = sin tope.
21
+ */
22
+ class CreatePromotionRequest {
23
+ }
24
+ exports.CreatePromotionRequest = CreatePromotionRequest;
25
+ __decorate([
26
+ (0, class_transformer_1.Expose)(),
27
+ (0, class_validator_1.IsString)(),
28
+ __metadata("design:type", String)
29
+ ], CreatePromotionRequest.prototype, "name", void 0);
30
+ __decorate([
31
+ (0, class_transformer_1.Expose)(),
32
+ (0, class_validator_1.IsString)(),
33
+ __metadata("design:type", String)
34
+ ], CreatePromotionRequest.prototype, "description", void 0);
35
+ __decorate([
36
+ (0, class_transformer_1.Expose)(),
37
+ (0, class_validator_1.ValidateNested)(),
38
+ (0, class_transformer_1.Type)(() => PromotionEffectInput_1.PromotionEffectInput),
39
+ __metadata("design:type", PromotionEffectInput_1.PromotionEffectInput)
40
+ ], CreatePromotionRequest.prototype, "effect", void 0);
41
+ __decorate([
42
+ (0, class_transformer_1.Expose)(),
43
+ (0, class_validator_1.IsString)(),
44
+ __metadata("design:type", String)
45
+ ], CreatePromotionRequest.prototype, "segmentId", void 0);
46
+ __decorate([
47
+ (0, class_transformer_1.Expose)(),
48
+ (0, class_validator_1.IsArray)(),
49
+ (0, class_validator_1.ArrayNotEmpty)(),
50
+ (0, class_validator_1.IsEnum)(CreditPlanLevelEnum_1.CreditPlanLevelEnum, { each: true }),
51
+ __metadata("design:type", Array)
52
+ ], CreatePromotionRequest.prototype, "targetLevels", void 0);
53
+ __decorate([
54
+ (0, class_transformer_1.Expose)(),
55
+ (0, class_validator_1.IsOptional)(),
56
+ (0, class_validator_1.IsArray)(),
57
+ (0, class_validator_1.IsString)({ each: true }),
58
+ __metadata("design:type", Array)
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);
67
+ __decorate([
68
+ (0, class_transformer_1.Expose)(),
69
+ (0, class_validator_1.IsOptional)(),
70
+ (0, class_validator_1.IsISO8601)(),
71
+ __metadata("design:type", String)
72
+ ], CreatePromotionRequest.prototype, "validFrom", void 0);
73
+ __decorate([
74
+ (0, class_transformer_1.Expose)(),
75
+ (0, class_validator_1.IsOptional)(),
76
+ (0, class_validator_1.IsISO8601)(),
77
+ __metadata("design:type", String)
78
+ ], CreatePromotionRequest.prototype, "validUntil", void 0);
79
+ __decorate([
80
+ (0, class_transformer_1.Expose)(),
81
+ (0, class_validator_1.IsOptional)(),
82
+ (0, class_validator_1.IsInt)(),
83
+ __metadata("design:type", Number)
84
+ ], CreatePromotionRequest.prototype, "budgetMaxCents", void 0);
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Efecto de la promoción tal como viaja en el body (alta y edición). Acá se valida solo la FORMA
3
+ * (que sea número o entero). Las cotas de negocio — rango de cada palanca y que venga al menos una
4
+ * clave — las valida el lambda con 422: son reglas del negocio sobre un body bien formado.
5
+ */
6
+ export declare class PromotionEffectInput {
7
+ /** Delta NEGATIVO sobre el enganche mínimo (`-0.20` = veinte puntos menos); rango [-1, 0]. */
8
+ downPaymentDeltaPct?: number | null;
9
+ /** Bono a la tarjeta PCF, en cents. */
10
+ pcfBonusCents?: number | null;
11
+ /** TNA que reemplaza a la del plan, hacia abajo (`1.80` = 180%); rango [0, 2.60]. */
12
+ tnaOverride?: number | null;
13
+ /** Techo de monto financiable que reemplaza al del plan, en cents. */
14
+ maxAmountOverrideCents?: number | null;
15
+ }
@@ -0,0 +1,46 @@
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.PromotionEffectInput = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ /**
16
+ * Efecto de la promoción tal como viaja en el body (alta y edición). Acá se valida solo la FORMA
17
+ * (que sea número o entero). Las cotas de negocio — rango de cada palanca y que venga al menos una
18
+ * clave — las valida el lambda con 422: son reglas del negocio sobre un body bien formado.
19
+ */
20
+ class PromotionEffectInput {
21
+ }
22
+ exports.PromotionEffectInput = PromotionEffectInput;
23
+ __decorate([
24
+ (0, class_transformer_1.Expose)(),
25
+ (0, class_validator_1.IsOptional)(),
26
+ (0, class_validator_1.IsNumber)(),
27
+ __metadata("design:type", Number)
28
+ ], PromotionEffectInput.prototype, "downPaymentDeltaPct", void 0);
29
+ __decorate([
30
+ (0, class_transformer_1.Expose)(),
31
+ (0, class_validator_1.IsOptional)(),
32
+ (0, class_validator_1.IsInt)(),
33
+ __metadata("design:type", Number)
34
+ ], PromotionEffectInput.prototype, "pcfBonusCents", void 0);
35
+ __decorate([
36
+ (0, class_transformer_1.Expose)(),
37
+ (0, class_validator_1.IsOptional)(),
38
+ (0, class_validator_1.IsNumber)(),
39
+ __metadata("design:type", Number)
40
+ ], PromotionEffectInput.prototype, "tnaOverride", void 0);
41
+ __decorate([
42
+ (0, class_transformer_1.Expose)(),
43
+ (0, class_validator_1.IsOptional)(),
44
+ (0, class_validator_1.IsInt)(),
45
+ __metadata("design:type", Number)
46
+ ], PromotionEffectInput.prototype, "maxAmountOverrideCents", void 0);
@@ -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);
@@ -0,0 +1,20 @@
1
+ import { CreditPlanLevelEnum } from '../../enums/CreditPlanLevelEnum';
2
+ import { PromotionEffectInput } from './PromotionEffectInput';
3
+ /**
4
+ * Body de PUT /promotions/:promotionId — edición parcial (todos los campos opcionales).
5
+ * Solo se admite sobre `DRAFT` y `PUBLISHED`, y sube `version`. El cambio de estado va por su
6
+ * endpoint dedicado. `effect` se reemplaza entero cuando viene, no se mergea clave a clave.
7
+ */
8
+ export declare class UpdatePromotionRequest {
9
+ name?: string;
10
+ description?: string;
11
+ effect?: PromotionEffectInput;
12
+ segmentId?: string;
13
+ targetLevels?: CreditPlanLevelEnum[];
14
+ productSkus?: string[] | null;
15
+ /** Tiendas alcanzadas. `null` o ausente = todas. */
16
+ storeIds?: string[] | null;
17
+ validFrom?: string | null;
18
+ validUntil?: string | null;
19
+ budgetMaxCents?: number | null;
20
+ }
@@ -0,0 +1,89 @@
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.UpdatePromotionRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const CreditPlanLevelEnum_1 = require("../../enums/CreditPlanLevelEnum");
16
+ const PromotionEffectInput_1 = require("./PromotionEffectInput");
17
+ /**
18
+ * Body de PUT /promotions/:promotionId — edición parcial (todos los campos opcionales).
19
+ * Solo se admite sobre `DRAFT` y `PUBLISHED`, y sube `version`. El cambio de estado va por su
20
+ * endpoint dedicado. `effect` se reemplaza entero cuando viene, no se mergea clave a clave.
21
+ */
22
+ class UpdatePromotionRequest {
23
+ }
24
+ exports.UpdatePromotionRequest = UpdatePromotionRequest;
25
+ __decorate([
26
+ (0, class_transformer_1.Expose)(),
27
+ (0, class_validator_1.IsOptional)(),
28
+ (0, class_validator_1.IsString)(),
29
+ __metadata("design:type", String)
30
+ ], UpdatePromotionRequest.prototype, "name", void 0);
31
+ __decorate([
32
+ (0, class_transformer_1.Expose)(),
33
+ (0, class_validator_1.IsOptional)(),
34
+ (0, class_validator_1.IsString)(),
35
+ __metadata("design:type", String)
36
+ ], UpdatePromotionRequest.prototype, "description", void 0);
37
+ __decorate([
38
+ (0, class_transformer_1.Expose)(),
39
+ (0, class_validator_1.IsOptional)(),
40
+ (0, class_validator_1.ValidateNested)(),
41
+ (0, class_transformer_1.Type)(() => PromotionEffectInput_1.PromotionEffectInput),
42
+ __metadata("design:type", PromotionEffectInput_1.PromotionEffectInput)
43
+ ], UpdatePromotionRequest.prototype, "effect", void 0);
44
+ __decorate([
45
+ (0, class_transformer_1.Expose)(),
46
+ (0, class_validator_1.IsOptional)(),
47
+ (0, class_validator_1.IsString)(),
48
+ __metadata("design:type", String)
49
+ ], UpdatePromotionRequest.prototype, "segmentId", void 0);
50
+ __decorate([
51
+ (0, class_transformer_1.Expose)(),
52
+ (0, class_validator_1.IsOptional)(),
53
+ (0, class_validator_1.IsArray)(),
54
+ (0, class_validator_1.ArrayNotEmpty)(),
55
+ (0, class_validator_1.IsEnum)(CreditPlanLevelEnum_1.CreditPlanLevelEnum, { each: true }),
56
+ __metadata("design:type", Array)
57
+ ], UpdatePromotionRequest.prototype, "targetLevels", void 0);
58
+ __decorate([
59
+ (0, class_transformer_1.Expose)(),
60
+ (0, class_validator_1.IsOptional)(),
61
+ (0, class_validator_1.IsArray)(),
62
+ (0, class_validator_1.IsString)({ each: true }),
63
+ __metadata("design:type", Array)
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);
72
+ __decorate([
73
+ (0, class_transformer_1.Expose)(),
74
+ (0, class_validator_1.IsOptional)(),
75
+ (0, class_validator_1.IsISO8601)(),
76
+ __metadata("design:type", String)
77
+ ], UpdatePromotionRequest.prototype, "validFrom", void 0);
78
+ __decorate([
79
+ (0, class_transformer_1.Expose)(),
80
+ (0, class_validator_1.IsOptional)(),
81
+ (0, class_validator_1.IsISO8601)(),
82
+ __metadata("design:type", String)
83
+ ], UpdatePromotionRequest.prototype, "validUntil", void 0);
84
+ __decorate([
85
+ (0, class_transformer_1.Expose)(),
86
+ (0, class_validator_1.IsOptional)(),
87
+ (0, class_validator_1.IsInt)(),
88
+ __metadata("design:type", Number)
89
+ ], UpdatePromotionRequest.prototype, "budgetMaxCents", void 0);
@@ -0,0 +1,17 @@
1
+ import { PromotionLogEventEnum } from '../../enums/PromotionLogEventEnum';
2
+ import { PromotionStatusEnum } from '../../enums/PromotionStatusEnum';
3
+ /**
4
+ * Fila del tab «Auditoría»: un evento de la bitácora de promociones.
5
+ * `fromStatus` es `null` en el alta; `reason` solo viene cargado en la pausa.
6
+ */
7
+ export interface PromotionLogEntryResponse {
8
+ promotionId: string;
9
+ promotionName: string;
10
+ event: PromotionLogEventEnum;
11
+ occurredAt: string;
12
+ performedBy: string;
13
+ fromStatus: PromotionStatusEnum | null;
14
+ toStatus: PromotionStatusEnum | null;
15
+ reason: string | null;
16
+ version: number;
17
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,44 @@
1
+ import { CreditPlanLevelEnum } from '../../enums/CreditPlanLevelEnum';
2
+ import { PromotionEffectKindEnum } from '../../enums/PromotionEffectKindEnum';
3
+ import { PromotionPhaseEnum } from '../../enums/PromotionPhaseEnum';
4
+ import { PromotionStatusEnum } from '../../enums/PromotionStatusEnum';
5
+ import { PromotionEffect } from '../PromotionEffect';
6
+ /**
7
+ * Shape de salida de una promoción (GET / POST / PUT de /promotions).
8
+ * Montos en cents; porcentajes y TNA en decimal.
9
+ *
10
+ * `effectKind` y `phase` son DERIVADOS y no viven en la tabla: el primero sale de las claves de
11
+ * `effect`, el segundo de las fechas contra hoy y solo cuando el estado es `PUBLISHED`.
12
+ */
13
+ export interface PromotionResponse {
14
+ promotionId: string;
15
+ name: string;
16
+ description: string;
17
+ effect: PromotionEffect;
18
+ /** Derivado de las claves de `effect`; `COMBO` si hay dos o más, `null` si no hay ninguna. */
19
+ effectKind: PromotionEffectKindEnum | null;
20
+ segmentId: string;
21
+ targetLevels: CreditPlanLevelEnum[];
22
+ /** `null` = alcanza a todos los productos. */
23
+ productSkus: string[] | null;
24
+ /** `null` = alcanza a todas las tiendas. Dimensión «Tienda / canal» del alcance. */
25
+ storeIds: string[] | null;
26
+ validFrom: string | null;
27
+ validUntil: string | null;
28
+ status: PromotionStatusEnum;
29
+ /** Fase de vigencia derivada; `null` cuando el estado no es `PUBLISHED`. */
30
+ phase: PromotionPhaseEnum | null;
31
+ /** Tope de presupuesto; `null` = sin tope. */
32
+ budgetMaxCents: number | null;
33
+ budgetConsumedCents: number;
34
+ creditsGenerated: number;
35
+ version: number;
36
+ pausedAt: string | null;
37
+ pauseReason: string | null;
38
+ publishedAt: string | null;
39
+ publishedBy: string | null;
40
+ createdBy: string;
41
+ updatedBy: string;
42
+ createdAt: string;
43
+ updatedAt: string;
44
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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,12 @@
1
+ /**
2
+ * Naturaleza del efecto de una promoción, DERIVADA de las claves presentes en `effect`.
3
+ * `COMBO` cuando hay dos o más claves. No se persiste: se calcula al responder.
4
+ * @enum {string}
5
+ */
6
+ export declare enum PromotionEffectKindEnum {
7
+ DOWN_PAYMENT_DELTA = "DOWN_PAYMENT_DELTA",
8
+ PCF_BONUS = "PCF_BONUS",
9
+ TNA_OVERRIDE = "TNA_OVERRIDE",
10
+ MAX_AMOUNT_OVERRIDE = "MAX_AMOUNT_OVERRIDE",
11
+ COMBO = "COMBO"
12
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PromotionEffectKindEnum = void 0;
4
+ /**
5
+ * Naturaleza del efecto de una promoción, DERIVADA de las claves presentes en `effect`.
6
+ * `COMBO` cuando hay dos o más claves. No se persiste: se calcula al responder.
7
+ * @enum {string}
8
+ */
9
+ var PromotionEffectKindEnum;
10
+ (function (PromotionEffectKindEnum) {
11
+ PromotionEffectKindEnum["DOWN_PAYMENT_DELTA"] = "DOWN_PAYMENT_DELTA";
12
+ PromotionEffectKindEnum["PCF_BONUS"] = "PCF_BONUS";
13
+ PromotionEffectKindEnum["TNA_OVERRIDE"] = "TNA_OVERRIDE";
14
+ PromotionEffectKindEnum["MAX_AMOUNT_OVERRIDE"] = "MAX_AMOUNT_OVERRIDE";
15
+ PromotionEffectKindEnum["COMBO"] = "COMBO";
16
+ })(PromotionEffectKindEnum || (exports.PromotionEffectKindEnum = PromotionEffectKindEnum = {}));
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Evento de la bitácora de promociones (`<T>LoanPromotionLog_GT`), que alimenta el tab «Auditoría».
3
+ * @enum {string}
4
+ */
5
+ export declare enum PromotionLogEventEnum {
6
+ CREATE = "CREATE",
7
+ PUBLISH = "PUBLISH",
8
+ PAUSE = "PAUSE",
9
+ RESUME = "RESUME",
10
+ EXPIRE = "EXPIRE",
11
+ UPDATE = "UPDATE"
12
+ }