@fiado/type-kit 3.488.0 → 3.490.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 (35) hide show
  1. package/_test_/unit/loanOfferings/appliedPromotionBonus.test.ts +22 -0
  2. package/_test_/unit/retailCustomer/promotionBonusContract.test.ts +101 -0
  3. package/_test_/unit/retailCustomer/upsertCustomerFromKycRequest.test.ts +51 -0
  4. package/_test_/unit/retailWizard/creditPromotionBonusContract.test.ts +26 -0
  5. package/bin/loanOfferings/dtos/responses/SimulationResultResponse.d.ts +2 -0
  6. package/bin/retailCustomer/dtos/requests/UpsertCustomerFromKycRequest.d.ts +5 -0
  7. package/bin/retailCustomer/dtos/requests/UpsertCustomerFromKycRequest.js +13 -0
  8. package/bin/retailCustomer/dtos/requests/UpsertPromotionBonusRequest.d.ts +27 -0
  9. package/bin/retailCustomer/dtos/requests/UpsertPromotionBonusRequest.js +139 -0
  10. package/bin/retailCustomer/dtos/responses/PromotionBonusEntryResponse.d.ts +27 -0
  11. package/bin/retailCustomer/dtos/responses/PromotionBonusEntryResponse.js +2 -0
  12. package/bin/retailCustomer/enums/BonusTypeEnum.d.ts +6 -0
  13. package/bin/retailCustomer/enums/BonusTypeEnum.js +10 -0
  14. package/bin/retailCustomer/enums/KycMethodEnum.d.ts +5 -0
  15. package/bin/retailCustomer/enums/KycMethodEnum.js +9 -0
  16. package/bin/retailCustomer/index.d.ts +4 -0
  17. package/bin/retailCustomer/index.js +4 -0
  18. package/bin/retailWizard/dtos/WizardCreditPromotionBonus.d.ts +8 -0
  19. package/bin/retailWizard/dtos/WizardCreditPromotionBonus.js +2 -0
  20. package/bin/retailWizard/dtos/WizardSession.d.ts +3 -0
  21. package/bin/retailWizard/dtos/responses/QuoteResponse.d.ts +2 -0
  22. package/bin/retailWizard/index.d.ts +1 -0
  23. package/bin/retailWizard/index.js +1 -0
  24. package/package.json +1 -1
  25. package/src/loanOfferings/dtos/responses/SimulationResultResponse.ts +2 -0
  26. package/src/retailCustomer/dtos/requests/UpsertCustomerFromKycRequest.ts +13 -0
  27. package/src/retailCustomer/dtos/requests/UpsertPromotionBonusRequest.ts +121 -0
  28. package/src/retailCustomer/dtos/responses/PromotionBonusEntryResponse.ts +28 -0
  29. package/src/retailCustomer/enums/BonusTypeEnum.ts +6 -0
  30. package/src/retailCustomer/enums/KycMethodEnum.ts +5 -0
  31. package/src/retailCustomer/index.ts +4 -0
  32. package/src/retailWizard/dtos/WizardCreditPromotionBonus.ts +9 -0
  33. package/src/retailWizard/dtos/WizardSession.ts +3 -0
  34. package/src/retailWizard/dtos/responses/QuoteResponse.ts +2 -0
  35. package/src/retailWizard/index.ts +1 -0
@@ -0,0 +1,22 @@
1
+ import 'reflect-metadata';
2
+ import { LoanOfferings } from '../../../src/index';
3
+ import type { AppliedPromotionResponse } from '../../../src/loanOfferings/index';
4
+
5
+ describe('AppliedPromotionResponse.pcfBonusCents', () => {
6
+ it('la ganadora del bono lo trae; las demás lo omiten', () => {
7
+ const winner: AppliedPromotionResponse = {
8
+ promotionId: 'p-1',
9
+ name: 'Bono',
10
+ version: 2,
11
+ appliedEffects: [LoanOfferings.PromotionEffectKindEnum.PCF_BONUS],
12
+ pcfBonusCents: 5_000,
13
+ };
14
+ const other: AppliedPromotionResponse = {
15
+ promotionId: 'p-0',
16
+ name: 'Tasa',
17
+ version: 1,
18
+ appliedEffects: [LoanOfferings.PromotionEffectKindEnum.TNA_OVERRIDE],
19
+ };
20
+ expect([winner.pcfBonusCents, other.pcfBonusCents]).toEqual([5_000, undefined]);
21
+ });
22
+ });
@@ -0,0 +1,101 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validateSync } from 'class-validator';
4
+ import { RetailCustomer } from '../../../src/index';
5
+ import { BonusTypeEnum, UpsertPromotionBonusRequest } from '../../../src/retailCustomer/index';
6
+ import type { PromotionBonusEntryResponse } from '../../../src/retailCustomer/index';
7
+
8
+ describe('BonusTypeEnum', () => {
9
+ it('distingue la bienvenida de las dos promociones', () => {
10
+ expect(Object.values(BonusTypeEnum)).toEqual(['WELCOME', 'CREDIT_PROMOTION', 'SALE_PROMOTION']);
11
+ });
12
+
13
+ it('sale por el index raíz', () => {
14
+ expect(RetailCustomer.BonusTypeEnum.SALE_PROMOTION).toBe('SALE_PROMOTION');
15
+ });
16
+ });
17
+
18
+ /** Valida como retail-customer-business: con `@Expose` y `excludeExtraneousValues`. */
19
+ function errorsOf(payload: Record<string, unknown>): string[] {
20
+ const dto = plainToInstance(UpsertPromotionBonusRequest, payload, { excludeExtraneousValues: true });
21
+ return validateSync(dto).map((e) => e.property);
22
+ }
23
+
24
+ const PENDING_SALE = {
25
+ bonusType: 'SALE_PROMOTION',
26
+ promotionId: 'promo-1',
27
+ sourceId: 'sale-1',
28
+ storeId: 'st-1',
29
+ amountCents: 10_000,
30
+ currency: 'MXN',
31
+ status: 'PENDING',
32
+ idempotencyKey: 'sale-1-WALLET-1',
33
+ };
34
+
35
+ describe('UpsertPromotionBonusRequest', () => {
36
+ it('acepta el PENDING «sin cuenta todavía», sin directorio', () => {
37
+ expect(errorsOf(PENDING_SALE)).toEqual([]);
38
+ });
39
+
40
+ it('ACCREDITED exige el directorio que recibió el depósito', () => {
41
+ expect(errorsOf({ ...PENDING_SALE, status: 'ACCREDITED' })).toContain('fiadoDirectoryId');
42
+ expect(errorsOf({ ...PENDING_SALE, status: 'ACCREDITED', fiadoDirectoryId: 'dir-1' })).toEqual([]);
43
+ });
44
+
45
+ it.each(['FAILED', 'UNVERIFIED'])('%s exige el motivo', (status) => {
46
+ expect(errorsOf({ ...PENDING_SALE, status })).toContain('failReason');
47
+ expect(errorsOf({ ...PENDING_SALE, status, failReason: 'VOID_EXPIRED' })).toEqual([]);
48
+ });
49
+
50
+ it('rechaza WELCOME: la bienvenida tiene su propio endpoint', () => {
51
+ expect(errorsOf({ ...PENDING_SALE, bonusType: 'WELCOME' })).toContain('bonusType');
52
+ });
53
+
54
+ it.each(['promotionId', 'sourceId', 'storeId', 'currency', 'idempotencyKey'])('rechaza %s vacío', (field) => {
55
+ expect(errorsOf({ ...PENDING_SALE, [field]: ' ' })).toContain(field);
56
+ });
57
+
58
+ it.each([0, -1, 1.5])('rechaza el monto %p', (amountCents) => {
59
+ expect(errorsOf({ ...PENDING_SALE, amountCents })).toContain('amountCents');
60
+ });
61
+
62
+ it('rechaza un estado fuera del libro', () => {
63
+ expect(errorsOf({ ...PENDING_SALE, status: 'SETTLED' })).toContain('status');
64
+ });
65
+
66
+ it('rechaza un motivo de más de 256 caracteres', () => {
67
+ expect(errorsOf({ ...PENDING_SALE, status: 'FAILED', failReason: 'x'.repeat(257) })).toContain('failReason');
68
+ });
69
+
70
+ it('sale por el index raíz', () => {
71
+ expect(new RetailCustomer.UpsertPromotionBonusRequest()).toBeInstanceOf(UpsertPromotionBonusRequest);
72
+ });
73
+ });
74
+
75
+ describe('PromotionBonusEntryResponse', () => {
76
+ it('describe el asiento de promo con su fuente', () => {
77
+ const entry: PromotionBonusEntryResponse = {
78
+ bonusId: 'B-1',
79
+ bonusType: BonusTypeEnum.CREDIT_PROMOTION,
80
+ promotionId: 'promo-1',
81
+ sourceId: 'credit-1',
82
+ retailCustomerId: 'rc-1',
83
+ fiadoDirectoryId: null,
84
+ saleId: null,
85
+ creditId: 'credit-1',
86
+ storeId: 'st-1',
87
+ amountCents: 5_000,
88
+ currency: 'MXN',
89
+ status: RetailCustomer.WelcomeBonusStatusEnum.PENDING,
90
+ failReason: null,
91
+ processorTransactionId: null,
92
+ idempotencyKey: 'credit-1',
93
+ fundedBy: 'VENTASLUGA',
94
+ settlementStatus: RetailCustomer.WelcomeBonusSettlementStatusEnum.PENDING,
95
+ resolvedAt: null,
96
+ createdAt: '2026-10-02T00:00:00.000Z',
97
+ updatedAt: '2026-10-02T00:00:00.000Z',
98
+ };
99
+ expect(entry.sourceId).toBe('credit-1');
100
+ });
101
+ });
@@ -0,0 +1,51 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validateSync } from 'class-validator';
4
+ import { UpsertCustomerFromKycRequest } from '../../../src/retailCustomer/dtos/requests/UpsertCustomerFromKycRequest';
5
+ import { KycMethodEnum } from '../../../src/retailCustomer/enums/KycMethodEnum';
6
+ import { KycModalityEnum } from '../../../src/retailCustomer/enums/KycModalityEnum';
7
+ import { RetailKycStatusEnum } from '../../../src/retailCustomer/enums/RetailKycStatusEnum';
8
+
9
+ /** Valida como lo hace `retail-customer-business`: con `@Expose` y `excludeExtraneousValues`. */
10
+ function toDto(payload: Record<string, unknown>): UpsertCustomerFromKycRequest {
11
+ return plainToInstance(UpsertCustomerFromKycRequest, payload, { excludeExtraneousValues: true });
12
+ }
13
+
14
+ const base = {
15
+ originStoreId: 'store-1',
16
+ names: 'Ana',
17
+ paternalLastName: 'Pérez',
18
+ phone: '5512345678',
19
+ curp: 'PEGA900101MDFRRN09',
20
+ fiadoDirectoryId: 'dir-1',
21
+ fiadoPeopleId: 'people-1',
22
+ kycStatus: Object.values(RetailKycStatusEnum)[0],
23
+ kycModality: KycModalityEnum.STORE_DEVICE,
24
+ };
25
+
26
+ describe('UpsertCustomerFromKycRequest — método de KYC', () => {
27
+ it('KycMethodEnum expone FULL_KYC y FACEMATCH', () => {
28
+ expect(Object.values(KycMethodEnum)).toEqual(['FULL_KYC', 'FACEMATCH']);
29
+ });
30
+
31
+ it('acepta el payload sin kycMethod ni biometricVerificationId', () => {
32
+ expect(validateSync(toDto(base)).map((e) => e.property)).toEqual([]);
33
+ });
34
+
35
+ it('conserva kycMethod y biometricVerificationId del alta por facematch', () => {
36
+ const dto = toDto({ ...base, kycMethod: KycMethodEnum.FACEMATCH, biometricVerificationId: 'bv-1' });
37
+ expect(validateSync(dto)).toEqual([]);
38
+ expect(dto.kycMethod).toBe(KycMethodEnum.FACEMATCH);
39
+ expect(dto.biometricVerificationId).toBe('bv-1');
40
+ });
41
+
42
+ it('rechaza un kycMethod fuera del catálogo', () => {
43
+ expect(validateSync(toDto({ ...base, kycMethod: 'SELFIE' })).map((e) => e.property)).toEqual(['kycMethod']);
44
+ });
45
+
46
+ it('rechaza un biometricVerificationId que no es string', () => {
47
+ expect(validateSync(toDto({ ...base, biometricVerificationId: 42 })).map((e) => e.property)).toEqual([
48
+ 'biometricVerificationId',
49
+ ]);
50
+ });
51
+ });
@@ -0,0 +1,26 @@
1
+ import 'reflect-metadata';
2
+ import { LoanOfferings } from '../../../src/index';
3
+ import type { QuoteResponse, WizardCreditPromotionBonus, WizardSession } from '../../../src/retailWizard/index';
4
+
5
+ describe('bono de crédito en el contrato del wizard', () => {
6
+ it('la sesión lleva el desenlace persistido del bono de crédito', () => {
7
+ const bonus: WizardCreditPromotionBonus = {
8
+ promotionId: 'promo-1',
9
+ amountCents: 5_000,
10
+ status: LoanOfferings.PromotionBonusStatusEnum.RESERVED,
11
+ };
12
+ const session: Pick<WizardSession, 'creditPromotionBonus'> = { creditPromotionBonus: bonus };
13
+ expect(session.creditPromotionBonus?.status).toBe('RESERVED');
14
+ });
15
+
16
+ it('la sesión sin bono resuelto lo omite o lo manda null', () => {
17
+ const absent: Pick<WizardSession, 'creditPromotionBonus'> = {};
18
+ const nulled: Pick<WizardSession, 'creditPromotionBonus'> = { creditPromotionBonus: null };
19
+ expect([absent.creditPromotionBonus, nulled.creditPromotionBonus]).toEqual([undefined, null]);
20
+ });
21
+
22
+ it('la cotización puede traer el monto del bono que se cotizó', () => {
23
+ const quote: Pick<QuoteResponse, 'creditPromotionBonusCents'> = { creditPromotionBonusCents: 5_000 };
24
+ expect(quote.creditPromotionBonusCents).toBe(5_000);
25
+ });
26
+ });
@@ -27,6 +27,8 @@ export interface AppliedPromotionResponse {
27
27
  version: number;
28
28
  /** Palancas del plan que la promoción pisó. */
29
29
  appliedEffects: PromotionEffectKindEnum[];
30
+ /** Monto del bono PCF; solo en la promoción que gana el bono de la cotización. */
31
+ pcfBonusCents?: number;
30
32
  }
31
33
  /**
32
34
  * Una `CreditPlan` que el paso Base consideró para esta venta, haya ganado algún término o no.
@@ -1,4 +1,5 @@
1
1
  import { RetailAddress } from '../RetailAddress';
2
+ import { KycMethodEnum } from '../../enums/KycMethodEnum';
2
3
  import { KycModalityEnum } from '../../enums/KycModalityEnum';
3
4
  import { RetailKycStatusEnum } from '../../enums/RetailKycStatusEnum';
4
5
  /**
@@ -47,6 +48,10 @@ export declare class UpsertCustomerFromKycRequest {
47
48
  hasActiveMxAccount?: boolean;
48
49
  kycStatus: RetailKycStatusEnum;
49
50
  kycModality: KycModalityEnum;
51
+ /** Método con el que se verificó la identidad. Ausente = no pisa el valor guardado. */
52
+ kycMethod?: KycMethodEnum;
53
+ /** Verificación biométrica de `biometrics-business` que respaldó el alta por facematch. */
54
+ biometricVerificationId?: string;
50
55
  /**
51
56
  * Domicilio del INE (paso 02e), ya normalizado contra `places-business`. Se persiste embebido en la
52
57
  * MISMA TX del upsert.
@@ -14,6 +14,7 @@ const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
15
  const regex_1 = require("../../../helpers/constans/regex");
16
16
  const RetailAddress_1 = require("../RetailAddress");
17
+ const KycMethodEnum_1 = require("../../enums/KycMethodEnum");
17
18
  const KycModalityEnum_1 = require("../../enums/KycModalityEnum");
18
19
  const RetailKycStatusEnum_1 = require("../../enums/RetailKycStatusEnum");
19
20
  /**
@@ -141,6 +142,18 @@ __decorate([
141
142
  (0, class_validator_1.IsEnum)(KycModalityEnum_1.KycModalityEnum),
142
143
  __metadata("design:type", String)
143
144
  ], UpsertCustomerFromKycRequest.prototype, "kycModality", void 0);
145
+ __decorate([
146
+ (0, class_transformer_1.Expose)(),
147
+ (0, class_validator_1.IsOptional)(),
148
+ (0, class_validator_1.IsEnum)(KycMethodEnum_1.KycMethodEnum),
149
+ __metadata("design:type", String)
150
+ ], UpsertCustomerFromKycRequest.prototype, "kycMethod", void 0);
151
+ __decorate([
152
+ (0, class_transformer_1.Expose)(),
153
+ (0, class_validator_1.IsOptional)(),
154
+ (0, class_validator_1.IsString)(),
155
+ __metadata("design:type", String)
156
+ ], UpsertCustomerFromKycRequest.prototype, "biometricVerificationId", void 0);
144
157
  __decorate([
145
158
  (0, class_transformer_1.Expose)(),
146
159
  (0, class_validator_1.IsOptional)(),
@@ -0,0 +1,27 @@
1
+ import { BonusTypeEnum } from '../../enums/BonusTypeEnum';
2
+ import { WelcomeBonusStatusEnum } from '../../enums/WelcomeBonusStatusEnum';
3
+ /**
4
+ * Asiento de un bono de promoción en el libro de bonos:
5
+ * `PUT /private/customers/:id/promotion-bonuses`. El libro es espejo del sistema de la promo.
6
+ */
7
+ export declare class UpsertPromotionBonusRequest {
8
+ bonusType: BonusTypeEnum;
9
+ promotionId: string;
10
+ /** `creditId` en la promo de crédito, `saleId` en la de venta. */
11
+ sourceId: string;
12
+ /** Tienda de la venta: es la partición del asiento. */
13
+ storeId: string;
14
+ /** Obligatorio con `ACCREDITED`; el `PENDING` «sin cuenta todavía» no lo tiene. */
15
+ fiadoDirectoryId?: string;
16
+ amountCents: number;
17
+ currency: string;
18
+ status: WelcomeBonusStatusEnum;
19
+ idempotencyKey: string;
20
+ processorTransactionId?: string;
21
+ /** Resumen legible, sin el payload crudo del processor (el libro va sin PII). */
22
+ failReason?: string;
23
+ saleId?: string;
24
+ folio?: string;
25
+ wizardSessionId?: string;
26
+ sellerRetailUserId?: string;
27
+ }
@@ -0,0 +1,139 @@
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.UpsertPromotionBonusRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const Trim_1 = require("../../../common/decorators/Trim");
16
+ const BonusTypeEnum_1 = require("../../enums/BonusTypeEnum");
17
+ const WelcomeBonusStatusEnum_1 = require("../../enums/WelcomeBonusStatusEnum");
18
+ /** Tope del motivo libre que el caller escribe en el asiento. */
19
+ const FREE_TEXT_MAX_LENGTH = 256;
20
+ const PROMOTION_BONUS_TYPES = [BonusTypeEnum_1.BonusTypeEnum.CREDIT_PROMOTION, BonusTypeEnum_1.BonusTypeEnum.SALE_PROMOTION];
21
+ const STATUSES_REQUIRING_REASON = [
22
+ WelcomeBonusStatusEnum_1.WelcomeBonusStatusEnum.FAILED,
23
+ WelcomeBonusStatusEnum_1.WelcomeBonusStatusEnum.UNVERIFIED,
24
+ ];
25
+ /**
26
+ * Asiento de un bono de promoción en el libro de bonos:
27
+ * `PUT /private/customers/:id/promotion-bonuses`. El libro es espejo del sistema de la promo.
28
+ */
29
+ class UpsertPromotionBonusRequest {
30
+ }
31
+ exports.UpsertPromotionBonusRequest = UpsertPromotionBonusRequest;
32
+ __decorate([
33
+ (0, class_transformer_1.Expose)(),
34
+ (0, class_validator_1.IsIn)(PROMOTION_BONUS_TYPES),
35
+ __metadata("design:type", String)
36
+ ], UpsertPromotionBonusRequest.prototype, "bonusType", void 0);
37
+ __decorate([
38
+ (0, class_transformer_1.Expose)(),
39
+ (0, Trim_1.Trim)(),
40
+ (0, class_validator_1.IsString)(),
41
+ (0, class_validator_1.IsNotEmpty)(),
42
+ __metadata("design:type", String)
43
+ ], UpsertPromotionBonusRequest.prototype, "promotionId", void 0);
44
+ __decorate([
45
+ (0, class_transformer_1.Expose)(),
46
+ (0, Trim_1.Trim)(),
47
+ (0, class_validator_1.IsString)(),
48
+ (0, class_validator_1.IsNotEmpty)(),
49
+ __metadata("design:type", String)
50
+ ], UpsertPromotionBonusRequest.prototype, "sourceId", void 0);
51
+ __decorate([
52
+ (0, class_transformer_1.Expose)(),
53
+ (0, Trim_1.Trim)(),
54
+ (0, class_validator_1.IsString)(),
55
+ (0, class_validator_1.IsNotEmpty)(),
56
+ __metadata("design:type", String)
57
+ ], UpsertPromotionBonusRequest.prototype, "storeId", void 0);
58
+ __decorate([
59
+ (0, class_transformer_1.Expose)(),
60
+ (0, class_validator_1.ValidateIf)((o) => o.status === WelcomeBonusStatusEnum_1.WelcomeBonusStatusEnum.ACCREDITED || o.fiadoDirectoryId !== undefined),
61
+ (0, Trim_1.Trim)(),
62
+ (0, class_validator_1.IsString)(),
63
+ (0, class_validator_1.IsNotEmpty)({ message: 'fiadoDirectoryId es obligatorio cuando status es ACCREDITED' }),
64
+ __metadata("design:type", String)
65
+ ], UpsertPromotionBonusRequest.prototype, "fiadoDirectoryId", void 0);
66
+ __decorate([
67
+ (0, class_transformer_1.Expose)(),
68
+ (0, class_validator_1.IsInt)(),
69
+ (0, class_validator_1.IsPositive)(),
70
+ __metadata("design:type", Number)
71
+ ], UpsertPromotionBonusRequest.prototype, "amountCents", void 0);
72
+ __decorate([
73
+ (0, class_transformer_1.Expose)(),
74
+ (0, Trim_1.Trim)(),
75
+ (0, class_validator_1.IsString)(),
76
+ (0, class_validator_1.IsNotEmpty)(),
77
+ __metadata("design:type", String)
78
+ ], UpsertPromotionBonusRequest.prototype, "currency", void 0);
79
+ __decorate([
80
+ (0, class_transformer_1.Expose)(),
81
+ (0, class_validator_1.IsIn)(Object.values(WelcomeBonusStatusEnum_1.WelcomeBonusStatusEnum)),
82
+ __metadata("design:type", String)
83
+ ], UpsertPromotionBonusRequest.prototype, "status", void 0);
84
+ __decorate([
85
+ (0, class_transformer_1.Expose)(),
86
+ (0, Trim_1.Trim)(),
87
+ (0, class_validator_1.IsString)(),
88
+ (0, class_validator_1.IsNotEmpty)(),
89
+ __metadata("design:type", String)
90
+ ], UpsertPromotionBonusRequest.prototype, "idempotencyKey", void 0);
91
+ __decorate([
92
+ (0, class_transformer_1.Expose)(),
93
+ (0, class_validator_1.IsOptional)(),
94
+ (0, Trim_1.Trim)(),
95
+ (0, class_validator_1.IsString)(),
96
+ (0, class_validator_1.IsNotEmpty)(),
97
+ __metadata("design:type", String)
98
+ ], UpsertPromotionBonusRequest.prototype, "processorTransactionId", void 0);
99
+ __decorate([
100
+ (0, class_transformer_1.Expose)(),
101
+ (0, class_validator_1.ValidateIf)((o) => STATUSES_REQUIRING_REASON.includes(o.status)),
102
+ (0, Trim_1.Trim)(),
103
+ (0, class_validator_1.IsString)(),
104
+ (0, class_validator_1.IsNotEmpty)({ message: 'failReason es obligatorio cuando status es FAILED o UNVERIFIED' }),
105
+ (0, class_validator_1.MaxLength)(FREE_TEXT_MAX_LENGTH),
106
+ __metadata("design:type", String)
107
+ ], UpsertPromotionBonusRequest.prototype, "failReason", void 0);
108
+ __decorate([
109
+ (0, class_transformer_1.Expose)(),
110
+ (0, class_validator_1.IsOptional)(),
111
+ (0, Trim_1.Trim)(),
112
+ (0, class_validator_1.IsString)(),
113
+ (0, class_validator_1.IsNotEmpty)(),
114
+ __metadata("design:type", String)
115
+ ], UpsertPromotionBonusRequest.prototype, "saleId", void 0);
116
+ __decorate([
117
+ (0, class_transformer_1.Expose)(),
118
+ (0, class_validator_1.IsOptional)(),
119
+ (0, Trim_1.Trim)(),
120
+ (0, class_validator_1.IsString)(),
121
+ (0, class_validator_1.IsNotEmpty)(),
122
+ __metadata("design:type", String)
123
+ ], UpsertPromotionBonusRequest.prototype, "folio", void 0);
124
+ __decorate([
125
+ (0, class_transformer_1.Expose)(),
126
+ (0, class_validator_1.IsOptional)(),
127
+ (0, Trim_1.Trim)(),
128
+ (0, class_validator_1.IsString)(),
129
+ (0, class_validator_1.IsNotEmpty)(),
130
+ __metadata("design:type", String)
131
+ ], UpsertPromotionBonusRequest.prototype, "wizardSessionId", void 0);
132
+ __decorate([
133
+ (0, class_transformer_1.Expose)(),
134
+ (0, class_validator_1.IsOptional)(),
135
+ (0, Trim_1.Trim)(),
136
+ (0, class_validator_1.IsString)(),
137
+ (0, class_validator_1.IsNotEmpty)(),
138
+ __metadata("design:type", String)
139
+ ], UpsertPromotionBonusRequest.prototype, "sellerRetailUserId", void 0);
@@ -0,0 +1,27 @@
1
+ import { BonusTypeEnum } from '../../enums/BonusTypeEnum';
2
+ import { WelcomeBonusSettlementStatusEnum } from '../../enums/WelcomeBonusSettlementStatusEnum';
3
+ import { WelcomeBonusStatusEnum } from '../../enums/WelcomeBonusStatusEnum';
4
+ /** Asiento de un bono de promoción en el libro de bonos. Sin PII. */
5
+ export interface PromotionBonusEntryResponse {
6
+ bonusId: string;
7
+ bonusType: BonusTypeEnum;
8
+ promotionId: string;
9
+ /** `creditId` en la promo de crédito, `saleId` en la de venta. */
10
+ sourceId: string;
11
+ retailCustomerId: string;
12
+ fiadoDirectoryId: string | null;
13
+ saleId: string | null;
14
+ creditId: string | null;
15
+ storeId: string;
16
+ amountCents: number | null;
17
+ currency: string;
18
+ status: WelcomeBonusStatusEnum;
19
+ failReason: string | null;
20
+ processorTransactionId: string | null;
21
+ idempotencyKey: string | null;
22
+ fundedBy: string;
23
+ settlementStatus: WelcomeBonusSettlementStatusEnum;
24
+ resolvedAt: string | null;
25
+ createdAt: string;
26
+ updatedAt: string;
27
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ /** Tipo de bono del libro de bonos. Un asiento sin tipo se lee como `WELCOME`. */
2
+ export declare enum BonusTypeEnum {
3
+ WELCOME = "WELCOME",
4
+ CREDIT_PROMOTION = "CREDIT_PROMOTION",
5
+ SALE_PROMOTION = "SALE_PROMOTION"
6
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BonusTypeEnum = void 0;
4
+ /** Tipo de bono del libro de bonos. Un asiento sin tipo se lee como `WELCOME`. */
5
+ var BonusTypeEnum;
6
+ (function (BonusTypeEnum) {
7
+ BonusTypeEnum["WELCOME"] = "WELCOME";
8
+ BonusTypeEnum["CREDIT_PROMOTION"] = "CREDIT_PROMOTION";
9
+ BonusTypeEnum["SALE_PROMOTION"] = "SALE_PROMOTION";
10
+ })(BonusTypeEnum || (exports.BonusTypeEnum = BonusTypeEnum = {}));
@@ -0,0 +1,5 @@
1
+ /** Cómo se verificó la identidad del cliente: KYC completo o solo selfie contra la cuenta existente. */
2
+ export declare enum KycMethodEnum {
3
+ FULL_KYC = "FULL_KYC",
4
+ FACEMATCH = "FACEMATCH"
5
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.KycMethodEnum = void 0;
4
+ /** Cómo se verificó la identidad del cliente: KYC completo o solo selfie contra la cuenta existente. */
5
+ var KycMethodEnum;
6
+ (function (KycMethodEnum) {
7
+ KycMethodEnum["FULL_KYC"] = "FULL_KYC";
8
+ KycMethodEnum["FACEMATCH"] = "FACEMATCH";
9
+ })(KycMethodEnum || (exports.KycMethodEnum = KycMethodEnum = {}));
@@ -1,11 +1,13 @@
1
1
  export * from './enums/AccountStatusEnum';
2
2
  export * from './enums/RetailKycStatusEnum';
3
3
  export * from './enums/KycModalityEnum';
4
+ export * from './enums/KycMethodEnum';
4
5
  export * from './enums/KycReviewResultEnum';
5
6
  export * from './enums/RetailCustomerStatusEnum';
6
7
  export * from './enums/WelcomeBonusStatusEnum';
7
8
  export * from './enums/WelcomeBonusAmountSourceEnum';
8
9
  export * from './enums/WelcomeBonusSettlementStatusEnum';
10
+ export * from './enums/BonusTypeEnum';
9
11
  export * from './dtos/KycReview';
10
12
  export * from './dtos/RetailAddress';
11
13
  export * from './dtos/RetailCustomer';
@@ -16,10 +18,12 @@ export * from './dtos/requests/AccountResultRequest';
16
18
  export * from './dtos/requests/KycReviewRequest';
17
19
  export * from './dtos/requests/WelcomeAccreditationRequest';
18
20
  export * from './dtos/requests/WelcomeAccreditationResultRequest';
21
+ export * from './dtos/requests/UpsertPromotionBonusRequest';
19
22
  export * from './dtos/responses/CustomerResponse';
20
23
  export * from './dtos/responses/Customer360Response';
21
24
  export * from './dtos/responses/WelcomeBonusResponse';
22
25
  export * from './dtos/responses/WelcomeAccreditationResponse';
26
+ export * from './dtos/responses/PromotionBonusEntryResponse';
23
27
  export * from './events/CustomerCreatedV1';
24
28
  export * from './events/CustomerUpdatedV1';
25
29
  export * from './events/CustomerKycVerifiedV1';
@@ -18,11 +18,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
18
18
  __exportStar(require("./enums/AccountStatusEnum"), exports);
19
19
  __exportStar(require("./enums/RetailKycStatusEnum"), exports);
20
20
  __exportStar(require("./enums/KycModalityEnum"), exports);
21
+ __exportStar(require("./enums/KycMethodEnum"), exports);
21
22
  __exportStar(require("./enums/KycReviewResultEnum"), exports);
22
23
  __exportStar(require("./enums/RetailCustomerStatusEnum"), exports);
23
24
  __exportStar(require("./enums/WelcomeBonusStatusEnum"), exports);
24
25
  __exportStar(require("./enums/WelcomeBonusAmountSourceEnum"), exports);
25
26
  __exportStar(require("./enums/WelcomeBonusSettlementStatusEnum"), exports);
27
+ __exportStar(require("./enums/BonusTypeEnum"), exports);
26
28
  // Entidades (planas, con class-validator + @Expose)
27
29
  __exportStar(require("./dtos/KycReview"), exports);
28
30
  __exportStar(require("./dtos/RetailAddress"), exports);
@@ -35,11 +37,13 @@ __exportStar(require("./dtos/requests/AccountResultRequest"), exports);
35
37
  __exportStar(require("./dtos/requests/KycReviewRequest"), exports);
36
38
  __exportStar(require("./dtos/requests/WelcomeAccreditationRequest"), exports);
37
39
  __exportStar(require("./dtos/requests/WelcomeAccreditationResultRequest"), exports);
40
+ __exportStar(require("./dtos/requests/UpsertPromotionBonusRequest"), exports);
38
41
  // Response DTOs
39
42
  __exportStar(require("./dtos/responses/CustomerResponse"), exports);
40
43
  __exportStar(require("./dtos/responses/Customer360Response"), exports);
41
44
  __exportStar(require("./dtos/responses/WelcomeBonusResponse"), exports);
42
45
  __exportStar(require("./dtos/responses/WelcomeAccreditationResponse"), exports);
46
+ __exportStar(require("./dtos/responses/PromotionBonusEntryResponse"), exports);
43
47
  // Contratos de eventos (PascalCase + sufijo V1)
44
48
  __exportStar(require("./events/CustomerCreatedV1"), exports);
45
49
  __exportStar(require("./events/CustomerUpdatedV1"), exports);
@@ -0,0 +1,8 @@
1
+ import type { PromotionBonusStatusEnum } from '../../loanOfferings/enums/PromotionBonusStatusEnum';
2
+ /** Desenlace del bono de la promo de crédito, persistido en la sesión del wizard. */
3
+ export interface WizardCreditPromotionBonus {
4
+ promotionId: string;
5
+ amountCents: number;
6
+ /** `RESERVED` = en proceso; los otros tres son terminales. */
7
+ status: PromotionBonusStatusEnum;
8
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -13,6 +13,7 @@ import type { WizardProduct } from './WizardProduct';
13
13
  import type { WizardReservedLine } from './WizardReservedLine';
14
14
  import type { WizardResumeTarget } from './WizardResumeTarget';
15
15
  import type { WizardWelcome } from './WizardWelcome';
16
+ import type { WizardCreditPromotionBonus } from './WizardCreditPromotionBonus';
16
17
  /** Modalidad de captura del KYC (M1 §213-329). */
17
18
  export type KycModality = 'CUSTOMER_LINK' | 'STORE_DEVICE' | 'MANUAL';
18
19
  /** Estado de la apertura de cuenta async (D35) — espejo de `RetailCustomer.accountStatus`. */
@@ -129,6 +130,8 @@ export interface WizardSession {
129
130
  folio: string | null;
130
131
  payment: WizardPayment | null;
131
132
  welcome: WizardWelcome | null;
133
+ /** Bono de la promo de crédito; ausente o `null` mientras no se haya reservado. */
134
+ creditPromotionBonus?: WizardCreditPromotionBonus | null;
132
135
  /** Contexto de crédito (pista SOFOM, pasos 04-09): PUNTEROS al dominio loan-*. Null en contado/externa. */
133
136
  loan: WizardLoan | null;
134
137
  saleId: string | null;
@@ -20,4 +20,6 @@ export interface QuotePlanBounds {
20
20
  export interface QuoteResponse {
21
21
  plan: QuotePlanBounds;
22
22
  credit: WizardCreditSummary;
23
+ /** Bono de la promo de crédito ganadora en esta cotización; ausente si no hay. */
24
+ creditPromotionBonusCents?: number;
23
25
  }
@@ -28,6 +28,7 @@ export * from './dtos/WizardConsents';
28
28
  export * from './dtos/WizardPayment';
29
29
  export * from './dtos/WizardProduct';
30
30
  export * from './dtos/WizardWelcome';
31
+ export * from './dtos/WizardCreditPromotionBonus';
31
32
  export * from './dtos/SalePaymentDetail';
32
33
  export * from './dtos/ProspectNewCustomer';
33
34
  export * from './dtos/WizardBeneficiary';
@@ -47,6 +47,7 @@ __exportStar(require("./dtos/WizardConsents"), exports);
47
47
  __exportStar(require("./dtos/WizardPayment"), exports);
48
48
  __exportStar(require("./dtos/WizardProduct"), exports);
49
49
  __exportStar(require("./dtos/WizardWelcome"), exports);
50
+ __exportStar(require("./dtos/WizardCreditPromotionBonus"), exports);
50
51
  __exportStar(require("./dtos/SalePaymentDetail"), exports);
51
52
  __exportStar(require("./dtos/ProspectNewCustomer"), exports);
52
53
  __exportStar(require("./dtos/WizardBeneficiary"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.488.0",
3
+ "version": "3.490.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -29,6 +29,8 @@ export interface AppliedPromotionResponse {
29
29
  version: number;
30
30
  /** Palancas del plan que la promoción pisó. */
31
31
  appliedEffects: PromotionEffectKindEnum[];
32
+ /** Monto del bono PCF; solo en la promoción que gana el bono de la cotización. */
33
+ pcfBonusCents?: number;
32
34
  }
33
35
 
34
36
  /**
@@ -12,6 +12,7 @@ import {
12
12
  } from 'class-validator';
13
13
  import { regexCurp, regexIso8601Date, regexPhoneMx } from '../../../helpers/constans/regex';
14
14
  import { RetailAddress } from '../RetailAddress';
15
+ import { KycMethodEnum } from '../../enums/KycMethodEnum';
15
16
  import { KycModalityEnum } from '../../enums/KycModalityEnum';
16
17
  import { RetailKycStatusEnum } from '../../enums/RetailKycStatusEnum';
17
18
 
@@ -140,6 +141,18 @@ export class UpsertCustomerFromKycRequest {
140
141
  @IsEnum(KycModalityEnum)
141
142
  kycModality!: KycModalityEnum;
142
143
 
144
+ /** Método con el que se verificó la identidad. Ausente = no pisa el valor guardado. */
145
+ @Expose()
146
+ @IsOptional()
147
+ @IsEnum(KycMethodEnum)
148
+ kycMethod?: KycMethodEnum;
149
+
150
+ /** Verificación biométrica de `biometrics-business` que respaldó el alta por facematch. */
151
+ @Expose()
152
+ @IsOptional()
153
+ @IsString()
154
+ biometricVerificationId?: string;
155
+
143
156
  /**
144
157
  * Domicilio del INE (paso 02e), ya normalizado contra `places-business`. Se persiste embebido en la
145
158
  * MISMA TX del upsert.
@@ -0,0 +1,121 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsIn, IsInt, IsNotEmpty, IsOptional, IsPositive, IsString, MaxLength, ValidateIf } from 'class-validator';
3
+ import { Trim } from '../../../common/decorators/Trim';
4
+ import { BonusTypeEnum } from '../../enums/BonusTypeEnum';
5
+ import { WelcomeBonusStatusEnum } from '../../enums/WelcomeBonusStatusEnum';
6
+
7
+ /** Tope del motivo libre que el caller escribe en el asiento. */
8
+ const FREE_TEXT_MAX_LENGTH = 256;
9
+
10
+ const PROMOTION_BONUS_TYPES = [BonusTypeEnum.CREDIT_PROMOTION, BonusTypeEnum.SALE_PROMOTION];
11
+
12
+ const STATUSES_REQUIRING_REASON: WelcomeBonusStatusEnum[] = [
13
+ WelcomeBonusStatusEnum.FAILED,
14
+ WelcomeBonusStatusEnum.UNVERIFIED,
15
+ ];
16
+
17
+ /**
18
+ * Asiento de un bono de promoción en el libro de bonos:
19
+ * `PUT /private/customers/:id/promotion-bonuses`. El libro es espejo del sistema de la promo.
20
+ */
21
+ export class UpsertPromotionBonusRequest {
22
+ @Expose()
23
+ @IsIn(PROMOTION_BONUS_TYPES)
24
+ bonusType!: BonusTypeEnum;
25
+
26
+ @Expose()
27
+ @Trim()
28
+ @IsString()
29
+ @IsNotEmpty()
30
+ promotionId!: string;
31
+
32
+ /** `creditId` en la promo de crédito, `saleId` en la de venta. */
33
+ @Expose()
34
+ @Trim()
35
+ @IsString()
36
+ @IsNotEmpty()
37
+ sourceId!: string;
38
+
39
+ /** Tienda de la venta: es la partición del asiento. */
40
+ @Expose()
41
+ @Trim()
42
+ @IsString()
43
+ @IsNotEmpty()
44
+ storeId!: string;
45
+
46
+ /** Obligatorio con `ACCREDITED`; el `PENDING` «sin cuenta todavía» no lo tiene. */
47
+ @Expose()
48
+ @ValidateIf(
49
+ (o: UpsertPromotionBonusRequest) =>
50
+ o.status === WelcomeBonusStatusEnum.ACCREDITED || o.fiadoDirectoryId !== undefined,
51
+ )
52
+ @Trim()
53
+ @IsString()
54
+ @IsNotEmpty({ message: 'fiadoDirectoryId es obligatorio cuando status es ACCREDITED' })
55
+ fiadoDirectoryId?: string;
56
+
57
+ @Expose()
58
+ @IsInt()
59
+ @IsPositive()
60
+ amountCents!: number;
61
+
62
+ @Expose()
63
+ @Trim()
64
+ @IsString()
65
+ @IsNotEmpty()
66
+ currency!: string;
67
+
68
+ @Expose()
69
+ @IsIn(Object.values(WelcomeBonusStatusEnum))
70
+ status!: WelcomeBonusStatusEnum;
71
+
72
+ @Expose()
73
+ @Trim()
74
+ @IsString()
75
+ @IsNotEmpty()
76
+ idempotencyKey!: string;
77
+
78
+ @Expose()
79
+ @IsOptional()
80
+ @Trim()
81
+ @IsString()
82
+ @IsNotEmpty()
83
+ processorTransactionId?: string;
84
+
85
+ /** Resumen legible, sin el payload crudo del processor (el libro va sin PII). */
86
+ @Expose()
87
+ @ValidateIf((o: UpsertPromotionBonusRequest) => STATUSES_REQUIRING_REASON.includes(o.status))
88
+ @Trim()
89
+ @IsString()
90
+ @IsNotEmpty({ message: 'failReason es obligatorio cuando status es FAILED o UNVERIFIED' })
91
+ @MaxLength(FREE_TEXT_MAX_LENGTH)
92
+ failReason?: string;
93
+
94
+ @Expose()
95
+ @IsOptional()
96
+ @Trim()
97
+ @IsString()
98
+ @IsNotEmpty()
99
+ saleId?: string;
100
+
101
+ @Expose()
102
+ @IsOptional()
103
+ @Trim()
104
+ @IsString()
105
+ @IsNotEmpty()
106
+ folio?: string;
107
+
108
+ @Expose()
109
+ @IsOptional()
110
+ @Trim()
111
+ @IsString()
112
+ @IsNotEmpty()
113
+ wizardSessionId?: string;
114
+
115
+ @Expose()
116
+ @IsOptional()
117
+ @Trim()
118
+ @IsString()
119
+ @IsNotEmpty()
120
+ sellerRetailUserId?: string;
121
+ }
@@ -0,0 +1,28 @@
1
+ import { BonusTypeEnum } from '../../enums/BonusTypeEnum';
2
+ import { WelcomeBonusSettlementStatusEnum } from '../../enums/WelcomeBonusSettlementStatusEnum';
3
+ import { WelcomeBonusStatusEnum } from '../../enums/WelcomeBonusStatusEnum';
4
+
5
+ /** Asiento de un bono de promoción en el libro de bonos. Sin PII. */
6
+ export interface PromotionBonusEntryResponse {
7
+ bonusId: string;
8
+ bonusType: BonusTypeEnum;
9
+ promotionId: string;
10
+ /** `creditId` en la promo de crédito, `saleId` en la de venta. */
11
+ sourceId: string;
12
+ retailCustomerId: string;
13
+ fiadoDirectoryId: string | null;
14
+ saleId: string | null;
15
+ creditId: string | null;
16
+ storeId: string;
17
+ amountCents: number | null;
18
+ currency: string;
19
+ status: WelcomeBonusStatusEnum;
20
+ failReason: string | null;
21
+ processorTransactionId: string | null;
22
+ idempotencyKey: string | null;
23
+ fundedBy: string;
24
+ settlementStatus: WelcomeBonusSettlementStatusEnum;
25
+ resolvedAt: string | null;
26
+ createdAt: string;
27
+ updatedAt: string;
28
+ }
@@ -0,0 +1,6 @@
1
+ /** Tipo de bono del libro de bonos. Un asiento sin tipo se lee como `WELCOME`. */
2
+ export enum BonusTypeEnum {
3
+ WELCOME = 'WELCOME',
4
+ CREDIT_PROMOTION = 'CREDIT_PROMOTION',
5
+ SALE_PROMOTION = 'SALE_PROMOTION',
6
+ }
@@ -0,0 +1,5 @@
1
+ /** Cómo se verificó la identidad del cliente: KYC completo o solo selfie contra la cuenta existente. */
2
+ export enum KycMethodEnum {
3
+ FULL_KYC = 'FULL_KYC',
4
+ FACEMATCH = 'FACEMATCH',
5
+ }
@@ -2,11 +2,13 @@
2
2
  export * from './enums/AccountStatusEnum';
3
3
  export * from './enums/RetailKycStatusEnum';
4
4
  export * from './enums/KycModalityEnum';
5
+ export * from './enums/KycMethodEnum';
5
6
  export * from './enums/KycReviewResultEnum';
6
7
  export * from './enums/RetailCustomerStatusEnum';
7
8
  export * from './enums/WelcomeBonusStatusEnum';
8
9
  export * from './enums/WelcomeBonusAmountSourceEnum';
9
10
  export * from './enums/WelcomeBonusSettlementStatusEnum';
11
+ export * from './enums/BonusTypeEnum';
10
12
 
11
13
  // Entidades (planas, con class-validator + @Expose)
12
14
  export * from './dtos/KycReview';
@@ -21,12 +23,14 @@ export * from './dtos/requests/AccountResultRequest';
21
23
  export * from './dtos/requests/KycReviewRequest';
22
24
  export * from './dtos/requests/WelcomeAccreditationRequest';
23
25
  export * from './dtos/requests/WelcomeAccreditationResultRequest';
26
+ export * from './dtos/requests/UpsertPromotionBonusRequest';
24
27
 
25
28
  // Response DTOs
26
29
  export * from './dtos/responses/CustomerResponse';
27
30
  export * from './dtos/responses/Customer360Response';
28
31
  export * from './dtos/responses/WelcomeBonusResponse';
29
32
  export * from './dtos/responses/WelcomeAccreditationResponse';
33
+ export * from './dtos/responses/PromotionBonusEntryResponse';
30
34
 
31
35
  // Contratos de eventos (PascalCase + sufijo V1)
32
36
  export * from './events/CustomerCreatedV1';
@@ -0,0 +1,9 @@
1
+ import type { PromotionBonusStatusEnum } from '../../loanOfferings/enums/PromotionBonusStatusEnum';
2
+
3
+ /** Desenlace del bono de la promo de crédito, persistido en la sesión del wizard. */
4
+ export interface WizardCreditPromotionBonus {
5
+ promotionId: string;
6
+ amountCents: number;
7
+ /** `RESERVED` = en proceso; los otros tres son terminales. */
8
+ status: PromotionBonusStatusEnum;
9
+ }
@@ -13,6 +13,7 @@ import type { WizardProduct } from './WizardProduct';
13
13
  import type { WizardReservedLine } from './WizardReservedLine';
14
14
  import type { WizardResumeTarget } from './WizardResumeTarget';
15
15
  import type { WizardWelcome } from './WizardWelcome';
16
+ import type { WizardCreditPromotionBonus } from './WizardCreditPromotionBonus';
16
17
 
17
18
  /** Modalidad de captura del KYC (M1 §213-329). */
18
19
  export type KycModality = 'CUSTOMER_LINK' | 'STORE_DEVICE' | 'MANUAL';
@@ -133,6 +134,8 @@ export interface WizardSession {
133
134
  folio: string | null;
134
135
  payment: WizardPayment | null;
135
136
  welcome: WizardWelcome | null;
137
+ /** Bono de la promo de crédito; ausente o `null` mientras no se haya reservado. */
138
+ creditPromotionBonus?: WizardCreditPromotionBonus | null;
136
139
  /** Contexto de crédito (pista SOFOM, pasos 04-09): PUNTEROS al dominio loan-*. Null en contado/externa. */
137
140
  loan: WizardLoan | null;
138
141
  saleId: string | null;
@@ -22,4 +22,6 @@ export interface QuotePlanBounds {
22
22
  export interface QuoteResponse {
23
23
  plan: QuotePlanBounds;
24
24
  credit: WizardCreditSummary;
25
+ /** Bono de la promo de crédito ganadora en esta cotización; ausente si no hay. */
26
+ creditPromotionBonusCents?: number;
25
27
  }
@@ -33,6 +33,7 @@ export * from './dtos/WizardConsents';
33
33
  export * from './dtos/WizardPayment';
34
34
  export * from './dtos/WizardProduct';
35
35
  export * from './dtos/WizardWelcome';
36
+ export * from './dtos/WizardCreditPromotionBonus';
36
37
  export * from './dtos/SalePaymentDetail';
37
38
  export * from './dtos/ProspectNewCustomer';
38
39
  export * from './dtos/WizardBeneficiary';