@fiado/type-kit 3.536.0 → 3.537.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.
- package/_test_/unit/loanCredit/creditLifecycleEnums.test.ts +2 -1
- package/_test_/unit/loanCredit/signLoanCreditRequest.test.ts +37 -0
- package/_test_/unit/messagesConnector/otpBinding.test.ts +43 -0
- package/_test_/unit/retailWizard/signatureSendOtpRequest.test.ts +25 -0
- package/bin/loanCredit/dtos/LoanContract.d.ts +5 -1
- package/bin/loanCredit/dtos/LoanContract.js +8 -1
- package/bin/loanCredit/dtos/LoanContractSignatureEvidence.d.ts +45 -0
- package/bin/loanCredit/dtos/LoanContractSignatureEvidence.js +2 -0
- package/bin/loanCredit/dtos/SignatureContext.d.ts +20 -0
- package/bin/loanCredit/dtos/SignatureContext.js +92 -0
- package/bin/loanCredit/dtos/requests/SignLoanCreditRequest.d.ts +6 -0
- package/bin/loanCredit/dtos/requests/SignLoanCreditRequest.js +8 -0
- package/bin/loanCredit/dtos/responses/LoanContractResponse.d.ts +3 -0
- package/bin/loanCredit/enums/ContractTypeEnum.d.ts +2 -0
- package/bin/loanCredit/enums/ContractTypeEnum.js +2 -0
- package/bin/loanCredit/index.d.ts +2 -0
- package/bin/loanCredit/index.js +2 -0
- package/bin/messagesConnector/constants/OtpBinding.d.ts +2 -0
- package/bin/messagesConnector/constants/OtpBinding.js +5 -0
- package/bin/messagesConnector/dtos/SendMessageRequest.d.ts +1 -0
- package/bin/messagesConnector/dtos/SendMessageRequest.js +7 -0
- package/bin/messagesConnector/dtos/VerifyOtpRequest.d.ts +2 -0
- package/bin/messagesConnector/dtos/VerifyOtpRequest.js +14 -0
- package/bin/messagesConnector/dtos/VerifyOtpResponse.d.ts +6 -0
- package/bin/messagesConnector/index.d.ts +1 -0
- package/bin/messagesConnector/index.js +1 -0
- package/bin/retailWizard/dtos/requests/SignatureSendOtpRequest.d.ts +7 -0
- package/bin/retailWizard/dtos/requests/SignatureSendOtpRequest.js +26 -0
- package/bin/retailWizard/index.d.ts +1 -0
- package/bin/retailWizard/index.js +1 -0
- package/package.json +1 -1
- package/src/loanCredit/dtos/LoanContract.ts +10 -2
- package/src/loanCredit/dtos/LoanContractSignatureEvidence.ts +50 -0
- package/src/loanCredit/dtos/SignatureContext.ts +75 -0
- package/src/loanCredit/dtos/requests/SignLoanCreditRequest.ts +11 -0
- package/src/loanCredit/dtos/responses/LoanContractResponse.ts +3 -0
- package/src/loanCredit/enums/ContractTypeEnum.ts +2 -0
- package/src/loanCredit/index.ts +2 -0
- package/src/messagesConnector/constants/OtpBinding.ts +2 -0
- package/src/messagesConnector/dtos/SendMessageRequest.ts +5 -1
- package/src/messagesConnector/dtos/VerifyOtpRequest.ts +5 -1
- package/src/messagesConnector/dtos/VerifyOtpResponse.ts +6 -0
- package/src/messagesConnector/index.ts +1 -0
- package/src/retailWizard/dtos/requests/SignatureSendOtpRequest.ts +12 -0
- package/src/retailWizard/index.ts +1 -0
|
@@ -16,12 +16,13 @@ import {
|
|
|
16
16
|
const sortedValues = (enumObject: Record<string, string>) => Object.values(enumObject).sort();
|
|
17
17
|
|
|
18
18
|
describe('ContractTypeEnum', () => {
|
|
19
|
-
it('suma los documentos del ciclo de vida a los tres de la originación', () => {
|
|
19
|
+
it('suma la constancia de firma y los documentos del ciclo de vida a los tres de la originación', () => {
|
|
20
20
|
expect(sortedValues(ContractTypeEnum)).toEqual(
|
|
21
21
|
[
|
|
22
22
|
'CREDIT',
|
|
23
23
|
'PROMISSORY_NOTE',
|
|
24
24
|
'SIC_AUTHORIZATION',
|
|
25
|
+
'SIGNATURE_EVIDENCE',
|
|
25
26
|
'RESTRUCTURE_ADDENDUM',
|
|
26
27
|
'ADVANCE_AUTHORIZATION',
|
|
27
28
|
'SETTLEMENT_CERTIFICATE',
|
|
@@ -86,3 +86,40 @@ describe('SignLoanCreditRequest', () => {
|
|
|
86
86
|
expect(await errorsOf({ contractDetails: details })).toEqual(['contractDetails.provider.legalName']);
|
|
87
87
|
});
|
|
88
88
|
});
|
|
89
|
+
|
|
90
|
+
const CONTEXT = {
|
|
91
|
+
ip: '201.141.10.20',
|
|
92
|
+
userAgent: 'Mozilla/5.0',
|
|
93
|
+
termsAccepted: true,
|
|
94
|
+
sellerId: 'ru-1',
|
|
95
|
+
sellerActorId: 'sub-1',
|
|
96
|
+
sellerName: 'Ana López',
|
|
97
|
+
storeId: 'st-1',
|
|
98
|
+
storeName: 'Tienda Centro',
|
|
99
|
+
wizardSessionId: 'WZ-1',
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
describe('SignLoanCreditRequest.signatureContext', () => {
|
|
103
|
+
it('acepta el contexto completo', async () => {
|
|
104
|
+
expect(await errorsOf({ signatureContext: CONTEXT })).toEqual([]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('acepta el contexto sin nombres ni navegador', async () => {
|
|
108
|
+
const minimal = { ip: CONTEXT.ip, sellerId: 'ru-1', sellerActorId: 'sub-1', storeId: 'st-1', wizardSessionId: 'WZ-1' };
|
|
109
|
+
expect(await errorsOf({ signatureContext: minimal })).toEqual([]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('exige ip, vendedor, tienda y sesión', async () => {
|
|
113
|
+
expect(await errorsOf({ signatureContext: {} })).toEqual([
|
|
114
|
+
'signatureContext.ip',
|
|
115
|
+
'signatureContext.sellerActorId',
|
|
116
|
+
'signatureContext.sellerId',
|
|
117
|
+
'signatureContext.storeId',
|
|
118
|
+
'signatureContext.wizardSessionId',
|
|
119
|
+
]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('rechaza una aceptación que no es booleana', async () => {
|
|
123
|
+
expect(await errorsOf({ signatureContext: { ...CONTEXT, termsAccepted: 'si' } })).toEqual(['signatureContext.termsAccepted']);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import { SendMessageRequest, VerifyOtpRequest } from '../../../src/messagesConnector/index';
|
|
5
|
+
import { DeliveryChannelEnum } from '../../../src/messaging';
|
|
6
|
+
|
|
7
|
+
const HASH = 'a'.repeat(64);
|
|
8
|
+
const SEND = {
|
|
9
|
+
channelType: DeliveryChannelEnum.SMS,
|
|
10
|
+
messageType: 'CONTRACT_SIGNATURE_OTP',
|
|
11
|
+
directoryId: 'd1',
|
|
12
|
+
typeOfDirectory: 'USER',
|
|
13
|
+
language: 'es',
|
|
14
|
+
country: 'MX',
|
|
15
|
+
destination: '+525512345678',
|
|
16
|
+
transactionNumber: 'c-1',
|
|
17
|
+
};
|
|
18
|
+
const VERIFY = { directoryId: 'd1', typeOfDirectoryId: 'USER', message: '1234' };
|
|
19
|
+
|
|
20
|
+
const failing = async (cls: new () => object, body: Record<string, unknown>): Promise<string[]> =>
|
|
21
|
+
(await validate(plainToInstance(cls, body))).map((error) => error.property).sort();
|
|
22
|
+
|
|
23
|
+
describe('amarre del código de firma', () => {
|
|
24
|
+
it('SendMessageRequest acepta la huella sha256 del documento', async () => {
|
|
25
|
+
expect(await failing(SendMessageRequest, { ...SEND, documentHash: HASH })).toEqual([]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('SendMessageRequest rechaza una huella que no es sha256 en hexadecimal', async () => {
|
|
29
|
+
expect(await failing(SendMessageRequest, { ...SEND, documentHash: 'ABC' })).toEqual(['documentHash']);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('VerifyOtpRequest acepta el crédito y la huella', async () => {
|
|
33
|
+
expect(await failing(VerifyOtpRequest, { ...VERIFY, transactionNumber: 'c-1', documentHash: HASH })).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('VerifyOtpRequest sigue aceptando la verificación sin amarre', async () => {
|
|
37
|
+
expect(await failing(VerifyOtpRequest, VERIFY)).toEqual([]);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('VerifyOtpRequest rechaza una huella inválida', async () => {
|
|
41
|
+
expect(await failing(VerifyOtpRequest, { ...VERIFY, documentHash: 'x' })).toEqual(['documentHash']);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import { SignatureSendOtpRequest } from '../../../src/retailWizard/index';
|
|
5
|
+
|
|
6
|
+
const failing = async (body: Record<string, unknown>): Promise<string[]> =>
|
|
7
|
+
(await validate(plainToInstance(SignatureSendOtpRequest, body))).map((error) => error.property);
|
|
8
|
+
|
|
9
|
+
describe('SignatureSendOtpRequest', () => {
|
|
10
|
+
it('acepta la aceptación de los términos', async () => {
|
|
11
|
+
expect(await failing({ termsAccepted: true })).toEqual([]);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('rechaza el envío sin aceptación', async () => {
|
|
15
|
+
expect(await failing({})).toEqual(['termsAccepted']);
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('rechaza termsAccepted en false', async () => {
|
|
19
|
+
expect(await failing({ termsAccepted: false })).toEqual(['termsAccepted']);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('rechaza "true" como texto', async () => {
|
|
23
|
+
expect(await failing({ termsAccepted: 'true' })).toEqual(['termsAccepted']);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { ContractTypeEnum } from '../enums/ContractTypeEnum';
|
|
2
|
+
import type { LoanContractSignatureEvidence } from './LoanContractSignatureEvidence';
|
|
2
3
|
/**
|
|
3
4
|
* LoanContract — documento del contrato de crédito con firma FES (modelo-datos §5b ·
|
|
4
|
-
* `<T>LoanContract_GT` · M2 §4.3-§4.4). Un registro por documento
|
|
5
|
+
* `<T>LoanContract_GT` · M2 §4.3-§4.4). Un registro por documento: los 3 de la originación (C4), más la
|
|
6
|
+
* constancia de firma al firmar.
|
|
5
7
|
*
|
|
6
8
|
* Nace DRAFT en la originación (sin PDF); la firma FES genera el PDF, calcula su `sha256`,
|
|
7
9
|
* verifica el OTP y sella con NOM-151. Conservación documental: 10 años (NOM-151).
|
|
@@ -22,6 +24,8 @@ export declare class LoanContract {
|
|
|
22
24
|
/** Sello de tiempo NOM-151 (TSA). Ausente hasta firmar (AS del TSA connector). */
|
|
23
25
|
nom151Timestamp?: string;
|
|
24
26
|
signedAt?: string;
|
|
27
|
+
/** Evidencia de la firma con código (solo en documentos firmados). */
|
|
28
|
+
signatureEvidence?: LoanContractSignatureEvidence;
|
|
25
29
|
createdBy: string;
|
|
26
30
|
updatedBy: string;
|
|
27
31
|
createdAt: string;
|
|
@@ -16,7 +16,8 @@ const regex_1 = require("../../helpers/constans/regex");
|
|
|
16
16
|
const ContractTypeEnum_1 = require("../enums/ContractTypeEnum");
|
|
17
17
|
/**
|
|
18
18
|
* LoanContract — documento del contrato de crédito con firma FES (modelo-datos §5b ·
|
|
19
|
-
* `<T>LoanContract_GT` · M2 §4.3-§4.4). Un registro por documento
|
|
19
|
+
* `<T>LoanContract_GT` · M2 §4.3-§4.4). Un registro por documento: los 3 de la originación (C4), más la
|
|
20
|
+
* constancia de firma al firmar.
|
|
20
21
|
*
|
|
21
22
|
* Nace DRAFT en la originación (sin PDF); la firma FES genera el PDF, calcula su `sha256`,
|
|
22
23
|
* verifica el OTP y sella con NOM-151. Conservación documental: 10 años (NOM-151).
|
|
@@ -75,6 +76,12 @@ __decorate([
|
|
|
75
76
|
(0, class_validator_1.Matches)(regex_1.regexIso8601),
|
|
76
77
|
__metadata("design:type", String)
|
|
77
78
|
], LoanContract.prototype, "signedAt", void 0);
|
|
79
|
+
__decorate([
|
|
80
|
+
(0, class_transformer_1.Expose)(),
|
|
81
|
+
(0, class_validator_1.IsOptional)(),
|
|
82
|
+
(0, class_validator_1.IsObject)(),
|
|
83
|
+
__metadata("design:type", Object)
|
|
84
|
+
], LoanContract.prototype, "signatureEvidence", void 0);
|
|
78
85
|
__decorate([
|
|
79
86
|
(0, class_transformer_1.Expose)(),
|
|
80
87
|
(0, class_validator_1.IsString)(),
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** El código de firma tal como lo validó messages-business. */
|
|
2
|
+
export interface SignatureEvidenceOtp {
|
|
3
|
+
/** Id del envío en messages-business (fila del log del código). */
|
|
4
|
+
messageLogId: string;
|
|
5
|
+
sentAt: string;
|
|
6
|
+
verifiedAt: string;
|
|
7
|
+
channel: 'SMS';
|
|
8
|
+
/** Teléfono destino enmascarado (`****1234`). */
|
|
9
|
+
destinationMasked?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Envíos del código (con reenvíos) y validaciones fallidas antes de firmar. */
|
|
12
|
+
export interface SignatureEvidenceAttempts {
|
|
13
|
+
sends: number;
|
|
14
|
+
failedVerifications: number;
|
|
15
|
+
}
|
|
16
|
+
/** Aceptación de términos del tiempo 1, amarrada a la huella del contrato generado en esa llamada. */
|
|
17
|
+
export interface SignatureEvidenceAcceptance {
|
|
18
|
+
acceptedAt: string;
|
|
19
|
+
contractSha256: string;
|
|
20
|
+
ip: string;
|
|
21
|
+
userAgent?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Desde dónde y quién envió el código al firmar (tiempo 2). */
|
|
24
|
+
export interface SignatureEvidenceSigning {
|
|
25
|
+
ip: string;
|
|
26
|
+
userAgent?: string;
|
|
27
|
+
sellerActorId: string;
|
|
28
|
+
}
|
|
29
|
+
/** Quién facilitó la firma en la tienda. */
|
|
30
|
+
export interface SignatureEvidenceFacilitator {
|
|
31
|
+
sellerId: string;
|
|
32
|
+
sellerActorId: string;
|
|
33
|
+
sellerName?: string;
|
|
34
|
+
storeId: string;
|
|
35
|
+
storeName?: string;
|
|
36
|
+
wizardSessionId: string;
|
|
37
|
+
}
|
|
38
|
+
/** Evidencia de la firma con código que queda en cada documento firmado. */
|
|
39
|
+
export interface LoanContractSignatureEvidence {
|
|
40
|
+
otp: SignatureEvidenceOtp;
|
|
41
|
+
attempts: SignatureEvidenceAttempts;
|
|
42
|
+
acceptance: SignatureEvidenceAcceptance;
|
|
43
|
+
signing: SignatureEvidenceSigning;
|
|
44
|
+
facilitator: SignatureEvidenceFacilitator;
|
|
45
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contexto de la firma que aporta el wizard en cada tiempo de `POST /private/credits/:creditId/sign`:
|
|
3
|
+
* quién facilita la firma (vendedor, tienda, sesión) y desde qué navegador. Es evidencia de la
|
|
4
|
+
* ceremonia: la IP y el navegador son del equipo de la tienda. Nunca se loguean.
|
|
5
|
+
*/
|
|
6
|
+
export declare class SignatureContext {
|
|
7
|
+
/** IP de origen de la llamada, como la ve el API Gateway del wizard. */
|
|
8
|
+
ip: string;
|
|
9
|
+
userAgent?: string;
|
|
10
|
+
/** Tiempo 1: el cliente marcó "Acepto los términos". El motor exige `true` para mandar el código. */
|
|
11
|
+
termsAccepted?: boolean;
|
|
12
|
+
/** Usuario retail del vendedor. */
|
|
13
|
+
sellerId: string;
|
|
14
|
+
/** Cognito sub del vendedor: queda como actor de la firma. */
|
|
15
|
+
sellerActorId: string;
|
|
16
|
+
sellerName?: string;
|
|
17
|
+
storeId: string;
|
|
18
|
+
storeName?: string;
|
|
19
|
+
wizardSessionId: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
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.SignatureContext = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/** Largo máximo de un id operacional (vendedor, tienda, sesión). */
|
|
16
|
+
const ID_TEXT = 128;
|
|
17
|
+
/** Largo máximo de un nombre para mostrar. */
|
|
18
|
+
const NAME_TEXT = 300;
|
|
19
|
+
/** Una IPv6 mide 39 caracteres; se deja margen para el formato mapeado. */
|
|
20
|
+
const IP_TEXT = 64;
|
|
21
|
+
/** Los navegadores mandan User-Agent de 150 a 300 caracteres. */
|
|
22
|
+
const USER_AGENT_TEXT = 512;
|
|
23
|
+
/**
|
|
24
|
+
* Contexto de la firma que aporta el wizard en cada tiempo de `POST /private/credits/:creditId/sign`:
|
|
25
|
+
* quién facilita la firma (vendedor, tienda, sesión) y desde qué navegador. Es evidencia de la
|
|
26
|
+
* ceremonia: la IP y el navegador son del equipo de la tienda. Nunca se loguean.
|
|
27
|
+
*/
|
|
28
|
+
class SignatureContext {
|
|
29
|
+
}
|
|
30
|
+
exports.SignatureContext = SignatureContext;
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, class_transformer_1.Expose)(),
|
|
33
|
+
(0, class_validator_1.IsString)(),
|
|
34
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
35
|
+
(0, class_validator_1.MaxLength)(IP_TEXT),
|
|
36
|
+
__metadata("design:type", String)
|
|
37
|
+
], SignatureContext.prototype, "ip", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, class_transformer_1.Expose)(),
|
|
40
|
+
(0, class_validator_1.IsOptional)(),
|
|
41
|
+
(0, class_validator_1.IsString)(),
|
|
42
|
+
(0, class_validator_1.MaxLength)(USER_AGENT_TEXT),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], SignatureContext.prototype, "userAgent", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
(0, class_transformer_1.Expose)(),
|
|
47
|
+
(0, class_validator_1.IsOptional)(),
|
|
48
|
+
(0, class_validator_1.IsBoolean)(),
|
|
49
|
+
__metadata("design:type", Boolean)
|
|
50
|
+
], SignatureContext.prototype, "termsAccepted", void 0);
|
|
51
|
+
__decorate([
|
|
52
|
+
(0, class_transformer_1.Expose)(),
|
|
53
|
+
(0, class_validator_1.IsString)(),
|
|
54
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
55
|
+
(0, class_validator_1.MaxLength)(ID_TEXT),
|
|
56
|
+
__metadata("design:type", String)
|
|
57
|
+
], SignatureContext.prototype, "sellerId", void 0);
|
|
58
|
+
__decorate([
|
|
59
|
+
(0, class_transformer_1.Expose)(),
|
|
60
|
+
(0, class_validator_1.IsString)(),
|
|
61
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
62
|
+
(0, class_validator_1.MaxLength)(ID_TEXT),
|
|
63
|
+
__metadata("design:type", String)
|
|
64
|
+
], SignatureContext.prototype, "sellerActorId", void 0);
|
|
65
|
+
__decorate([
|
|
66
|
+
(0, class_transformer_1.Expose)(),
|
|
67
|
+
(0, class_validator_1.IsOptional)(),
|
|
68
|
+
(0, class_validator_1.IsString)(),
|
|
69
|
+
(0, class_validator_1.MaxLength)(NAME_TEXT),
|
|
70
|
+
__metadata("design:type", String)
|
|
71
|
+
], SignatureContext.prototype, "sellerName", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
(0, class_transformer_1.Expose)(),
|
|
74
|
+
(0, class_validator_1.IsString)(),
|
|
75
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
76
|
+
(0, class_validator_1.MaxLength)(ID_TEXT),
|
|
77
|
+
__metadata("design:type", String)
|
|
78
|
+
], SignatureContext.prototype, "storeId", void 0);
|
|
79
|
+
__decorate([
|
|
80
|
+
(0, class_transformer_1.Expose)(),
|
|
81
|
+
(0, class_validator_1.IsOptional)(),
|
|
82
|
+
(0, class_validator_1.IsString)(),
|
|
83
|
+
(0, class_validator_1.MaxLength)(NAME_TEXT),
|
|
84
|
+
__metadata("design:type", String)
|
|
85
|
+
], SignatureContext.prototype, "storeName", void 0);
|
|
86
|
+
__decorate([
|
|
87
|
+
(0, class_transformer_1.Expose)(),
|
|
88
|
+
(0, class_validator_1.IsString)(),
|
|
89
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
90
|
+
(0, class_validator_1.MaxLength)(ID_TEXT),
|
|
91
|
+
__metadata("design:type", String)
|
|
92
|
+
], SignatureContext.prototype, "wizardSessionId", void 0);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LoanContractDetails } from '../LoanContractDetails';
|
|
2
|
+
import { SignatureContext } from '../SignatureContext';
|
|
2
3
|
/**
|
|
3
4
|
* Body de `POST /private/credits/:creditId/sign` (loan-credit-business — wizard paso 08, firma FES
|
|
4
5
|
* M2 §4.4). Endpoint de DOS tiempos sobre el mismo contrato:
|
|
@@ -40,4 +41,9 @@ export declare class SignLoanCreditRequest {
|
|
|
40
41
|
* PII-zero — el teléfono vive en RetailCustomer).
|
|
41
42
|
*/
|
|
42
43
|
otpDestination?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Ambos tiempos: quién facilita la firma y desde qué navegador (evidencia de la ceremonia). En el
|
|
46
|
+
* tiempo 1 trae `termsAccepted: true`. El motor lo exige; la IP y el navegador nunca se loguean.
|
|
47
|
+
*/
|
|
48
|
+
signatureContext?: SignatureContext;
|
|
43
49
|
}
|
|
@@ -13,6 +13,7 @@ exports.SignLoanCreditRequest = void 0;
|
|
|
13
13
|
const class_transformer_1 = require("class-transformer");
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
15
|
const LoanContractDetails_1 = require("../LoanContractDetails");
|
|
16
|
+
const SignatureContext_1 = require("../SignatureContext");
|
|
16
17
|
/**
|
|
17
18
|
* Body de `POST /private/credits/:creditId/sign` (loan-credit-business — wizard paso 08, firma FES
|
|
18
19
|
* M2 §4.4). Endpoint de DOS tiempos sobre el mismo contrato:
|
|
@@ -61,3 +62,10 @@ __decorate([
|
|
|
61
62
|
(0, class_validator_1.IsString)(),
|
|
62
63
|
__metadata("design:type", String)
|
|
63
64
|
], SignLoanCreditRequest.prototype, "otpDestination", void 0);
|
|
65
|
+
__decorate([
|
|
66
|
+
(0, class_transformer_1.Expose)(),
|
|
67
|
+
(0, class_validator_1.IsOptional)(),
|
|
68
|
+
(0, class_validator_1.ValidateNested)(),
|
|
69
|
+
(0, class_transformer_1.Type)(() => SignatureContext_1.SignatureContext),
|
|
70
|
+
__metadata("design:type", SignatureContext_1.SignatureContext)
|
|
71
|
+
], SignLoanCreditRequest.prototype, "signatureContext", void 0);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ContractTypeEnum } from '../../enums/ContractTypeEnum';
|
|
2
|
+
import type { LoanContractSignatureEvidence } from '../LoanContractSignatureEvidence';
|
|
2
3
|
/**
|
|
3
4
|
* Response de un documento del contrato (loan-credit-business). `signedAt` ausente = draft.
|
|
4
5
|
*/
|
|
@@ -12,6 +13,8 @@ export interface LoanContractResponse {
|
|
|
12
13
|
otpVerified: boolean;
|
|
13
14
|
nom151Timestamp?: string;
|
|
14
15
|
signedAt?: string;
|
|
16
|
+
/** Evidencia de la firma con código (solo en documentos firmados). */
|
|
17
|
+
signatureEvidence?: LoanContractSignatureEvidence;
|
|
15
18
|
createdAt: string;
|
|
16
19
|
updatedAt: string;
|
|
17
20
|
}
|
|
@@ -6,6 +6,8 @@ export declare enum ContractTypeEnum {
|
|
|
6
6
|
CREDIT = "CREDIT",
|
|
7
7
|
PROMISSORY_NOTE = "PROMISSORY_NOTE",
|
|
8
8
|
SIC_AUTHORIZATION = "SIC_AUTHORIZATION",
|
|
9
|
+
/** Constancia de firma electrónica: la evidencia de la firma con código, en PDF. */
|
|
10
|
+
SIGNATURE_EVIDENCE = "SIGNATURE_EVIDENCE",
|
|
9
11
|
RESTRUCTURE_ADDENDUM = "RESTRUCTURE_ADDENDUM",
|
|
10
12
|
ADVANCE_AUTHORIZATION = "ADVANCE_AUTHORIZATION",
|
|
11
13
|
SETTLEMENT_CERTIFICATE = "SETTLEMENT_CERTIFICATE",
|
|
@@ -10,6 +10,8 @@ var ContractTypeEnum;
|
|
|
10
10
|
ContractTypeEnum["CREDIT"] = "CREDIT";
|
|
11
11
|
ContractTypeEnum["PROMISSORY_NOTE"] = "PROMISSORY_NOTE";
|
|
12
12
|
ContractTypeEnum["SIC_AUTHORIZATION"] = "SIC_AUTHORIZATION";
|
|
13
|
+
/** Constancia de firma electrónica: la evidencia de la firma con código, en PDF. */
|
|
14
|
+
ContractTypeEnum["SIGNATURE_EVIDENCE"] = "SIGNATURE_EVIDENCE";
|
|
13
15
|
ContractTypeEnum["RESTRUCTURE_ADDENDUM"] = "RESTRUCTURE_ADDENDUM";
|
|
14
16
|
ContractTypeEnum["ADVANCE_AUTHORIZATION"] = "ADVANCE_AUTHORIZATION";
|
|
15
17
|
ContractTypeEnum["SETTLEMENT_CERTIFICATE"] = "SETTLEMENT_CERTIFICATE";
|
|
@@ -9,6 +9,8 @@ export * from './dtos/LoanInstallment';
|
|
|
9
9
|
export * from './dtos/InstallmentPaidEvent';
|
|
10
10
|
export * from './dtos/LoanContract';
|
|
11
11
|
export * from './dtos/LoanContractDetails';
|
|
12
|
+
export * from './dtos/SignatureContext';
|
|
13
|
+
export * from './dtos/LoanContractSignatureEvidence';
|
|
12
14
|
export * from './dtos/ActivationChecklist';
|
|
13
15
|
export * from './dtos/AppliedPromotionSnapshot';
|
|
14
16
|
export * from './dtos/AppliedStorePolicySnapshot';
|
package/bin/loanCredit/index.js
CHANGED
|
@@ -30,6 +30,8 @@ __exportStar(require("./dtos/LoanInstallment"), exports);
|
|
|
30
30
|
__exportStar(require("./dtos/InstallmentPaidEvent"), exports);
|
|
31
31
|
__exportStar(require("./dtos/LoanContract"), exports);
|
|
32
32
|
__exportStar(require("./dtos/LoanContractDetails"), exports);
|
|
33
|
+
__exportStar(require("./dtos/SignatureContext"), exports);
|
|
34
|
+
__exportStar(require("./dtos/LoanContractSignatureEvidence"), exports);
|
|
33
35
|
__exportStar(require("./dtos/ActivationChecklist"), exports);
|
|
34
36
|
__exportStar(require("./dtos/AppliedPromotionSnapshot"), exports);
|
|
35
37
|
__exportStar(require("./dtos/AppliedStorePolicySnapshot"), exports);
|
|
@@ -13,6 +13,7 @@ exports.SendMessageRequest = void 0;
|
|
|
13
13
|
const class_transformer_1 = require("class-transformer");
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
15
|
const messaging_1 = require("../../messaging");
|
|
16
|
+
const OtpBinding_1 = require("../constants/OtpBinding");
|
|
16
17
|
const OtpMessagePurposeEnum_1 = require("../enums/OtpMessagePurposeEnum");
|
|
17
18
|
class SendMessageRequest {
|
|
18
19
|
}
|
|
@@ -118,6 +119,12 @@ __decorate([
|
|
|
118
119
|
(0, class_validator_1.IsString)(),
|
|
119
120
|
__metadata("design:type", String)
|
|
120
121
|
], SendMessageRequest.prototype, "transactionNumber", void 0);
|
|
122
|
+
__decorate([
|
|
123
|
+
(0, class_transformer_1.Expose)(),
|
|
124
|
+
(0, class_validator_1.IsOptional)(),
|
|
125
|
+
(0, class_validator_1.Matches)(OtpBinding_1.OTP_DOCUMENT_HASH_PATTERN),
|
|
126
|
+
__metadata("design:type", String)
|
|
127
|
+
], SendMessageRequest.prototype, "documentHash", void 0);
|
|
121
128
|
__decorate([
|
|
122
129
|
(0, class_transformer_1.Expose)(),
|
|
123
130
|
(0, class_validator_1.IsOptional)(),
|
|
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.VerifyOtpRequest = void 0;
|
|
13
13
|
const class_transformer_1 = require("class-transformer");
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
|
+
const OtpBinding_1 = require("../constants/OtpBinding");
|
|
15
16
|
const OtpMessagePurposeEnum_1 = require("../enums/OtpMessagePurposeEnum");
|
|
16
17
|
class VerifyOtpRequest {
|
|
17
18
|
}
|
|
@@ -40,3 +41,16 @@ __decorate([
|
|
|
40
41
|
(0, class_validator_1.IsEnum)(OtpMessagePurposeEnum_1.OtpMessagePurposeEnum),
|
|
41
42
|
__metadata("design:type", String)
|
|
42
43
|
], VerifyOtpRequest.prototype, "purpose", void 0);
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, class_transformer_1.Expose)(),
|
|
46
|
+
(0, class_validator_1.IsOptional)(),
|
|
47
|
+
(0, class_validator_1.IsString)(),
|
|
48
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
49
|
+
__metadata("design:type", String)
|
|
50
|
+
], VerifyOtpRequest.prototype, "transactionNumber", void 0);
|
|
51
|
+
__decorate([
|
|
52
|
+
(0, class_transformer_1.Expose)(),
|
|
53
|
+
(0, class_validator_1.IsOptional)(),
|
|
54
|
+
(0, class_validator_1.Matches)(OtpBinding_1.OTP_DOCUMENT_HASH_PATTERN),
|
|
55
|
+
__metadata("design:type", String)
|
|
56
|
+
], VerifyOtpRequest.prototype, "documentHash", void 0);
|
|
@@ -2,4 +2,10 @@ export declare class VerifyOtpResponse {
|
|
|
2
2
|
verified: boolean;
|
|
3
3
|
directoryId: string;
|
|
4
4
|
typeOfDirectoryId: string;
|
|
5
|
+
/** Id del envío (fila del log) que se validó. */
|
|
6
|
+
logId?: string;
|
|
7
|
+
/** Cuándo se mandó el código (ISO 8601). */
|
|
8
|
+
sentAt?: string;
|
|
9
|
+
/** Cuándo se validó (ISO 8601). */
|
|
10
|
+
verifiedAt?: string;
|
|
5
11
|
}
|
|
@@ -2,6 +2,7 @@ export * from './enums/DeliveryChannelExtendedEnum';
|
|
|
2
2
|
export * from './enums/NotificationOriginEnum';
|
|
3
3
|
export * from './enums/MessagingSlotEnum';
|
|
4
4
|
export * from './enums/OtpMessagePurposeEnum';
|
|
5
|
+
export * from './constants/OtpBinding';
|
|
5
6
|
export * from './validators/IsStringValueRecord';
|
|
6
7
|
export * from './dtos/NotificationQueueMessageRequestV2';
|
|
7
8
|
export * from './dtos/SendMessageRequest';
|
|
@@ -18,6 +18,7 @@ __exportStar(require("./enums/DeliveryChannelExtendedEnum"), exports);
|
|
|
18
18
|
__exportStar(require("./enums/NotificationOriginEnum"), exports);
|
|
19
19
|
__exportStar(require("./enums/MessagingSlotEnum"), exports);
|
|
20
20
|
__exportStar(require("./enums/OtpMessagePurposeEnum"), exports);
|
|
21
|
+
__exportStar(require("./constants/OtpBinding"), exports);
|
|
21
22
|
__exportStar(require("./validators/IsStringValueRecord"), exports);
|
|
22
23
|
__exportStar(require("./dtos/NotificationQueueMessageRequestV2"), exports);
|
|
23
24
|
__exportStar(require("./dtos/SendMessageRequest"), exports);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /wizard/sessions/:id/signature/send-otp — firma FES tiempo 1 (paso 08). El cliente marcó
|
|
3
|
+
* "Acepto los términos del contrato de crédito": sin esa aceptación el wizard no manda el código.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SignatureSendOtpRequest {
|
|
6
|
+
termsAccepted: true;
|
|
7
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
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.SignatureSendOtpRequest = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/**
|
|
16
|
+
* POST /wizard/sessions/:id/signature/send-otp — firma FES tiempo 1 (paso 08). El cliente marcó
|
|
17
|
+
* "Acepto los términos del contrato de crédito": sin esa aceptación el wizard no manda el código.
|
|
18
|
+
*/
|
|
19
|
+
class SignatureSendOtpRequest {
|
|
20
|
+
}
|
|
21
|
+
exports.SignatureSendOtpRequest = SignatureSendOtpRequest;
|
|
22
|
+
__decorate([
|
|
23
|
+
(0, class_transformer_1.Expose)(),
|
|
24
|
+
(0, class_validator_1.Equals)(true, { message: 'termsAccepted debe ser true: el cliente tiene que aceptar los términos' }),
|
|
25
|
+
__metadata("design:type", Boolean)
|
|
26
|
+
], SignatureSendOtpRequest.prototype, "termsAccepted", void 0);
|
|
@@ -91,6 +91,7 @@ export * from './dtos/requests/CancelSaleRequest';
|
|
|
91
91
|
export * from './dtos/requests/QuoteRequest';
|
|
92
92
|
export * from './dtos/requests/DownPaymentRequest';
|
|
93
93
|
export * from './dtos/requests/SignatureSignRequest';
|
|
94
|
+
export * from './dtos/requests/SignatureSendOtpRequest';
|
|
94
95
|
export * from './dtos/requests/RegisterDeviceRequest';
|
|
95
96
|
export * from './dtos/requests/CompleteSaleRequest';
|
|
96
97
|
export * from './dtos/requests/SuggestIdentifiersQuery';
|
|
@@ -116,6 +116,7 @@ __exportStar(require("./dtos/requests/CancelSaleRequest"), exports);
|
|
|
116
116
|
__exportStar(require("./dtos/requests/QuoteRequest"), exports);
|
|
117
117
|
__exportStar(require("./dtos/requests/DownPaymentRequest"), exports);
|
|
118
118
|
__exportStar(require("./dtos/requests/SignatureSignRequest"), exports);
|
|
119
|
+
__exportStar(require("./dtos/requests/SignatureSendOtpRequest"), exports);
|
|
119
120
|
__exportStar(require("./dtos/requests/RegisterDeviceRequest"), exports);
|
|
120
121
|
__exportStar(require("./dtos/requests/CompleteSaleRequest"), exports);
|
|
121
122
|
__exportStar(require("./dtos/requests/SuggestIdentifiersQuery"), exports);
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { Expose } from 'class-transformer';
|
|
2
|
-
import { IsBoolean, IsEnum, IsOptional, IsString, Matches } from 'class-validator';
|
|
2
|
+
import { IsBoolean, IsEnum, IsObject, IsOptional, IsString, Matches } from 'class-validator';
|
|
3
3
|
import { regexIso8601 } from '../../helpers/constans/regex';
|
|
4
4
|
import { ContractTypeEnum } from '../enums/ContractTypeEnum';
|
|
5
|
+
import type { LoanContractSignatureEvidence } from './LoanContractSignatureEvidence';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* LoanContract — documento del contrato de crédito con firma FES (modelo-datos §5b ·
|
|
8
|
-
* `<T>LoanContract_GT` · M2 §4.3-§4.4). Un registro por documento
|
|
9
|
+
* `<T>LoanContract_GT` · M2 §4.3-§4.4). Un registro por documento: los 3 de la originación (C4), más la
|
|
10
|
+
* constancia de firma al firmar.
|
|
9
11
|
*
|
|
10
12
|
* Nace DRAFT en la originación (sin PDF); la firma FES genera el PDF, calcula su `sha256`,
|
|
11
13
|
* verifica el OTP y sella con NOM-151. Conservación documental: 10 años (NOM-151).
|
|
@@ -58,6 +60,12 @@ export class LoanContract {
|
|
|
58
60
|
@Matches(regexIso8601)
|
|
59
61
|
signedAt?: string;
|
|
60
62
|
|
|
63
|
+
/** Evidencia de la firma con código (solo en documentos firmados). */
|
|
64
|
+
@Expose()
|
|
65
|
+
@IsOptional()
|
|
66
|
+
@IsObject()
|
|
67
|
+
signatureEvidence?: LoanContractSignatureEvidence;
|
|
68
|
+
|
|
61
69
|
@Expose()
|
|
62
70
|
@IsString()
|
|
63
71
|
createdBy!: string;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/** El código de firma tal como lo validó messages-business. */
|
|
2
|
+
export interface SignatureEvidenceOtp {
|
|
3
|
+
/** Id del envío en messages-business (fila del log del código). */
|
|
4
|
+
messageLogId: string;
|
|
5
|
+
sentAt: string;
|
|
6
|
+
verifiedAt: string;
|
|
7
|
+
channel: 'SMS';
|
|
8
|
+
/** Teléfono destino enmascarado (`****1234`). */
|
|
9
|
+
destinationMasked?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Envíos del código (con reenvíos) y validaciones fallidas antes de firmar. */
|
|
13
|
+
export interface SignatureEvidenceAttempts {
|
|
14
|
+
sends: number;
|
|
15
|
+
failedVerifications: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Aceptación de términos del tiempo 1, amarrada a la huella del contrato generado en esa llamada. */
|
|
19
|
+
export interface SignatureEvidenceAcceptance {
|
|
20
|
+
acceptedAt: string;
|
|
21
|
+
contractSha256: string;
|
|
22
|
+
ip: string;
|
|
23
|
+
userAgent?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Desde dónde y quién envió el código al firmar (tiempo 2). */
|
|
27
|
+
export interface SignatureEvidenceSigning {
|
|
28
|
+
ip: string;
|
|
29
|
+
userAgent?: string;
|
|
30
|
+
sellerActorId: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Quién facilitó la firma en la tienda. */
|
|
34
|
+
export interface SignatureEvidenceFacilitator {
|
|
35
|
+
sellerId: string;
|
|
36
|
+
sellerActorId: string;
|
|
37
|
+
sellerName?: string;
|
|
38
|
+
storeId: string;
|
|
39
|
+
storeName?: string;
|
|
40
|
+
wizardSessionId: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Evidencia de la firma con código que queda en cada documento firmado. */
|
|
44
|
+
export interface LoanContractSignatureEvidence {
|
|
45
|
+
otp: SignatureEvidenceOtp;
|
|
46
|
+
attempts: SignatureEvidenceAttempts;
|
|
47
|
+
acceptance: SignatureEvidenceAcceptance;
|
|
48
|
+
signing: SignatureEvidenceSigning;
|
|
49
|
+
facilitator: SignatureEvidenceFacilitator;
|
|
50
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsBoolean, IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
/** Largo máximo de un id operacional (vendedor, tienda, sesión). */
|
|
5
|
+
const ID_TEXT = 128;
|
|
6
|
+
/** Largo máximo de un nombre para mostrar. */
|
|
7
|
+
const NAME_TEXT = 300;
|
|
8
|
+
/** Una IPv6 mide 39 caracteres; se deja margen para el formato mapeado. */
|
|
9
|
+
const IP_TEXT = 64;
|
|
10
|
+
/** Los navegadores mandan User-Agent de 150 a 300 caracteres. */
|
|
11
|
+
const USER_AGENT_TEXT = 512;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Contexto de la firma que aporta el wizard en cada tiempo de `POST /private/credits/:creditId/sign`:
|
|
15
|
+
* quién facilita la firma (vendedor, tienda, sesión) y desde qué navegador. Es evidencia de la
|
|
16
|
+
* ceremonia: la IP y el navegador son del equipo de la tienda. Nunca se loguean.
|
|
17
|
+
*/
|
|
18
|
+
export class SignatureContext {
|
|
19
|
+
/** IP de origen de la llamada, como la ve el API Gateway del wizard. */
|
|
20
|
+
@Expose()
|
|
21
|
+
@IsString()
|
|
22
|
+
@IsNotEmpty()
|
|
23
|
+
@MaxLength(IP_TEXT)
|
|
24
|
+
ip!: string;
|
|
25
|
+
|
|
26
|
+
@Expose()
|
|
27
|
+
@IsOptional()
|
|
28
|
+
@IsString()
|
|
29
|
+
@MaxLength(USER_AGENT_TEXT)
|
|
30
|
+
userAgent?: string;
|
|
31
|
+
|
|
32
|
+
/** Tiempo 1: el cliente marcó "Acepto los términos". El motor exige `true` para mandar el código. */
|
|
33
|
+
@Expose()
|
|
34
|
+
@IsOptional()
|
|
35
|
+
@IsBoolean()
|
|
36
|
+
termsAccepted?: boolean;
|
|
37
|
+
|
|
38
|
+
/** Usuario retail del vendedor. */
|
|
39
|
+
@Expose()
|
|
40
|
+
@IsString()
|
|
41
|
+
@IsNotEmpty()
|
|
42
|
+
@MaxLength(ID_TEXT)
|
|
43
|
+
sellerId!: string;
|
|
44
|
+
|
|
45
|
+
/** Cognito sub del vendedor: queda como actor de la firma. */
|
|
46
|
+
@Expose()
|
|
47
|
+
@IsString()
|
|
48
|
+
@IsNotEmpty()
|
|
49
|
+
@MaxLength(ID_TEXT)
|
|
50
|
+
sellerActorId!: string;
|
|
51
|
+
|
|
52
|
+
@Expose()
|
|
53
|
+
@IsOptional()
|
|
54
|
+
@IsString()
|
|
55
|
+
@MaxLength(NAME_TEXT)
|
|
56
|
+
sellerName?: string;
|
|
57
|
+
|
|
58
|
+
@Expose()
|
|
59
|
+
@IsString()
|
|
60
|
+
@IsNotEmpty()
|
|
61
|
+
@MaxLength(ID_TEXT)
|
|
62
|
+
storeId!: string;
|
|
63
|
+
|
|
64
|
+
@Expose()
|
|
65
|
+
@IsOptional()
|
|
66
|
+
@IsString()
|
|
67
|
+
@MaxLength(NAME_TEXT)
|
|
68
|
+
storeName?: string;
|
|
69
|
+
|
|
70
|
+
@Expose()
|
|
71
|
+
@IsString()
|
|
72
|
+
@IsNotEmpty()
|
|
73
|
+
@MaxLength(ID_TEXT)
|
|
74
|
+
wizardSessionId!: string;
|
|
75
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Expose, Type } from 'class-transformer';
|
|
2
2
|
import { IsObject, IsOptional, IsString, Length, ValidateNested } from 'class-validator';
|
|
3
3
|
import { LoanContractDetails } from '../LoanContractDetails';
|
|
4
|
+
import { SignatureContext } from '../SignatureContext';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Body de `POST /private/credits/:creditId/sign` (loan-credit-business — wizard paso 08, firma FES
|
|
@@ -64,4 +65,14 @@ export class SignLoanCreditRequest {
|
|
|
64
65
|
@IsOptional()
|
|
65
66
|
@IsString()
|
|
66
67
|
otpDestination?: string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Ambos tiempos: quién facilita la firma y desde qué navegador (evidencia de la ceremonia). En el
|
|
71
|
+
* tiempo 1 trae `termsAccepted: true`. El motor lo exige; la IP y el navegador nunca se loguean.
|
|
72
|
+
*/
|
|
73
|
+
@Expose()
|
|
74
|
+
@IsOptional()
|
|
75
|
+
@ValidateNested()
|
|
76
|
+
@Type(() => SignatureContext)
|
|
77
|
+
signatureContext?: SignatureContext;
|
|
67
78
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ContractTypeEnum } from '../../enums/ContractTypeEnum';
|
|
2
|
+
import type { LoanContractSignatureEvidence } from '../LoanContractSignatureEvidence';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Response de un documento del contrato (loan-credit-business). `signedAt` ausente = draft.
|
|
@@ -13,6 +14,8 @@ export interface LoanContractResponse {
|
|
|
13
14
|
otpVerified: boolean;
|
|
14
15
|
nom151Timestamp?: string;
|
|
15
16
|
signedAt?: string;
|
|
17
|
+
/** Evidencia de la firma con código (solo en documentos firmados). */
|
|
18
|
+
signatureEvidence?: LoanContractSignatureEvidence;
|
|
16
19
|
createdAt: string;
|
|
17
20
|
updatedAt: string;
|
|
18
21
|
}
|
|
@@ -6,6 +6,8 @@ export enum ContractTypeEnum {
|
|
|
6
6
|
CREDIT = 'CREDIT',
|
|
7
7
|
PROMISSORY_NOTE = 'PROMISSORY_NOTE',
|
|
8
8
|
SIC_AUTHORIZATION = 'SIC_AUTHORIZATION',
|
|
9
|
+
/** Constancia de firma electrónica: la evidencia de la firma con código, en PDF. */
|
|
10
|
+
SIGNATURE_EVIDENCE = 'SIGNATURE_EVIDENCE',
|
|
9
11
|
RESTRUCTURE_ADDENDUM = 'RESTRUCTURE_ADDENDUM',
|
|
10
12
|
ADVANCE_AUTHORIZATION = 'ADVANCE_AUTHORIZATION',
|
|
11
13
|
SETTLEMENT_CERTIFICATE = 'SETTLEMENT_CERTIFICATE',
|
package/src/loanCredit/index.ts
CHANGED
|
@@ -13,6 +13,8 @@ export * from './dtos/LoanInstallment';
|
|
|
13
13
|
export * from './dtos/InstallmentPaidEvent';
|
|
14
14
|
export * from './dtos/LoanContract';
|
|
15
15
|
export * from './dtos/LoanContractDetails';
|
|
16
|
+
export * from './dtos/SignatureContext';
|
|
17
|
+
export * from './dtos/LoanContractSignatureEvidence';
|
|
16
18
|
export * from './dtos/ActivationChecklist';
|
|
17
19
|
export * from './dtos/AppliedPromotionSnapshot';
|
|
18
20
|
export * from './dtos/AppliedStorePolicySnapshot';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Expose } from 'class-transformer';
|
|
2
|
-
import { IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, IsUUID } from 'class-validator';
|
|
2
|
+
import { IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, IsUUID, Matches } from 'class-validator';
|
|
3
3
|
import { DeliveryChannelEnum } from '../../messaging';
|
|
4
|
+
import { OTP_DOCUMENT_HASH_PATTERN } from '../constants/OtpBinding';
|
|
4
5
|
import { OtpMessagePurposeEnum } from '../enums/OtpMessagePurposeEnum';
|
|
5
6
|
|
|
6
7
|
export class SendMessageRequest {
|
|
@@ -28,6 +29,9 @@ export class SendMessageRequest {
|
|
|
28
29
|
@Expose() @IsOptional() @IsObject() options?: Record<string, unknown>;
|
|
29
30
|
@Expose() @IsOptional() @IsUUID() referenceMessageId?: string;
|
|
30
31
|
@Expose() @IsOptional() @IsString() transactionNumber?: string;
|
|
32
|
+
// Huella del documento que firma el código (CONTRACT_SIGNATURE_OTP). Junto con `transactionNumber`
|
|
33
|
+
// amarra el código a ese documento: messages solo lo valida contra la misma pareja.
|
|
34
|
+
@Expose() @IsOptional() @Matches(OTP_DOCUMENT_HASH_PATTERN) documentHash?: string;
|
|
31
35
|
@Expose() @IsOptional() @IsEnum(OtpMessagePurposeEnum) purpose?: OtpMessagePurposeEnum;
|
|
32
36
|
// Tenant emisor: decide plantilla e identidad de envío. Sin él messages-business cae a FIADO.
|
|
33
37
|
@Expose() @IsOptional() @IsString() @IsNotEmpty() tenantId?: string;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Expose } from 'class-transformer';
|
|
2
|
-
import { IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
|
2
|
+
import { IsEnum, IsNotEmpty, IsOptional, IsString, Matches } from 'class-validator';
|
|
3
|
+
import { OTP_DOCUMENT_HASH_PATTERN } from '../constants/OtpBinding';
|
|
3
4
|
import { OtpMessagePurposeEnum } from '../enums/OtpMessagePurposeEnum';
|
|
4
5
|
|
|
5
6
|
export class VerifyOtpRequest {
|
|
@@ -11,4 +12,7 @@ export class VerifyOtpRequest {
|
|
|
11
12
|
@Expose() @IsString() @IsNotEmpty() typeOfDirectoryId!: string;
|
|
12
13
|
@Expose() @IsString() @IsNotEmpty() message!: string;
|
|
13
14
|
@Expose() @IsOptional() @IsEnum(OtpMessagePurposeEnum) purpose?: OtpMessagePurposeEnum;
|
|
15
|
+
// Amarre del código de firma: si vienen, la fila tiene que traer los mismos o el código no sirve.
|
|
16
|
+
@Expose() @IsOptional() @IsString() @IsNotEmpty() transactionNumber?: string;
|
|
17
|
+
@Expose() @IsOptional() @Matches(OTP_DOCUMENT_HASH_PATTERN) documentHash?: string;
|
|
14
18
|
}
|
|
@@ -2,4 +2,10 @@ export class VerifyOtpResponse {
|
|
|
2
2
|
verified!: boolean;
|
|
3
3
|
directoryId!: string;
|
|
4
4
|
typeOfDirectoryId!: string;
|
|
5
|
+
/** Id del envío (fila del log) que se validó. */
|
|
6
|
+
logId?: string;
|
|
7
|
+
/** Cuándo se mandó el código (ISO 8601). */
|
|
8
|
+
sentAt?: string;
|
|
9
|
+
/** Cuándo se validó (ISO 8601). */
|
|
10
|
+
verifiedAt?: string;
|
|
5
11
|
}
|
|
@@ -2,6 +2,7 @@ export * from './enums/DeliveryChannelExtendedEnum';
|
|
|
2
2
|
export * from './enums/NotificationOriginEnum';
|
|
3
3
|
export * from './enums/MessagingSlotEnum';
|
|
4
4
|
export * from './enums/OtpMessagePurposeEnum';
|
|
5
|
+
export * from './constants/OtpBinding';
|
|
5
6
|
export * from './validators/IsStringValueRecord';
|
|
6
7
|
export * from './dtos/NotificationQueueMessageRequestV2';
|
|
7
8
|
export * from './dtos/SendMessageRequest';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { Equals } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* POST /wizard/sessions/:id/signature/send-otp — firma FES tiempo 1 (paso 08). El cliente marcó
|
|
6
|
+
* "Acepto los términos del contrato de crédito": sin esa aceptación el wizard no manda el código.
|
|
7
|
+
*/
|
|
8
|
+
export class SignatureSendOtpRequest {
|
|
9
|
+
@Expose()
|
|
10
|
+
@Equals(true, { message: 'termsAccepted debe ser true: el cliente tiene que aceptar los términos' })
|
|
11
|
+
termsAccepted!: true;
|
|
12
|
+
}
|
|
@@ -102,6 +102,7 @@ export * from './dtos/requests/CancelSaleRequest';
|
|
|
102
102
|
export * from './dtos/requests/QuoteRequest';
|
|
103
103
|
export * from './dtos/requests/DownPaymentRequest';
|
|
104
104
|
export * from './dtos/requests/SignatureSignRequest';
|
|
105
|
+
export * from './dtos/requests/SignatureSendOtpRequest';
|
|
105
106
|
export * from './dtos/requests/RegisterDeviceRequest';
|
|
106
107
|
export * from './dtos/requests/CompleteSaleRequest';
|
|
107
108
|
export * from './dtos/requests/SuggestIdentifiersQuery';
|