@fiado/type-kit 3.363.0 → 3.364.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 (42) hide show
  1. package/_test_/unit/loanOfferings/promotionRequests.test.ts +62 -0
  2. package/bin/loanOfferings/dtos/PromotionEffect.d.ts +15 -0
  3. package/bin/loanOfferings/dtos/PromotionEffect.js +2 -0
  4. package/bin/loanOfferings/dtos/requests/ChangePromotionStatusRequest.d.ts +10 -0
  5. package/bin/loanOfferings/dtos/requests/ChangePromotionStatusRequest.js +34 -0
  6. package/bin/loanOfferings/dtos/requests/CreatePromotionRequest.d.ts +24 -0
  7. package/bin/loanOfferings/dtos/requests/CreatePromotionRequest.js +77 -0
  8. package/bin/loanOfferings/dtos/requests/PromotionEffectInput.d.ts +15 -0
  9. package/bin/loanOfferings/dtos/requests/PromotionEffectInput.js +46 -0
  10. package/bin/loanOfferings/dtos/requests/UpdatePromotionRequest.d.ts +18 -0
  11. package/bin/loanOfferings/dtos/requests/UpdatePromotionRequest.js +82 -0
  12. package/bin/loanOfferings/dtos/responses/PromotionLogEntryResponse.d.ts +17 -0
  13. package/bin/loanOfferings/dtos/responses/PromotionLogEntryResponse.js +2 -0
  14. package/bin/loanOfferings/dtos/responses/PromotionResponse.d.ts +42 -0
  15. package/bin/loanOfferings/dtos/responses/PromotionResponse.js +2 -0
  16. package/bin/loanOfferings/enums/PromotionEffectKindEnum.d.ts +12 -0
  17. package/bin/loanOfferings/enums/PromotionEffectKindEnum.js +16 -0
  18. package/bin/loanOfferings/enums/PromotionLogEventEnum.d.ts +12 -0
  19. package/bin/loanOfferings/enums/PromotionLogEventEnum.js +16 -0
  20. package/bin/loanOfferings/enums/PromotionPhaseEnum.d.ts +11 -0
  21. package/bin/loanOfferings/enums/PromotionPhaseEnum.js +15 -0
  22. package/bin/loanOfferings/enums/PromotionStatusEnum.d.ts +12 -0
  23. package/bin/loanOfferings/enums/PromotionStatusEnum.js +16 -0
  24. package/bin/loanOfferings/index.d.ts +11 -0
  25. package/bin/loanOfferings/index.js +11 -0
  26. package/bin/retailCustomer/dtos/responses/Customer360Response.d.ts +20 -1
  27. package/bin/retailCustomer/dtos/responses/CustomerResponse.d.ts +6 -0
  28. package/package.json +1 -1
  29. package/src/loanOfferings/dtos/PromotionEffect.ts +15 -0
  30. package/src/loanOfferings/dtos/requests/ChangePromotionStatusRequest.ts +19 -0
  31. package/src/loanOfferings/dtos/requests/CreatePromotionRequest.ts +70 -0
  32. package/src/loanOfferings/dtos/requests/PromotionEffectInput.ts +33 -0
  33. package/src/loanOfferings/dtos/requests/UpdatePromotionRequest.ts +69 -0
  34. package/src/loanOfferings/dtos/responses/PromotionLogEntryResponse.ts +18 -0
  35. package/src/loanOfferings/dtos/responses/PromotionResponse.ts +43 -0
  36. package/src/loanOfferings/enums/PromotionEffectKindEnum.ts +12 -0
  37. package/src/loanOfferings/enums/PromotionLogEventEnum.ts +12 -0
  38. package/src/loanOfferings/enums/PromotionPhaseEnum.ts +11 -0
  39. package/src/loanOfferings/enums/PromotionStatusEnum.ts +12 -0
  40. package/src/loanOfferings/index.ts +11 -0
  41. package/src/retailCustomer/dtos/responses/Customer360Response.ts +21 -1
  42. 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
+ });
@@ -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
+ /** Puntos de enganche que se restan al mínimo del plan (decimal sobre 1: `0.05` = 5 puntos). */
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 (decimal: `2.10` = 210%). */
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,24 @@
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
+ validFrom?: string | null;
18
+ validUntil?: string | null;
19
+ /**
20
+ * Tope de presupuesto en cents; `null` = sin tope. El signo lo valida el lambda (422): un
21
+ * presupuesto negativo es un request bien formado que el negocio rechaza.
22
+ */
23
+ budgetMaxCents?: number | null;
24
+ }
@@ -0,0 +1,77 @@
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.IsISO8601)(),
64
+ __metadata("design:type", String)
65
+ ], CreatePromotionRequest.prototype, "validFrom", void 0);
66
+ __decorate([
67
+ (0, class_transformer_1.Expose)(),
68
+ (0, class_validator_1.IsOptional)(),
69
+ (0, class_validator_1.IsISO8601)(),
70
+ __metadata("design:type", String)
71
+ ], CreatePromotionRequest.prototype, "validUntil", void 0);
72
+ __decorate([
73
+ (0, class_transformer_1.Expose)(),
74
+ (0, class_validator_1.IsOptional)(),
75
+ (0, class_validator_1.IsInt)(),
76
+ __metadata("design:type", Number)
77
+ ], 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
+ /** Puntos de enganche a restar del mínimo del plan (decimal sobre 1). */
8
+ downPaymentDeltaPct?: number | null;
9
+ /** Bono a la tarjeta PCF, en cents. */
10
+ pcfBonusCents?: number | null;
11
+ /** TNA que reemplaza a la del plan (decimal); rango de negocio [2.00, 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);
@@ -0,0 +1,18 @@
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
+ validFrom?: string | null;
16
+ validUntil?: string | null;
17
+ budgetMaxCents?: number | null;
18
+ }
@@ -0,0 +1,82 @@
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.IsISO8601)(),
69
+ __metadata("design:type", String)
70
+ ], UpdatePromotionRequest.prototype, "validFrom", void 0);
71
+ __decorate([
72
+ (0, class_transformer_1.Expose)(),
73
+ (0, class_validator_1.IsOptional)(),
74
+ (0, class_validator_1.IsISO8601)(),
75
+ __metadata("design:type", String)
76
+ ], UpdatePromotionRequest.prototype, "validUntil", void 0);
77
+ __decorate([
78
+ (0, class_transformer_1.Expose)(),
79
+ (0, class_validator_1.IsOptional)(),
80
+ (0, class_validator_1.IsInt)(),
81
+ __metadata("design:type", Number)
82
+ ], 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,42 @@
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
+ validFrom: string | null;
25
+ validUntil: string | null;
26
+ status: PromotionStatusEnum;
27
+ /** Fase de vigencia derivada; `null` cuando el estado no es `PUBLISHED`. */
28
+ phase: PromotionPhaseEnum | null;
29
+ /** Tope de presupuesto; `null` = sin tope. */
30
+ budgetMaxCents: number | null;
31
+ budgetConsumedCents: number;
32
+ creditsGenerated: number;
33
+ version: number;
34
+ pausedAt: string | null;
35
+ pauseReason: string | null;
36
+ publishedAt: string | null;
37
+ publishedBy: string | null;
38
+ createdBy: string;
39
+ updatedBy: string;
40
+ createdAt: string;
41
+ updatedAt: string;
42
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -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
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PromotionLogEventEnum = void 0;
4
+ /**
5
+ * Evento de la bitácora de promociones (`<T>LoanPromotionLog_GT`), que alimenta el tab «Auditoría».
6
+ * @enum {string}
7
+ */
8
+ var PromotionLogEventEnum;
9
+ (function (PromotionLogEventEnum) {
10
+ PromotionLogEventEnum["CREATE"] = "CREATE";
11
+ PromotionLogEventEnum["PUBLISH"] = "PUBLISH";
12
+ PromotionLogEventEnum["PAUSE"] = "PAUSE";
13
+ PromotionLogEventEnum["RESUME"] = "RESUME";
14
+ PromotionLogEventEnum["EXPIRE"] = "EXPIRE";
15
+ PromotionLogEventEnum["UPDATE"] = "UPDATE";
16
+ })(PromotionLogEventEnum || (exports.PromotionLogEventEnum = PromotionLogEventEnum = {}));
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Fase de vigencia de una promoción PUBLICADA, derivada de `validFrom`/`validUntil` contra hoy.
3
+ * No se persiste — así no hace falta un cron que mueva estados a medianoche. `null` cuando el
4
+ * estado persistido no es `PUBLISHED`.
5
+ * @enum {string}
6
+ */
7
+ export declare enum PromotionPhaseEnum {
8
+ SCHEDULED = "SCHEDULED",
9
+ ACTIVE = "ACTIVE",
10
+ EXPIRED = "EXPIRED"
11
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PromotionPhaseEnum = void 0;
4
+ /**
5
+ * Fase de vigencia de una promoción PUBLICADA, derivada de `validFrom`/`validUntil` contra hoy.
6
+ * No se persiste — así no hace falta un cron que mueva estados a medianoche. `null` cuando el
7
+ * estado persistido no es `PUBLISHED`.
8
+ * @enum {string}
9
+ */
10
+ var PromotionPhaseEnum;
11
+ (function (PromotionPhaseEnum) {
12
+ PromotionPhaseEnum["SCHEDULED"] = "SCHEDULED";
13
+ PromotionPhaseEnum["ACTIVE"] = "ACTIVE";
14
+ PromotionPhaseEnum["EXPIRED"] = "EXPIRED";
15
+ })(PromotionPhaseEnum || (exports.PromotionPhaseEnum = PromotionPhaseEnum = {}));
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Estado PERSISTIDO de una promoción del motor (portal-admin-sk-promociones).
3
+ * `EXPIRED` es terminal. La «fase» que ve el operador (programada / activa / vencida) NO se guarda:
4
+ * se deriva de las fechas — ver `PromotionPhaseEnum`.
5
+ * @enum {string}
6
+ */
7
+ export declare enum PromotionStatusEnum {
8
+ DRAFT = "DRAFT",
9
+ PUBLISHED = "PUBLISHED",
10
+ PAUSED = "PAUSED",
11
+ EXPIRED = "EXPIRED"
12
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PromotionStatusEnum = void 0;
4
+ /**
5
+ * Estado PERSISTIDO de una promoción del motor (portal-admin-sk-promociones).
6
+ * `EXPIRED` es terminal. La «fase» que ve el operador (programada / activa / vencida) NO se guarda:
7
+ * se deriva de las fechas — ver `PromotionPhaseEnum`.
8
+ * @enum {string}
9
+ */
10
+ var PromotionStatusEnum;
11
+ (function (PromotionStatusEnum) {
12
+ PromotionStatusEnum["DRAFT"] = "DRAFT";
13
+ PromotionStatusEnum["PUBLISHED"] = "PUBLISHED";
14
+ PromotionStatusEnum["PAUSED"] = "PAUSED";
15
+ PromotionStatusEnum["EXPIRED"] = "EXPIRED";
16
+ })(PromotionStatusEnum || (exports.PromotionStatusEnum = PromotionStatusEnum = {}));
@@ -4,9 +4,14 @@ export * from './enums/ProductTierEnum';
4
4
  export * from './enums/CreditPlanStatusEnum';
5
5
  export * from './enums/FinancierTypeEnum';
6
6
  export * from './enums/FinancierStatusEnum';
7
+ export * from './enums/PromotionStatusEnum';
8
+ export * from './enums/PromotionEffectKindEnum';
9
+ export * from './enums/PromotionPhaseEnum';
10
+ export * from './enums/PromotionLogEventEnum';
7
11
  export * from './dtos/CreditPlan';
8
12
  export * from './dtos/Financier';
9
13
  export * from './dtos/RetailerCreditPlan';
14
+ export * from './dtos/PromotionEffect';
10
15
  export * from './dtos/requests/CreateCreditPlanRequest';
11
16
  export * from './dtos/requests/UpdateCreditPlanRequest';
12
17
  export * from './dtos/requests/ChangeCreditPlanStatusRequest';
@@ -15,7 +20,13 @@ export * from './dtos/requests/CreateFinancierRequest';
15
20
  export * from './dtos/requests/UpdateFinancierRequest';
16
21
  export * from './dtos/requests/ChangeFinancierStatusRequest';
17
22
  export * from './dtos/requests/ReorderFinancierRequest';
23
+ export * from './dtos/requests/PromotionEffectInput';
24
+ export * from './dtos/requests/CreatePromotionRequest';
25
+ export * from './dtos/requests/UpdatePromotionRequest';
26
+ export * from './dtos/requests/ChangePromotionStatusRequest';
18
27
  export * from './dtos/responses/CreditPlanResponse';
19
28
  export * from './dtos/responses/FinancierResponse';
20
29
  export * from './dtos/responses/RetailerCreditPlanResponse';
21
30
  export * from './dtos/responses/SimulationResultResponse';
31
+ export * from './dtos/responses/PromotionResponse';
32
+ export * from './dtos/responses/PromotionLogEntryResponse';
@@ -21,10 +21,15 @@ __exportStar(require("./enums/ProductTierEnum"), exports);
21
21
  __exportStar(require("./enums/CreditPlanStatusEnum"), exports);
22
22
  __exportStar(require("./enums/FinancierTypeEnum"), exports);
23
23
  __exportStar(require("./enums/FinancierStatusEnum"), exports);
24
+ __exportStar(require("./enums/PromotionStatusEnum"), exports);
25
+ __exportStar(require("./enums/PromotionEffectKindEnum"), exports);
26
+ __exportStar(require("./enums/PromotionPhaseEnum"), exports);
27
+ __exportStar(require("./enums/PromotionLogEventEnum"), exports);
24
28
  // Entity DTOs
25
29
  __exportStar(require("./dtos/CreditPlan"), exports);
26
30
  __exportStar(require("./dtos/Financier"), exports);
27
31
  __exportStar(require("./dtos/RetailerCreditPlan"), exports);
32
+ __exportStar(require("./dtos/PromotionEffect"), exports);
28
33
  // Request DTOs
29
34
  __exportStar(require("./dtos/requests/CreateCreditPlanRequest"), exports);
30
35
  __exportStar(require("./dtos/requests/UpdateCreditPlanRequest"), exports);
@@ -34,8 +39,14 @@ __exportStar(require("./dtos/requests/CreateFinancierRequest"), exports);
34
39
  __exportStar(require("./dtos/requests/UpdateFinancierRequest"), exports);
35
40
  __exportStar(require("./dtos/requests/ChangeFinancierStatusRequest"), exports);
36
41
  __exportStar(require("./dtos/requests/ReorderFinancierRequest"), exports);
42
+ __exportStar(require("./dtos/requests/PromotionEffectInput"), exports);
43
+ __exportStar(require("./dtos/requests/CreatePromotionRequest"), exports);
44
+ __exportStar(require("./dtos/requests/UpdatePromotionRequest"), exports);
45
+ __exportStar(require("./dtos/requests/ChangePromotionStatusRequest"), exports);
37
46
  // Response DTOs
38
47
  __exportStar(require("./dtos/responses/CreditPlanResponse"), exports);
39
48
  __exportStar(require("./dtos/responses/FinancierResponse"), exports);
40
49
  __exportStar(require("./dtos/responses/RetailerCreditPlanResponse"), exports);
41
50
  __exportStar(require("./dtos/responses/SimulationResultResponse"), exports);
51
+ __exportStar(require("./dtos/responses/PromotionResponse"), exports);
52
+ __exportStar(require("./dtos/responses/PromotionLogEntryResponse"), exports);
@@ -1,9 +1,26 @@
1
+ import { Status } from '../../../card/enums/Status';
2
+ import { VirtualOrPhysical } from '../../../card/enums/VirtualOrPhysical';
1
3
  import { CustomerResponse } from './CustomerResponse';
2
4
  /** Resumen de wallet (nivel N1/N2 + saldo) para el Cliente 360. */
3
5
  export interface Customer360Wallet {
4
6
  accountLevel: 1 | 2 | null;
5
7
  clabe: string | null;
6
- balanceCents: number;
8
+ /**
9
+ * Saldo en centavos, o `null` cuando la fuente no lo trajo. Era `number` a secas y eso obligaba
10
+ * a mandar `0` por un bloque ilegible, indistinguible de un saldo cero real.
11
+ */
12
+ balanceCents: number | null;
13
+ }
14
+ /**
15
+ * Tarjeta del cliente para el Cliente 360. Los campos espejan lo que devuelve `CardResponse` de
16
+ * `fiado-card-business`; `issued` en `false` deja los demás en `null` (no hay tarjeta que describir).
17
+ */
18
+ export interface Customer360Card {
19
+ issued: boolean;
20
+ /** Últimos dígitos del PAN, tal como los nombra `CardResponse.panLastDigit`. */
21
+ panLastDigit: string | null;
22
+ status: Status | null;
23
+ virtualOrPhysical: VirtualOrPhysical | null;
7
24
  }
8
25
  /** Ítem de compra en el historial del Cliente 360 (del GSI customerId-soldAt). */
9
26
  export interface Customer360Purchase {
@@ -28,6 +45,8 @@ export interface Customer360Prospect {
28
45
  export interface Customer360Response {
29
46
  customer: CustomerResponse;
30
47
  wallet: Customer360Wallet;
48
+ /** Tarjeta del cliente. Opcional: los consumidores que no la piden siguen compilando igual. */
49
+ card?: Customer360Card;
31
50
  purchases: Customer360Purchase[];
32
51
  prospects: Customer360Prospect[];
33
52
  }
@@ -1,3 +1,4 @@
1
+ import { KycReview } from '../KycReview';
1
2
  import { RetailAddress } from '../RetailAddress';
2
3
  import { AccountStatusEnum } from '../../enums/AccountStatusEnum';
3
4
  import { KycModalityEnum } from '../../enums/KycModalityEnum';
@@ -44,6 +45,11 @@ export interface CustomerResponse {
44
45
  kycStatus: RetailKycStatusEnum;
45
46
  kycModality: KycModalityEnum | null;
46
47
  kycScore: number | null;
48
+ /**
49
+ * Veredicto manual del oficial de Cumplimiento (D21), ya persistido en el cliente. Ausente
50
+ * mientras nadie resolvió el KYC a mano — opcional para no romper a los consumidores actuales.
51
+ */
52
+ kycReview?: KycReview;
47
53
  metamapVerificationId: string | null;
48
54
  pldFlag: boolean;
49
55
  notes: string | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.363.0",
3
+ "version": "3.364.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -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
+ /** Puntos de enganche que se restan al mínimo del plan (decimal sobre 1: `0.05` = 5 puntos). */
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 (decimal: `2.10` = 210%). */
12
+ tnaOverride: number | null;
13
+ /** Techo de monto financiable que reemplaza al del plan. */
14
+ maxAmountOverrideCents: number | null;
15
+ }
@@ -0,0 +1,19 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsEnum, IsOptional, IsString } from 'class-validator';
3
+ import { PromotionStatusEnum } from '../../enums/PromotionStatusEnum';
4
+
5
+ /**
6
+ * Body de PUT /promotions/:promotionId/status — publicar, pausar, reanudar o vencer.
7
+ * Transiciones válidas: `DRAFT→PUBLISHED`, `PUBLISHED⇄PAUSED`, `PUBLISHED|PAUSED→EXPIRED`.
8
+ * `reason` acompaña la pausa y queda en la bitácora.
9
+ */
10
+ export class ChangePromotionStatusRequest {
11
+ @Expose()
12
+ @IsEnum(PromotionStatusEnum)
13
+ status!: PromotionStatusEnum;
14
+
15
+ @Expose()
16
+ @IsOptional()
17
+ @IsString()
18
+ reason?: string | null;
19
+ }
@@ -0,0 +1,70 @@
1
+ import { Expose, Type } from 'class-transformer';
2
+ import {
3
+ ArrayNotEmpty,
4
+ IsArray,
5
+ IsEnum,
6
+ IsInt,
7
+ IsISO8601,
8
+ IsOptional,
9
+ IsString,
10
+ ValidateNested,
11
+ } from 'class-validator';
12
+ import { CreditPlanLevelEnum } from '../../enums/CreditPlanLevelEnum';
13
+ import { PromotionEffectInput } from './PromotionEffectInput';
14
+
15
+ /**
16
+ * Body de POST /promotions — alta de una promoción del motor.
17
+ * Nace en `DRAFT`: el estado, `promotionId`, `version`, los contadores de consumo y la auditoría
18
+ * los asigna el lambda y NO viajan en el request. `budgetMaxCents` ausente/`null` = sin tope.
19
+ */
20
+ export class CreatePromotionRequest {
21
+ @Expose()
22
+ @IsString()
23
+ name!: string;
24
+
25
+ @Expose()
26
+ @IsString()
27
+ description!: string;
28
+
29
+ @Expose()
30
+ @ValidateNested()
31
+ @Type(() => PromotionEffectInput)
32
+ effect!: PromotionEffectInput;
33
+
34
+ /** Segmento de clientes al que apunta la promoción. */
35
+ @Expose()
36
+ @IsString()
37
+ segmentId!: string;
38
+
39
+ @Expose()
40
+ @IsArray()
41
+ @ArrayNotEmpty()
42
+ @IsEnum(CreditPlanLevelEnum, { each: true })
43
+ targetLevels!: CreditPlanLevelEnum[];
44
+
45
+ /** SKUs alcanzados; ausente o `null` = todos los productos. */
46
+ @Expose()
47
+ @IsOptional()
48
+ @IsArray()
49
+ @IsString({ each: true })
50
+ productSkus?: string[] | null;
51
+
52
+ @Expose()
53
+ @IsOptional()
54
+ @IsISO8601()
55
+ validFrom?: string | null;
56
+
57
+ @Expose()
58
+ @IsOptional()
59
+ @IsISO8601()
60
+ validUntil?: string | null;
61
+
62
+ /**
63
+ * Tope de presupuesto en cents; `null` = sin tope. El signo lo valida el lambda (422): un
64
+ * presupuesto negativo es un request bien formado que el negocio rechaza.
65
+ */
66
+ @Expose()
67
+ @IsOptional()
68
+ @IsInt()
69
+ budgetMaxCents?: number | null;
70
+ }
@@ -0,0 +1,33 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsInt, IsNumber, IsOptional } from 'class-validator';
3
+
4
+ /**
5
+ * Efecto de la promoción tal como viaja en el body (alta y edición). Acá se valida solo la FORMA
6
+ * (que sea número o entero). Las cotas de negocio — rango de cada palanca y que venga al menos una
7
+ * clave — las valida el lambda con 422: son reglas del negocio sobre un body bien formado.
8
+ */
9
+ export class PromotionEffectInput {
10
+ /** Puntos de enganche a restar del mínimo del plan (decimal sobre 1). */
11
+ @Expose()
12
+ @IsOptional()
13
+ @IsNumber()
14
+ downPaymentDeltaPct?: number | null;
15
+
16
+ /** Bono a la tarjeta PCF, en cents. */
17
+ @Expose()
18
+ @IsOptional()
19
+ @IsInt()
20
+ pcfBonusCents?: number | null;
21
+
22
+ /** TNA que reemplaza a la del plan (decimal); rango de negocio [2.00, 2.60]. */
23
+ @Expose()
24
+ @IsOptional()
25
+ @IsNumber()
26
+ tnaOverride?: number | null;
27
+
28
+ /** Techo de monto financiable que reemplaza al del plan, en cents. */
29
+ @Expose()
30
+ @IsOptional()
31
+ @IsInt()
32
+ maxAmountOverrideCents?: number | null;
33
+ }
@@ -0,0 +1,69 @@
1
+ import { Expose, Type } from 'class-transformer';
2
+ import {
3
+ ArrayNotEmpty,
4
+ IsArray,
5
+ IsEnum,
6
+ IsInt,
7
+ IsISO8601,
8
+ IsOptional,
9
+ IsString,
10
+ ValidateNested,
11
+ } from 'class-validator';
12
+ import { CreditPlanLevelEnum } from '../../enums/CreditPlanLevelEnum';
13
+ import { PromotionEffectInput } from './PromotionEffectInput';
14
+
15
+ /**
16
+ * Body de PUT /promotions/:promotionId — edición parcial (todos los campos opcionales).
17
+ * Solo se admite sobre `DRAFT` y `PUBLISHED`, y sube `version`. El cambio de estado va por su
18
+ * endpoint dedicado. `effect` se reemplaza entero cuando viene, no se mergea clave a clave.
19
+ */
20
+ export class UpdatePromotionRequest {
21
+ @Expose()
22
+ @IsOptional()
23
+ @IsString()
24
+ name?: string;
25
+
26
+ @Expose()
27
+ @IsOptional()
28
+ @IsString()
29
+ description?: string;
30
+
31
+ @Expose()
32
+ @IsOptional()
33
+ @ValidateNested()
34
+ @Type(() => PromotionEffectInput)
35
+ effect?: PromotionEffectInput;
36
+
37
+ @Expose()
38
+ @IsOptional()
39
+ @IsString()
40
+ segmentId?: string;
41
+
42
+ @Expose()
43
+ @IsOptional()
44
+ @IsArray()
45
+ @ArrayNotEmpty()
46
+ @IsEnum(CreditPlanLevelEnum, { each: true })
47
+ targetLevels?: CreditPlanLevelEnum[];
48
+
49
+ @Expose()
50
+ @IsOptional()
51
+ @IsArray()
52
+ @IsString({ each: true })
53
+ productSkus?: string[] | null;
54
+
55
+ @Expose()
56
+ @IsOptional()
57
+ @IsISO8601()
58
+ validFrom?: string | null;
59
+
60
+ @Expose()
61
+ @IsOptional()
62
+ @IsISO8601()
63
+ validUntil?: string | null;
64
+
65
+ @Expose()
66
+ @IsOptional()
67
+ @IsInt()
68
+ budgetMaxCents?: number | null;
69
+ }
@@ -0,0 +1,18 @@
1
+ import { PromotionLogEventEnum } from '../../enums/PromotionLogEventEnum';
2
+ import { PromotionStatusEnum } from '../../enums/PromotionStatusEnum';
3
+
4
+ /**
5
+ * Fila del tab «Auditoría»: un evento de la bitácora de promociones.
6
+ * `fromStatus` es `null` en el alta; `reason` solo viene cargado en la pausa.
7
+ */
8
+ export interface PromotionLogEntryResponse {
9
+ promotionId: string;
10
+ promotionName: string;
11
+ event: PromotionLogEventEnum;
12
+ occurredAt: string;
13
+ performedBy: string;
14
+ fromStatus: PromotionStatusEnum | null;
15
+ toStatus: PromotionStatusEnum | null;
16
+ reason: string | null;
17
+ version: number;
18
+ }
@@ -0,0 +1,43 @@
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
+ /**
8
+ * Shape de salida de una promoción (GET / POST / PUT de /promotions).
9
+ * Montos en cents; porcentajes y TNA en decimal.
10
+ *
11
+ * `effectKind` y `phase` son DERIVADOS y no viven en la tabla: el primero sale de las claves de
12
+ * `effect`, el segundo de las fechas contra hoy y solo cuando el estado es `PUBLISHED`.
13
+ */
14
+ export interface PromotionResponse {
15
+ promotionId: string;
16
+ name: string;
17
+ description: string;
18
+ effect: PromotionEffect;
19
+ /** Derivado de las claves de `effect`; `COMBO` si hay dos o más, `null` si no hay ninguna. */
20
+ effectKind: PromotionEffectKindEnum | null;
21
+ segmentId: string;
22
+ targetLevels: CreditPlanLevelEnum[];
23
+ /** `null` = alcanza a todos los productos. */
24
+ productSkus: string[] | null;
25
+ validFrom: string | null;
26
+ validUntil: string | null;
27
+ status: PromotionStatusEnum;
28
+ /** Fase de vigencia derivada; `null` cuando el estado no es `PUBLISHED`. */
29
+ phase: PromotionPhaseEnum | null;
30
+ /** Tope de presupuesto; `null` = sin tope. */
31
+ budgetMaxCents: number | null;
32
+ budgetConsumedCents: number;
33
+ creditsGenerated: number;
34
+ version: number;
35
+ pausedAt: string | null;
36
+ pauseReason: string | null;
37
+ publishedAt: string | null;
38
+ publishedBy: string | null;
39
+ createdBy: string;
40
+ updatedBy: string;
41
+ createdAt: string;
42
+ updatedAt: string;
43
+ }
@@ -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 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,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 enum PromotionLogEventEnum {
6
+ CREATE = 'CREATE',
7
+ PUBLISH = 'PUBLISH',
8
+ PAUSE = 'PAUSE',
9
+ RESUME = 'RESUME',
10
+ EXPIRE = 'EXPIRE',
11
+ UPDATE = 'UPDATE',
12
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Fase de vigencia de una promoción PUBLICADA, derivada de `validFrom`/`validUntil` contra hoy.
3
+ * No se persiste — así no hace falta un cron que mueva estados a medianoche. `null` cuando el
4
+ * estado persistido no es `PUBLISHED`.
5
+ * @enum {string}
6
+ */
7
+ export enum PromotionPhaseEnum {
8
+ SCHEDULED = 'SCHEDULED',
9
+ ACTIVE = 'ACTIVE',
10
+ EXPIRED = 'EXPIRED',
11
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Estado PERSISTIDO de una promoción del motor (portal-admin-sk-promociones).
3
+ * `EXPIRED` es terminal. La «fase» que ve el operador (programada / activa / vencida) NO se guarda:
4
+ * se deriva de las fechas — ver `PromotionPhaseEnum`.
5
+ * @enum {string}
6
+ */
7
+ export enum PromotionStatusEnum {
8
+ DRAFT = 'DRAFT',
9
+ PUBLISHED = 'PUBLISHED',
10
+ PAUSED = 'PAUSED',
11
+ EXPIRED = 'EXPIRED',
12
+ }
@@ -5,11 +5,16 @@ export * from './enums/ProductTierEnum';
5
5
  export * from './enums/CreditPlanStatusEnum';
6
6
  export * from './enums/FinancierTypeEnum';
7
7
  export * from './enums/FinancierStatusEnum';
8
+ export * from './enums/PromotionStatusEnum';
9
+ export * from './enums/PromotionEffectKindEnum';
10
+ export * from './enums/PromotionPhaseEnum';
11
+ export * from './enums/PromotionLogEventEnum';
8
12
 
9
13
  // Entity DTOs
10
14
  export * from './dtos/CreditPlan';
11
15
  export * from './dtos/Financier';
12
16
  export * from './dtos/RetailerCreditPlan';
17
+ export * from './dtos/PromotionEffect';
13
18
 
14
19
  // Request DTOs
15
20
  export * from './dtos/requests/CreateCreditPlanRequest';
@@ -20,9 +25,15 @@ export * from './dtos/requests/CreateFinancierRequest';
20
25
  export * from './dtos/requests/UpdateFinancierRequest';
21
26
  export * from './dtos/requests/ChangeFinancierStatusRequest';
22
27
  export * from './dtos/requests/ReorderFinancierRequest';
28
+ export * from './dtos/requests/PromotionEffectInput';
29
+ export * from './dtos/requests/CreatePromotionRequest';
30
+ export * from './dtos/requests/UpdatePromotionRequest';
31
+ export * from './dtos/requests/ChangePromotionStatusRequest';
23
32
 
24
33
  // Response DTOs
25
34
  export * from './dtos/responses/CreditPlanResponse';
26
35
  export * from './dtos/responses/FinancierResponse';
27
36
  export * from './dtos/responses/RetailerCreditPlanResponse';
28
37
  export * from './dtos/responses/SimulationResultResponse';
38
+ export * from './dtos/responses/PromotionResponse';
39
+ export * from './dtos/responses/PromotionLogEntryResponse';
@@ -1,10 +1,28 @@
1
+ import { Status } from '../../../card/enums/Status';
2
+ import { VirtualOrPhysical } from '../../../card/enums/VirtualOrPhysical';
1
3
  import { CustomerResponse } from './CustomerResponse';
2
4
 
3
5
  /** Resumen de wallet (nivel N1/N2 + saldo) para el Cliente 360. */
4
6
  export interface Customer360Wallet {
5
7
  accountLevel: 1 | 2 | null;
6
8
  clabe: string | null;
7
- balanceCents: number;
9
+ /**
10
+ * Saldo en centavos, o `null` cuando la fuente no lo trajo. Era `number` a secas y eso obligaba
11
+ * a mandar `0` por un bloque ilegible, indistinguible de un saldo cero real.
12
+ */
13
+ balanceCents: number | null;
14
+ }
15
+
16
+ /**
17
+ * Tarjeta del cliente para el Cliente 360. Los campos espejan lo que devuelve `CardResponse` de
18
+ * `fiado-card-business`; `issued` en `false` deja los demás en `null` (no hay tarjeta que describir).
19
+ */
20
+ export interface Customer360Card {
21
+ issued: boolean;
22
+ /** Últimos dígitos del PAN, tal como los nombra `CardResponse.panLastDigit`. */
23
+ panLastDigit: string | null;
24
+ status: Status | null;
25
+ virtualOrPhysical: VirtualOrPhysical | null;
8
26
  }
9
27
 
10
28
  /** Ítem de compra en el historial del Cliente 360 (del GSI customerId-soldAt). */
@@ -32,6 +50,8 @@ export interface Customer360Prospect {
32
50
  export interface Customer360Response {
33
51
  customer: CustomerResponse;
34
52
  wallet: Customer360Wallet;
53
+ /** Tarjeta del cliente. Opcional: los consumidores que no la piden siguen compilando igual. */
54
+ card?: Customer360Card;
35
55
  purchases: Customer360Purchase[];
36
56
  prospects: Customer360Prospect[];
37
57
  }
@@ -1,3 +1,4 @@
1
+ import { KycReview } from '../KycReview';
1
2
  import { RetailAddress } from '../RetailAddress';
2
3
  import { AccountStatusEnum } from '../../enums/AccountStatusEnum';
3
4
  import { KycModalityEnum } from '../../enums/KycModalityEnum';
@@ -45,6 +46,11 @@ export interface CustomerResponse {
45
46
  kycStatus: RetailKycStatusEnum;
46
47
  kycModality: KycModalityEnum | null;
47
48
  kycScore: number | null;
49
+ /**
50
+ * Veredicto manual del oficial de Cumplimiento (D21), ya persistido en el cliente. Ausente
51
+ * mientras nadie resolvió el KYC a mano — opcional para no romper a los consumidores actuales.
52
+ */
53
+ kycReview?: KycReview;
48
54
  metamapVerificationId: string | null;
49
55
  pldFlag: boolean;
50
56
  notes: string | null;