@fiado/type-kit 3.526.0 → 3.528.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.
@@ -0,0 +1,68 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { ValidationError, validate } from 'class-validator';
4
+ import { SignLoanCreditRequest } from '../../../src/loanCredit/index';
5
+
6
+ /** Rutas de las propiedades que fallan, con los anidados como `contractDetails.borrower.fullName`. */
7
+ const pathsOf = (errors: ValidationError[], prefix = ''): string[] =>
8
+ errors.flatMap((error) => {
9
+ const path = prefix ? `${prefix}.${error.property}` : error.property;
10
+ return error.children?.length ? pathsOf(error.children, path) : [path];
11
+ });
12
+
13
+ const errorsOf = async (body: Record<string, unknown>): Promise<string[]> =>
14
+ pathsOf(await validate(plainToInstance(SignLoanCreditRequest, body))).sort();
15
+
16
+ const DETAILS = {
17
+ borrower: {
18
+ fullName: 'María Fernanda López Hernández',
19
+ curp: 'LOHM900215MMCPRR09',
20
+ address: 'Av. Ejemplo 123, Col. Centro, C.P. 50000, Toluca, Estado de México',
21
+ rfc: 'LOHM900215AB1',
22
+ occupation: 'Empleada',
23
+ monthlyIncome: '10,000 – 15,000',
24
+ },
25
+ device: { brand: 'Samsung', model: 'Galaxy A15', color: 'Negro', storage: '128 GB', imei: '356938035643809' },
26
+ provider: { legalName: 'Comercializadora de Ejemplo, S.A. de C.V.' },
27
+ };
28
+
29
+ describe('SignLoanCreditRequest', () => {
30
+ it('acepta el inicio de firma sin datos del contrato, como hasta ahora', async () => {
31
+ expect(await errorsOf({ contractData: { nombreAcreditado: 'María' } })).toEqual([]);
32
+ });
33
+
34
+ it('acepta los datos del contrato completos', async () => {
35
+ expect(await errorsOf({ contractDetails: DETAILS })).toEqual([]);
36
+ });
37
+
38
+ it('el proveedor es opcional: el motor lo resuelve con la tienda', async () => {
39
+ const { provider, ...withoutProvider } = DETAILS;
40
+ expect(provider).toBeDefined();
41
+ expect(await errorsOf({ contractDetails: withoutProvider })).toEqual([]);
42
+ });
43
+
44
+ it('exige acreditado y equipo cuando vienen los datos del contrato', async () => {
45
+ expect(await errorsOf({ contractDetails: {} })).toEqual(['contractDetails.borrower', 'contractDetails.device']);
46
+ });
47
+
48
+ it('exige nombre, CURP y domicilio del acreditado, y marca y modelo del equipo', async () => {
49
+ const details = { borrower: { rfc: 'LOHM900215AB1' }, device: { color: 'Negro' } };
50
+ expect(await errorsOf({ contractDetails: details })).toEqual([
51
+ 'contractDetails.borrower.address',
52
+ 'contractDetails.borrower.curp',
53
+ 'contractDetails.borrower.fullName',
54
+ 'contractDetails.device.brand',
55
+ 'contractDetails.device.model',
56
+ ]);
57
+ });
58
+
59
+ it('rechaza un IMEI que no tiene 15 dígitos', async () => {
60
+ const details = { ...DETAILS, device: { ...DETAILS.device, imei: '35693803564380A' } };
61
+ expect(await errorsOf({ contractDetails: details })).toEqual(['contractDetails.device.imei']);
62
+ });
63
+
64
+ it('rechaza un texto más largo que el máximo', async () => {
65
+ const details = { ...DETAILS, provider: { legalName: 'x'.repeat(301) } };
66
+ expect(await errorsOf({ contractDetails: details })).toEqual(['contractDetails.provider.legalName']);
67
+ });
68
+ });
@@ -77,10 +77,10 @@ describe('pdfRender includeContent', () => {
77
77
 
78
78
  describe('pdfRender referenceId', () => {
79
79
  it('accepts the owner id and folder fields, and rejects unsafe segments', async () => {
80
- const template = { enterprise: 'SUREKEEP', documentType: 'CREDITO_CONTRATO' };
80
+ const template = { enterprise: 'SUREKEEP', documentType: 'CREDIT_CONTRACT' };
81
81
  expect(await errorsOf(RenderDocumentRequest, { template, data: {}, referenceId: '01JX9KAB12' })).toEqual([]);
82
82
  expect(await errorsOf(RenderDocumentRequest, { template, data: {}, referenceId: '../x' })).toEqual(['referenceId']);
83
- expect(await errorsOf(GeneratePdfRequest, { html: '<p/>', enterprise: 'SUREKEEP', documentType: 'CREDITO_RESUMEN', referenceId: 'abc' })).toEqual([]);
83
+ expect(await errorsOf(GeneratePdfRequest, { html: '<p/>', enterprise: 'SUREKEEP', documentType: 'CREDIT_SUMMARY', referenceId: 'abc' })).toEqual([]);
84
84
  expect(await errorsOf(MergePdfsRequest, { pdfs: ['JVBERi0='], enterprise: 'A/B' })).toEqual(['enterprise']);
85
85
  });
86
86
  });
@@ -0,0 +1,42 @@
1
+ /** Datos del acreditado tal como se imprimen en el contrato (Sección II.1). */
2
+ export declare class LoanContractBorrowerDetails {
3
+ fullName: string;
4
+ curp: string;
5
+ /** Domicilio completo en una línea. */
6
+ address: string;
7
+ rfc?: string;
8
+ birthDate?: string;
9
+ /** Identificación oficial con la que se validó al acreditado (p. ej. INE). */
10
+ identification?: string;
11
+ phone?: string;
12
+ email?: string;
13
+ occupation?: string;
14
+ /** Ingresos mensuales declarados, ya formateados (monto o rango). */
15
+ monthlyIncome?: string;
16
+ fundsOrigin?: string;
17
+ }
18
+ /** Equipo celular que financia el crédito (Sección II.2). */
19
+ export declare class LoanContractDeviceDetails {
20
+ brand: string;
21
+ model: string;
22
+ color?: string;
23
+ /** Capacidad de almacenamiento, ya formateada (p. ej. "128 GB"). */
24
+ storage?: string;
25
+ imei?: string;
26
+ serialNumber?: string;
27
+ }
28
+ /** Proveedor que vende el equipo y recibe el desembolso (Sección II.3). */
29
+ export declare class LoanContractProviderDetails {
30
+ legalName: string;
31
+ }
32
+ /**
33
+ * Datos del contrato que el motor de crédito no guarda: los aporta el wizard al iniciar la firma
34
+ * y se imprimen en las plantillas de pdf-render-business. Son PII transitoria: no se persisten ni
35
+ * se loggean.
36
+ */
37
+ export declare class LoanContractDetails {
38
+ borrower: LoanContractBorrowerDetails;
39
+ device: LoanContractDeviceDetails;
40
+ /** Si falta, el motor lo resuelve con la tienda del crédito. */
41
+ provider?: LoanContractProviderDetails;
42
+ }
@@ -0,0 +1,187 @@
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.LoanContractDetails = exports.LoanContractProviderDetails = exports.LoanContractDeviceDetails = exports.LoanContractBorrowerDetails = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ /** Largo máximo de un texto corto del contrato (RFC, ocupación, marca…). */
16
+ const SHORT_TEXT = 120;
17
+ /** Largo máximo de un texto largo del contrato (nombre, domicilio, razón social). */
18
+ const LONG_TEXT = 300;
19
+ /** IMEI: exactamente 15 dígitos. */
20
+ const IMEI_PATTERN = /^\d{15}$/;
21
+ /** Datos del acreditado tal como se imprimen en el contrato (Sección II.1). */
22
+ class LoanContractBorrowerDetails {
23
+ }
24
+ exports.LoanContractBorrowerDetails = LoanContractBorrowerDetails;
25
+ __decorate([
26
+ (0, class_transformer_1.Expose)(),
27
+ (0, class_validator_1.IsString)(),
28
+ (0, class_validator_1.IsNotEmpty)(),
29
+ (0, class_validator_1.MaxLength)(LONG_TEXT),
30
+ __metadata("design:type", String)
31
+ ], LoanContractBorrowerDetails.prototype, "fullName", void 0);
32
+ __decorate([
33
+ (0, class_transformer_1.Expose)(),
34
+ (0, class_validator_1.IsString)(),
35
+ (0, class_validator_1.IsNotEmpty)(),
36
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
37
+ __metadata("design:type", String)
38
+ ], LoanContractBorrowerDetails.prototype, "curp", void 0);
39
+ __decorate([
40
+ (0, class_transformer_1.Expose)(),
41
+ (0, class_validator_1.IsString)(),
42
+ (0, class_validator_1.IsNotEmpty)(),
43
+ (0, class_validator_1.MaxLength)(LONG_TEXT),
44
+ __metadata("design:type", String)
45
+ ], LoanContractBorrowerDetails.prototype, "address", void 0);
46
+ __decorate([
47
+ (0, class_transformer_1.Expose)(),
48
+ (0, class_validator_1.IsOptional)(),
49
+ (0, class_validator_1.IsString)(),
50
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
51
+ __metadata("design:type", String)
52
+ ], LoanContractBorrowerDetails.prototype, "rfc", void 0);
53
+ __decorate([
54
+ (0, class_transformer_1.Expose)(),
55
+ (0, class_validator_1.IsOptional)(),
56
+ (0, class_validator_1.IsString)(),
57
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
58
+ __metadata("design:type", String)
59
+ ], LoanContractBorrowerDetails.prototype, "birthDate", void 0);
60
+ __decorate([
61
+ (0, class_transformer_1.Expose)(),
62
+ (0, class_validator_1.IsOptional)(),
63
+ (0, class_validator_1.IsString)(),
64
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
65
+ __metadata("design:type", String)
66
+ ], LoanContractBorrowerDetails.prototype, "identification", void 0);
67
+ __decorate([
68
+ (0, class_transformer_1.Expose)(),
69
+ (0, class_validator_1.IsOptional)(),
70
+ (0, class_validator_1.IsString)(),
71
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
72
+ __metadata("design:type", String)
73
+ ], LoanContractBorrowerDetails.prototype, "phone", void 0);
74
+ __decorate([
75
+ (0, class_transformer_1.Expose)(),
76
+ (0, class_validator_1.IsOptional)(),
77
+ (0, class_validator_1.IsString)(),
78
+ (0, class_validator_1.MaxLength)(LONG_TEXT),
79
+ __metadata("design:type", String)
80
+ ], LoanContractBorrowerDetails.prototype, "email", void 0);
81
+ __decorate([
82
+ (0, class_transformer_1.Expose)(),
83
+ (0, class_validator_1.IsOptional)(),
84
+ (0, class_validator_1.IsString)(),
85
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
86
+ __metadata("design:type", String)
87
+ ], LoanContractBorrowerDetails.prototype, "occupation", void 0);
88
+ __decorate([
89
+ (0, class_transformer_1.Expose)(),
90
+ (0, class_validator_1.IsOptional)(),
91
+ (0, class_validator_1.IsString)(),
92
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
93
+ __metadata("design:type", String)
94
+ ], LoanContractBorrowerDetails.prototype, "monthlyIncome", void 0);
95
+ __decorate([
96
+ (0, class_transformer_1.Expose)(),
97
+ (0, class_validator_1.IsOptional)(),
98
+ (0, class_validator_1.IsString)(),
99
+ (0, class_validator_1.MaxLength)(LONG_TEXT),
100
+ __metadata("design:type", String)
101
+ ], LoanContractBorrowerDetails.prototype, "fundsOrigin", void 0);
102
+ /** Equipo celular que financia el crédito (Sección II.2). */
103
+ class LoanContractDeviceDetails {
104
+ }
105
+ exports.LoanContractDeviceDetails = LoanContractDeviceDetails;
106
+ __decorate([
107
+ (0, class_transformer_1.Expose)(),
108
+ (0, class_validator_1.IsString)(),
109
+ (0, class_validator_1.IsNotEmpty)(),
110
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
111
+ __metadata("design:type", String)
112
+ ], LoanContractDeviceDetails.prototype, "brand", void 0);
113
+ __decorate([
114
+ (0, class_transformer_1.Expose)(),
115
+ (0, class_validator_1.IsString)(),
116
+ (0, class_validator_1.IsNotEmpty)(),
117
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
118
+ __metadata("design:type", String)
119
+ ], LoanContractDeviceDetails.prototype, "model", void 0);
120
+ __decorate([
121
+ (0, class_transformer_1.Expose)(),
122
+ (0, class_validator_1.IsOptional)(),
123
+ (0, class_validator_1.IsString)(),
124
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
125
+ __metadata("design:type", String)
126
+ ], LoanContractDeviceDetails.prototype, "color", void 0);
127
+ __decorate([
128
+ (0, class_transformer_1.Expose)(),
129
+ (0, class_validator_1.IsOptional)(),
130
+ (0, class_validator_1.IsString)(),
131
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
132
+ __metadata("design:type", String)
133
+ ], LoanContractDeviceDetails.prototype, "storage", void 0);
134
+ __decorate([
135
+ (0, class_transformer_1.Expose)(),
136
+ (0, class_validator_1.IsOptional)(),
137
+ (0, class_validator_1.IsString)(),
138
+ (0, class_validator_1.Matches)(IMEI_PATTERN, { message: 'imei admite solo 15 dígitos' }),
139
+ __metadata("design:type", String)
140
+ ], LoanContractDeviceDetails.prototype, "imei", void 0);
141
+ __decorate([
142
+ (0, class_transformer_1.Expose)(),
143
+ (0, class_validator_1.IsOptional)(),
144
+ (0, class_validator_1.IsString)(),
145
+ (0, class_validator_1.MaxLength)(SHORT_TEXT),
146
+ __metadata("design:type", String)
147
+ ], LoanContractDeviceDetails.prototype, "serialNumber", void 0);
148
+ /** Proveedor que vende el equipo y recibe el desembolso (Sección II.3). */
149
+ class LoanContractProviderDetails {
150
+ }
151
+ exports.LoanContractProviderDetails = LoanContractProviderDetails;
152
+ __decorate([
153
+ (0, class_transformer_1.Expose)(),
154
+ (0, class_validator_1.IsString)(),
155
+ (0, class_validator_1.IsNotEmpty)(),
156
+ (0, class_validator_1.MaxLength)(LONG_TEXT),
157
+ __metadata("design:type", String)
158
+ ], LoanContractProviderDetails.prototype, "legalName", void 0);
159
+ /**
160
+ * Datos del contrato que el motor de crédito no guarda: los aporta el wizard al iniciar la firma
161
+ * y se imprimen en las plantillas de pdf-render-business. Son PII transitoria: no se persisten ni
162
+ * se loggean.
163
+ */
164
+ class LoanContractDetails {
165
+ }
166
+ exports.LoanContractDetails = LoanContractDetails;
167
+ __decorate([
168
+ (0, class_transformer_1.Expose)(),
169
+ (0, class_validator_1.IsDefined)(),
170
+ (0, class_validator_1.ValidateNested)(),
171
+ (0, class_transformer_1.Type)(() => LoanContractBorrowerDetails),
172
+ __metadata("design:type", LoanContractBorrowerDetails)
173
+ ], LoanContractDetails.prototype, "borrower", void 0);
174
+ __decorate([
175
+ (0, class_transformer_1.Expose)(),
176
+ (0, class_validator_1.IsDefined)(),
177
+ (0, class_validator_1.ValidateNested)(),
178
+ (0, class_transformer_1.Type)(() => LoanContractDeviceDetails),
179
+ __metadata("design:type", LoanContractDeviceDetails)
180
+ ], LoanContractDetails.prototype, "device", void 0);
181
+ __decorate([
182
+ (0, class_transformer_1.Expose)(),
183
+ (0, class_validator_1.IsOptional)(),
184
+ (0, class_validator_1.ValidateNested)(),
185
+ (0, class_transformer_1.Type)(() => LoanContractProviderDetails),
186
+ __metadata("design:type", LoanContractProviderDetails)
187
+ ], LoanContractDetails.prototype, "provider", void 0);
@@ -1,3 +1,4 @@
1
+ import { LoanContractDetails } from '../LoanContractDetails';
1
2
  /**
2
3
  * Body de `POST /private/credits/:creditId/sign` (loan-credit-business — wizard paso 08, firma FES
3
4
  * M2 §4.4). Endpoint de DOS tiempos sobre el mismo contrato:
@@ -27,6 +28,12 @@ export declare class SignLoanCreditRequest {
27
28
  * pagos, tasa) y las pasa a document-generator. NO se persisten ni loggean (silo PII-zero).
28
29
  */
29
30
  contractData?: Record<string, string>;
31
+ /**
32
+ * SOLO en el inicio de firma (tiempo 1): datos del acreditado, del equipo y del proveedor que
33
+ * imprimen las plantillas de pdf-render-business. Los aporta el WIZARD; mismas reglas de PII
34
+ * que `contractData`.
35
+ */
36
+ contractDetails?: LoanContractDetails;
30
37
  /**
31
38
  * SOLO en el inicio de firma (tiempo 1) con el OTP REAL: el teléfono destino del SMS (E.164).
32
39
  * PII TRANSITORIA: el motor la pasa a messages-business y NO la persiste ni loggea (silo
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.SignLoanCreditRequest = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
+ const LoanContractDetails_1 = require("../LoanContractDetails");
15
16
  /**
16
17
  * Body de `POST /private/credits/:creditId/sign` (loan-credit-business — wizard paso 08, firma FES
17
18
  * M2 §4.4). Endpoint de DOS tiempos sobre el mismo contrato:
@@ -47,6 +48,13 @@ __decorate([
47
48
  (0, class_validator_1.IsObject)(),
48
49
  __metadata("design:type", Object)
49
50
  ], SignLoanCreditRequest.prototype, "contractData", void 0);
51
+ __decorate([
52
+ (0, class_transformer_1.Expose)(),
53
+ (0, class_validator_1.IsOptional)(),
54
+ (0, class_validator_1.ValidateNested)(),
55
+ (0, class_transformer_1.Type)(() => LoanContractDetails_1.LoanContractDetails),
56
+ __metadata("design:type", LoanContractDetails_1.LoanContractDetails)
57
+ ], SignLoanCreditRequest.prototype, "contractDetails", void 0);
50
58
  __decorate([
51
59
  (0, class_transformer_1.Expose)(),
52
60
  (0, class_validator_1.IsOptional)(),
@@ -8,6 +8,7 @@ export * from './dtos/LoanCredit';
8
8
  export * from './dtos/LoanInstallment';
9
9
  export * from './dtos/InstallmentPaidEvent';
10
10
  export * from './dtos/LoanContract';
11
+ export * from './dtos/LoanContractDetails';
11
12
  export * from './dtos/ActivationChecklist';
12
13
  export * from './dtos/AppliedPromotionSnapshot';
13
14
  export * from './dtos/AppliedStorePolicySnapshot';
@@ -29,6 +29,7 @@ __exportStar(require("./dtos/LoanCredit"), exports);
29
29
  __exportStar(require("./dtos/LoanInstallment"), exports);
30
30
  __exportStar(require("./dtos/InstallmentPaidEvent"), exports);
31
31
  __exportStar(require("./dtos/LoanContract"), exports);
32
+ __exportStar(require("./dtos/LoanContractDetails"), exports);
32
33
  __exportStar(require("./dtos/ActivationChecklist"), exports);
33
34
  __exportStar(require("./dtos/AppliedPromotionSnapshot"), exports);
34
35
  __exportStar(require("./dtos/AppliedStorePolicySnapshot"), exports);
@@ -5,7 +5,7 @@ export declare class GeneratePdfRequest {
5
5
  includeContent?: boolean;
6
6
  /** Empresa (tenant) dueña del documento; sin ella se guarda en una carpeta común. */
7
7
  enterprise?: string;
8
- /** Tipo de documento (carpeta en S3), p. ej. CREDITO_CONTRATO. */
8
+ /** Tipo de documento (carpeta en S3), p. ej. CREDIT_CONTRACT. */
9
9
  documentType?: string;
10
10
  /**
11
11
  * Id de la entidad dueña del documento (crédito, cliente...). Forma parte de la llave en S3, igual
@@ -5,7 +5,7 @@ export declare class MergePdfsRequest {
5
5
  includeContent?: boolean;
6
6
  /** Empresa (tenant) dueña del documento; sin ella se guarda en una carpeta común. */
7
7
  enterprise?: string;
8
- /** Tipo de documento (carpeta en S3), p. ej. CREDITO_CONTRATO. */
8
+ /** Tipo de documento (carpeta en S3), p. ej. CREDIT_CONTRACT. */
9
9
  documentType?: string;
10
10
  /**
11
11
  * Id de la entidad dueña del documento (crédito, cliente...). Forma parte de la llave en S3, igual
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Documento PDF generado y guardado por pdf-render-business.
3
- * `key` es la ubicación del documento por convención ({EMPRESA}/{TIPO}/{aaaa}/{mm}/{uuid}.pdf) y
4
- * es lo que se guarda para pedir una URL nueva con GET /documents/url?key=... cuando venza la actual.
3
+ * `key` es la ubicación del documento en el bucket de contratos, por convención
4
+ * {EMPRESA}/{TIPO}/{referenceId}/{uuid}.pdf (o {EMPRESA}/{PARTNER}/{CATEGORIA}/{referenceId}/{TIPO}/{uuid}.pdf),
5
+ * y es lo que se guarda para pedir una URL nueva con GET /documents/url?key=... cuando venza la actual.
5
6
  */
6
7
  export declare class PdfDocumentResponse {
7
8
  key: string;
@@ -3,8 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PdfDocumentResponse = void 0;
4
4
  /**
5
5
  * Documento PDF generado y guardado por pdf-render-business.
6
- * `key` es la ubicación del documento por convención ({EMPRESA}/{TIPO}/{aaaa}/{mm}/{uuid}.pdf) y
7
- * es lo que se guarda para pedir una URL nueva con GET /documents/url?key=... cuando venza la actual.
6
+ * `key` es la ubicación del documento en el bucket de contratos, por convención
7
+ * {EMPRESA}/{TIPO}/{referenceId}/{uuid}.pdf (o {EMPRESA}/{PARTNER}/{CATEGORIA}/{referenceId}/{TIPO}/{uuid}.pdf),
8
+ * y es lo que se guarda para pedir una URL nueva con GET /documents/url?key=... cuando venza la actual.
8
9
  */
9
10
  class PdfDocumentResponse {
10
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.526.0",
3
+ "version": "3.528.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -0,0 +1,156 @@
1
+ import { Expose, Type } from 'class-transformer';
2
+ import { IsDefined, IsNotEmpty, IsOptional, IsString, Matches, MaxLength, ValidateNested } from 'class-validator';
3
+
4
+ /** Largo máximo de un texto corto del contrato (RFC, ocupación, marca…). */
5
+ const SHORT_TEXT = 120;
6
+ /** Largo máximo de un texto largo del contrato (nombre, domicilio, razón social). */
7
+ const LONG_TEXT = 300;
8
+ /** IMEI: exactamente 15 dígitos. */
9
+ const IMEI_PATTERN = /^\d{15}$/;
10
+
11
+ /** Datos del acreditado tal como se imprimen en el contrato (Sección II.1). */
12
+ export class LoanContractBorrowerDetails {
13
+ @Expose()
14
+ @IsString()
15
+ @IsNotEmpty()
16
+ @MaxLength(LONG_TEXT)
17
+ fullName: string;
18
+
19
+ @Expose()
20
+ @IsString()
21
+ @IsNotEmpty()
22
+ @MaxLength(SHORT_TEXT)
23
+ curp: string;
24
+
25
+ /** Domicilio completo en una línea. */
26
+ @Expose()
27
+ @IsString()
28
+ @IsNotEmpty()
29
+ @MaxLength(LONG_TEXT)
30
+ address: string;
31
+
32
+ @Expose()
33
+ @IsOptional()
34
+ @IsString()
35
+ @MaxLength(SHORT_TEXT)
36
+ rfc?: string;
37
+
38
+ @Expose()
39
+ @IsOptional()
40
+ @IsString()
41
+ @MaxLength(SHORT_TEXT)
42
+ birthDate?: string;
43
+
44
+ /** Identificación oficial con la que se validó al acreditado (p. ej. INE). */
45
+ @Expose()
46
+ @IsOptional()
47
+ @IsString()
48
+ @MaxLength(SHORT_TEXT)
49
+ identification?: string;
50
+
51
+ @Expose()
52
+ @IsOptional()
53
+ @IsString()
54
+ @MaxLength(SHORT_TEXT)
55
+ phone?: string;
56
+
57
+ @Expose()
58
+ @IsOptional()
59
+ @IsString()
60
+ @MaxLength(LONG_TEXT)
61
+ email?: string;
62
+
63
+ @Expose()
64
+ @IsOptional()
65
+ @IsString()
66
+ @MaxLength(SHORT_TEXT)
67
+ occupation?: string;
68
+
69
+ /** Ingresos mensuales declarados, ya formateados (monto o rango). */
70
+ @Expose()
71
+ @IsOptional()
72
+ @IsString()
73
+ @MaxLength(SHORT_TEXT)
74
+ monthlyIncome?: string;
75
+
76
+ @Expose()
77
+ @IsOptional()
78
+ @IsString()
79
+ @MaxLength(LONG_TEXT)
80
+ fundsOrigin?: string;
81
+ }
82
+
83
+ /** Equipo celular que financia el crédito (Sección II.2). */
84
+ export class LoanContractDeviceDetails {
85
+ @Expose()
86
+ @IsString()
87
+ @IsNotEmpty()
88
+ @MaxLength(SHORT_TEXT)
89
+ brand: string;
90
+
91
+ @Expose()
92
+ @IsString()
93
+ @IsNotEmpty()
94
+ @MaxLength(SHORT_TEXT)
95
+ model: string;
96
+
97
+ @Expose()
98
+ @IsOptional()
99
+ @IsString()
100
+ @MaxLength(SHORT_TEXT)
101
+ color?: string;
102
+
103
+ /** Capacidad de almacenamiento, ya formateada (p. ej. "128 GB"). */
104
+ @Expose()
105
+ @IsOptional()
106
+ @IsString()
107
+ @MaxLength(SHORT_TEXT)
108
+ storage?: string;
109
+
110
+ @Expose()
111
+ @IsOptional()
112
+ @IsString()
113
+ @Matches(IMEI_PATTERN, { message: 'imei admite solo 15 dígitos' })
114
+ imei?: string;
115
+
116
+ @Expose()
117
+ @IsOptional()
118
+ @IsString()
119
+ @MaxLength(SHORT_TEXT)
120
+ serialNumber?: string;
121
+ }
122
+
123
+ /** Proveedor que vende el equipo y recibe el desembolso (Sección II.3). */
124
+ export class LoanContractProviderDetails {
125
+ @Expose()
126
+ @IsString()
127
+ @IsNotEmpty()
128
+ @MaxLength(LONG_TEXT)
129
+ legalName: string;
130
+ }
131
+
132
+ /**
133
+ * Datos del contrato que el motor de crédito no guarda: los aporta el wizard al iniciar la firma
134
+ * y se imprimen en las plantillas de pdf-render-business. Son PII transitoria: no se persisten ni
135
+ * se loggean.
136
+ */
137
+ export class LoanContractDetails {
138
+ @Expose()
139
+ @IsDefined()
140
+ @ValidateNested()
141
+ @Type(() => LoanContractBorrowerDetails)
142
+ borrower: LoanContractBorrowerDetails;
143
+
144
+ @Expose()
145
+ @IsDefined()
146
+ @ValidateNested()
147
+ @Type(() => LoanContractDeviceDetails)
148
+ device: LoanContractDeviceDetails;
149
+
150
+ /** Si falta, el motor lo resuelve con la tienda del crédito. */
151
+ @Expose()
152
+ @IsOptional()
153
+ @ValidateNested()
154
+ @Type(() => LoanContractProviderDetails)
155
+ provider?: LoanContractProviderDetails;
156
+ }
@@ -1,5 +1,6 @@
1
- import { Expose } from 'class-transformer';
2
- import { IsObject, IsOptional, IsString, Length } from 'class-validator';
1
+ import { Expose, Type } from 'class-transformer';
2
+ import { IsObject, IsOptional, IsString, Length, ValidateNested } from 'class-validator';
3
+ import { LoanContractDetails } from '../LoanContractDetails';
3
4
 
4
5
  /**
5
6
  * Body de `POST /private/credits/:creditId/sign` (loan-credit-business — wizard paso 08, firma FES
@@ -43,6 +44,17 @@ export class SignLoanCreditRequest {
43
44
  @IsObject()
44
45
  contractData?: Record<string, string>;
45
46
 
47
+ /**
48
+ * SOLO en el inicio de firma (tiempo 1): datos del acreditado, del equipo y del proveedor que
49
+ * imprimen las plantillas de pdf-render-business. Los aporta el WIZARD; mismas reglas de PII
50
+ * que `contractData`.
51
+ */
52
+ @Expose()
53
+ @IsOptional()
54
+ @ValidateNested()
55
+ @Type(() => LoanContractDetails)
56
+ contractDetails?: LoanContractDetails;
57
+
46
58
  /**
47
59
  * SOLO en el inicio de firma (tiempo 1) con el OTP REAL: el teléfono destino del SMS (E.164).
48
60
  * PII TRANSITORIA: el motor la pasa a messages-business y NO la persiste ni loggea (silo
@@ -12,6 +12,7 @@ export * from './dtos/LoanCredit';
12
12
  export * from './dtos/LoanInstallment';
13
13
  export * from './dtos/InstallmentPaidEvent';
14
14
  export * from './dtos/LoanContract';
15
+ export * from './dtos/LoanContractDetails';
15
16
  export * from './dtos/ActivationChecklist';
16
17
  export * from './dtos/AppliedPromotionSnapshot';
17
18
  export * from './dtos/AppliedStorePolicySnapshot';
@@ -13,7 +13,7 @@ export class GeneratePdfRequest {
13
13
  @IsOptional() @IsString() @Matches(/^[A-Za-z0-9_-]{1,64}$/)
14
14
  enterprise?: string;
15
15
 
16
- /** Tipo de documento (carpeta en S3), p. ej. CREDITO_CONTRATO. */
16
+ /** Tipo de documento (carpeta en S3), p. ej. CREDIT_CONTRACT. */
17
17
  @IsOptional() @IsString() @Matches(/^[A-Za-z0-9_-]{1,64}$/)
18
18
  documentType?: string;
19
19
 
@@ -13,7 +13,7 @@ export class MergePdfsRequest {
13
13
  @IsOptional() @IsString() @Matches(/^[A-Za-z0-9_-]{1,64}$/)
14
14
  enterprise?: string;
15
15
 
16
- /** Tipo de documento (carpeta en S3), p. ej. CREDITO_CONTRATO. */
16
+ /** Tipo de documento (carpeta en S3), p. ej. CREDIT_CONTRACT. */
17
17
  @IsOptional() @IsString() @Matches(/^[A-Za-z0-9_-]{1,64}$/)
18
18
  documentType?: string;
19
19
 
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Documento PDF generado y guardado por pdf-render-business.
3
- * `key` es la ubicación del documento por convención ({EMPRESA}/{TIPO}/{aaaa}/{mm}/{uuid}.pdf) y
4
- * es lo que se guarda para pedir una URL nueva con GET /documents/url?key=... cuando venza la actual.
3
+ * `key` es la ubicación del documento en el bucket de contratos, por convención
4
+ * {EMPRESA}/{TIPO}/{referenceId}/{uuid}.pdf (o {EMPRESA}/{PARTNER}/{CATEGORIA}/{referenceId}/{TIPO}/{uuid}.pdf),
5
+ * y es lo que se guarda para pedir una URL nueva con GET /documents/url?key=... cuando venza la actual.
5
6
  */
6
7
  export class PdfDocumentResponse {
7
8
  key!: string;