@fiado/type-kit 3.406.0 → 3.408.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/biometrics/BiometricReferenceSourceEnum.test.ts +18 -0
- package/_test_/unit/biometrics/BiometricVerificationResponse.test.ts +63 -0
- package/_test_/unit/biometrics/CreateBiometricVerificationRequest.test.ts +57 -0
- package/_test_/unit/identity/PeopleIdPhotoResponse.test.ts +33 -0
- package/bin/biometrics/dtos/requests/CreateBiometricVerificationRequest.d.ts +13 -0
- package/bin/biometrics/dtos/requests/CreateBiometricVerificationRequest.js +7 -0
- package/bin/biometrics/dtos/responses/BiometricVerificationResponse.d.ts +9 -0
- package/bin/biometrics/dtos/responses/BiometricVerificationResponse.js +6 -0
- package/bin/biometrics/enums/BiometricReferenceSourceEnum.d.ts +14 -0
- package/bin/biometrics/enums/BiometricReferenceSourceEnum.js +18 -0
- package/bin/biometrics/events/BiometricVerificationChangedV1.d.ts +12 -20
- package/bin/biometrics/events/BiometricVerificationChangedV1.js +7 -12
- package/bin/biometrics/index.d.ts +1 -0
- package/bin/biometrics/index.js +1 -0
- package/bin/identity/dtos/PeopleIdPhotoResponse.d.ts +17 -0
- package/bin/identity/dtos/PeopleIdPhotoResponse.js +49 -0
- package/bin/identity/index.d.ts +1 -0
- package/bin/identity/index.js +1 -0
- package/bin/loanCredit/constants/creditPaymentHook.d.ts +2 -0
- package/bin/loanCredit/constants/creditPaymentHook.js +5 -0
- package/bin/loanCredit/dtos/requests/CreditPaymentAppliedRequest.d.ts +10 -0
- package/bin/loanCredit/dtos/requests/CreditPaymentAppliedRequest.js +38 -0
- package/bin/loanCredit/dtos/requests/CreditSettledRequest.d.ts +10 -0
- package/bin/loanCredit/dtos/requests/CreditSettledRequest.js +38 -0
- package/bin/loanCredit/dtos/responses/CreditPaymentAppliedResponse.d.ts +8 -0
- package/bin/loanCredit/dtos/responses/CreditPaymentAppliedResponse.js +2 -0
- package/bin/loanCredit/dtos/responses/CreditSettledResponse.d.ts +8 -0
- package/bin/loanCredit/dtos/responses/CreditSettledResponse.js +2 -0
- package/bin/loanCredit/enums/CreditPaymentUnlockDecisionEnum.d.ts +20 -0
- package/bin/loanCredit/enums/CreditPaymentUnlockDecisionEnum.js +24 -0
- package/bin/loanCredit/enums/CreditSettlementDecisionEnum.d.ts +21 -0
- package/bin/loanCredit/enums/CreditSettlementDecisionEnum.js +25 -0
- package/bin/loanCredit/enums/CreditSettlementReleaseDecisionEnum.d.ts +17 -0
- package/bin/loanCredit/enums/CreditSettlementReleaseDecisionEnum.js +21 -0
- package/bin/loanCredit/index.d.ts +8 -0
- package/bin/loanCredit/index.js +8 -0
- package/package.json +1 -1
- package/src/biometrics/dtos/requests/CreateBiometricVerificationRequest.ts +20 -0
- package/src/biometrics/dtos/responses/BiometricVerificationResponse.ts +11 -0
- package/src/biometrics/enums/BiometricReferenceSourceEnum.ts +16 -0
- package/src/biometrics/events/BiometricVerificationChangedV1.ts +12 -20
- package/src/biometrics/index.ts +1 -0
- package/src/identity/dtos/PeopleIdPhotoResponse.ts +27 -0
- package/src/identity/index.ts +1 -0
- package/src/loanCredit/constants/creditPaymentHook.ts +2 -0
- package/src/loanCredit/dtos/requests/CreditPaymentAppliedRequest.ts +25 -0
- package/src/loanCredit/dtos/requests/CreditSettledRequest.ts +25 -0
- package/src/loanCredit/dtos/responses/CreditPaymentAppliedResponse.ts +9 -0
- package/src/loanCredit/dtos/responses/CreditSettledResponse.ts +9 -0
- package/src/loanCredit/enums/CreditPaymentUnlockDecisionEnum.ts +20 -0
- package/src/loanCredit/enums/CreditSettlementDecisionEnum.ts +21 -0
- package/src/loanCredit/enums/CreditSettlementReleaseDecisionEnum.ts +17 -0
- package/src/loanCredit/index.ts +8 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { BiometricReferenceSourceEnum } from '../../../src/biometrics/index';
|
|
3
|
+
|
|
4
|
+
describe('BiometricReferenceSourceEnum', () => {
|
|
5
|
+
it('tiene exactamente los tres valores del contrato', () => {
|
|
6
|
+
expect(Object.values(BiometricReferenceSourceEnum).sort()).toEqual([
|
|
7
|
+
'CALLER_PROVIDED',
|
|
8
|
+
'ID_DOCUMENT',
|
|
9
|
+
'KYC_SELFIE',
|
|
10
|
+
]);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
it('cada clave es igual a su valor', () => {
|
|
14
|
+
for (const [clave, valor] of Object.entries(BiometricReferenceSourceEnum)) {
|
|
15
|
+
expect(clave).toBe(valor);
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import {
|
|
5
|
+
BiometricVerificationResponse,
|
|
6
|
+
BiometricReferenceSourceEnum,
|
|
7
|
+
} from '../../../src/biometrics/index';
|
|
8
|
+
|
|
9
|
+
/** La respuesta mínima válida: todos los campos obligatorios del contrato. */
|
|
10
|
+
const base = {
|
|
11
|
+
biometricVerificationId: 'bio-1',
|
|
12
|
+
type: 'FACEMATCH',
|
|
13
|
+
provider: 'METAMAP',
|
|
14
|
+
directoryId: 'dir-1',
|
|
15
|
+
status: 'IN_PROGRESS',
|
|
16
|
+
result: 'UNKNOWN',
|
|
17
|
+
deliveryMode: 'REDIRECT',
|
|
18
|
+
delivery: { link: 'https://sk.fiado.test/abc', expiresAt: '2026-09-04T17:00:00.000Z' },
|
|
19
|
+
referenceImageSource: 'KYC_SELFIE',
|
|
20
|
+
createdAt: '2026-09-04T16:00:00.000Z',
|
|
21
|
+
updatedAt: '2026-09-04T16:00:00.000Z',
|
|
22
|
+
expiresAt: '2026-09-04T17:00:00.000Z',
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const instancia = (raw: Record<string, unknown>): BiometricVerificationResponse =>
|
|
26
|
+
plainToInstance(BiometricVerificationResponse, raw, { excludeExtraneousValues: true });
|
|
27
|
+
|
|
28
|
+
const propiedadesConError = async (raw: Record<string, unknown>): Promise<string[]> =>
|
|
29
|
+
(await validate(instancia(raw) as object)).map((e) => e.property);
|
|
30
|
+
|
|
31
|
+
describe('BiometricVerificationResponse', () => {
|
|
32
|
+
it('valida la respuesta mínima', async () => {
|
|
33
|
+
expect(await propiedadesConError(base)).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* El eco de contra qué foto se comparó. Acá sí entran los TRES valores: `CALLER_PROVIDED` es de
|
|
38
|
+
* salida y decir `KYC_SELFIE` cuando la foto la puso el caller sería mentir sobre la comparación.
|
|
39
|
+
*/
|
|
40
|
+
describe('referenceImageSource', () => {
|
|
41
|
+
it.each(['KYC_SELFIE', 'ID_DOCUMENT', 'CALLER_PROVIDED'])('acepta %s', async (fuente) => {
|
|
42
|
+
const dto = instancia({ ...base, referenceImageSource: fuente });
|
|
43
|
+
|
|
44
|
+
expect(await validate(dto as object)).toHaveLength(0);
|
|
45
|
+
expect(dto.referenceImageSource).toBe(fuente);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('rechaza la respuesta sin referenceImageSource: siempre viene poblado', async () => {
|
|
49
|
+
const { referenceImageSource: _omitido, ...sinFuente } = base;
|
|
50
|
+
|
|
51
|
+
expect(await propiedadesConError(sinFuente)).toContain('referenceImageSource');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('rechaza un valor fuera del enum', async () => {
|
|
55
|
+
expect(await propiedadesConError({ ...base, referenceImageSource: 'PROFILE_PICTURE' }))
|
|
56
|
+
.toContain('referenceImageSource');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('sobrevive al plainToInstance con excludeExtraneousValues (lleva @Expose)', () => {
|
|
60
|
+
expect(instancia(base).referenceImageSource).toBe(BiometricReferenceSourceEnum.KYC_SELFIE);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
CreateBiometricVerificationRequest,
|
|
6
6
|
BiometricProviderEnum,
|
|
7
7
|
BiometricTypeEnum,
|
|
8
|
+
BiometricReferenceSourceEnum,
|
|
8
9
|
} from '../../../src/biometrics/index';
|
|
9
10
|
|
|
10
11
|
/** El request mínimo válido: los 4 campos obligatorios. */
|
|
@@ -133,4 +134,60 @@ describe('CreateBiometricVerificationRequest', () => {
|
|
|
133
134
|
expect(instancia({ ...base, deliveryMode: 'EMBEDDED_SDK' }).deliveryMode).toBe('EMBEDDED_SDK');
|
|
134
135
|
});
|
|
135
136
|
});
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* `referenceImageSource` elige contra QUÉ foto se compara. Solo dos de los tres valores del enum
|
|
140
|
+
* son legales de entrada: `CALLER_PROVIDED` lo emite la respuesta, no lo pide el caller.
|
|
141
|
+
*/
|
|
142
|
+
describe('referenceImageSource', () => {
|
|
143
|
+
it('acepta ID_DOCUMENT', async () => {
|
|
144
|
+
const dto = instancia({ ...base, referenceImageSource: 'ID_DOCUMENT' });
|
|
145
|
+
|
|
146
|
+
expect(await validate(dto as object)).toHaveLength(0);
|
|
147
|
+
expect(dto.referenceImageSource).toBe(BiometricReferenceSourceEnum.ID_DOCUMENT);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('acepta KYC_SELFIE', async () => {
|
|
151
|
+
const dto = instancia({ ...base, referenceImageSource: 'KYC_SELFIE' });
|
|
152
|
+
|
|
153
|
+
expect(await validate(dto as object)).toHaveLength(0);
|
|
154
|
+
expect(dto.referenceImageSource).toBe(BiometricReferenceSourceEnum.KYC_SELFIE);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Llega ausente, no con el default puesto: el default lo aplica el manager. Poblarlo acá haría
|
|
159
|
+
* indistinguible el request que mandó la fuente del que solo mandó `referenceImageUrl`.
|
|
160
|
+
*/
|
|
161
|
+
it('es opcional y NO se autopobla con el default', async () => {
|
|
162
|
+
const dto = instancia(base);
|
|
163
|
+
|
|
164
|
+
expect(await validate(dto as object)).toHaveLength(0);
|
|
165
|
+
expect(dto.referenceImageSource).toBeUndefined();
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('RECHAZA CALLER_PROVIDED, que es solo de salida', async () => {
|
|
169
|
+
expect(await propiedadesConError({ ...base, referenceImageSource: 'CALLER_PROVIDED' }))
|
|
170
|
+
.toContain('referenceImageSource');
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('rechaza un valor que no está en el enum', async () => {
|
|
174
|
+
expect(await propiedadesConError({ ...base, referenceImageSource: 'PROFILE_PICTURE' }))
|
|
175
|
+
.toContain('referenceImageSource');
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
// El par tiene que pasar el DTO LIMPIO: quien rechaza el choque es el manager, con
|
|
180
|
+
// `422 CONFLICTING_REFERENCE_IMAGE`. Un validador cross-field acá le daria al caller un
|
|
181
|
+
// `400 VALIDATION_ERROR` generico en vez del codigo tipado que el front espera.
|
|
182
|
+
it('acepta referenceImageUrl y referenceImageSource juntos: el choque lo resuelve el manager', async () => {
|
|
183
|
+
const dto = instancia({
|
|
184
|
+
...base,
|
|
185
|
+
referenceImageUrl: 'https://cdn.tufiado.com/foto.jpg',
|
|
186
|
+
referenceImageSource: BiometricReferenceSourceEnum.ID_DOCUMENT,
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
expect(await validate(dto)).toHaveLength(0);
|
|
190
|
+
expect(dto.referenceImageUrl).toBe('https://cdn.tufiado.com/foto.jpg');
|
|
191
|
+
expect(dto.referenceImageSource).toBe(BiometricReferenceSourceEnum.ID_DOCUMENT);
|
|
192
|
+
});
|
|
136
193
|
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import { PeopleIdPhotoResponse } from '../../../src/identity/index';
|
|
5
|
+
|
|
6
|
+
const base = {
|
|
7
|
+
directoryId: '4cdc2e82-4bdc-4421-8c3a-c77dadea23b7',
|
|
8
|
+
url: 'https://s3.amazonaws.com/bucket/USER/dir/x_PASSPORT_FRONT.jpeg?X-Amz-Expires=900',
|
|
9
|
+
key: 'x_PASSPORT_FRONT.jpeg',
|
|
10
|
+
expiresInSeconds: 900,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const instancia = (raw: Record<string, unknown>): PeopleIdPhotoResponse =>
|
|
14
|
+
plainToInstance(PeopleIdPhotoResponse, raw, { excludeExtraneousValues: true });
|
|
15
|
+
|
|
16
|
+
describe('PeopleIdPhotoResponse', () => {
|
|
17
|
+
it('acepta la respuesta completa', async () => {
|
|
18
|
+
const dto = instancia(base);
|
|
19
|
+
expect(await validate(dto)).toHaveLength(0);
|
|
20
|
+
expect(dto.key).toBe('x_PASSPORT_FRONT.jpeg');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it.each(['directoryId', 'url', 'key', 'expiresInSeconds'])('exige %s', async (campo) => {
|
|
24
|
+
const { [campo]: _, ...sinCampo } = base as Record<string, unknown>;
|
|
25
|
+
const errores = await validate(instancia(sinCampo));
|
|
26
|
+
expect(errores.map((e) => e.property)).toContain(campo);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('rechaza una vigencia no positiva', async () => {
|
|
30
|
+
const errores = await validate(instancia({ ...base, expiresInSeconds: 0 }));
|
|
31
|
+
expect(errores.map((e) => e.property)).toContain('expiresInSeconds');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BiometricDeliveryModeEnum } from '../../enums/BiometricDeliveryModeEnum';
|
|
2
2
|
import { BiometricProviderEnum } from '../../enums/BiometricProviderEnum';
|
|
3
|
+
import { BiometricReferenceSourceEnum } from '../../enums/BiometricReferenceSourceEnum';
|
|
3
4
|
import { BiometricTypeEnum } from '../../enums/BiometricTypeEnum';
|
|
4
5
|
import { BiometricSubject } from '../BiometricSubject';
|
|
5
6
|
/**
|
|
@@ -56,6 +57,18 @@ export declare class CreateBiometricVerificationRequest {
|
|
|
56
57
|
* Úsalo solo si ya tienes la foto correcta a mano y quieres ahorrarte el round-trip.
|
|
57
58
|
*/
|
|
58
59
|
referenceImageUrl?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Contra QUÉ foto se compara. Default `KYC_SELFIE`, que aplica el servicio: acá viaja ausente
|
|
62
|
+
* cuando no lo mandas, para que se pueda distinguir de haberlo pedido explícitamente.
|
|
63
|
+
*
|
|
64
|
+
* **Sin fallback:** si la fuente pedida no tiene foto, responde `REFERENCE_PHOTO_UNAVAILABLE`;
|
|
65
|
+
* no se busca la otra. Quien pide contra el documento y recibe un match sabe que fue contra el
|
|
66
|
+
* documento.
|
|
67
|
+
*
|
|
68
|
+
* 🔴 `CALLER_PROVIDED` NO es válido acá — solo lo emite la respuesta. Y mandar esto junto con
|
|
69
|
+
* `referenceImageUrl` responde `422 CONFLICTING_REFERENCE_IMAGE`: son contradictorios.
|
|
70
|
+
*/
|
|
71
|
+
referenceImageSource?: BiometricReferenceSourceEnum.KYC_SELFIE | BiometricReferenceSourceEnum.ID_DOCUMENT;
|
|
59
72
|
/**
|
|
60
73
|
* Vigencia de la entrega, en segundos. Default 3600.
|
|
61
74
|
*
|
|
@@ -14,6 +14,7 @@ const class_transformer_1 = require("class-transformer");
|
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
15
|
const BiometricDeliveryModeEnum_1 = require("../../enums/BiometricDeliveryModeEnum");
|
|
16
16
|
const BiometricProviderEnum_1 = require("../../enums/BiometricProviderEnum");
|
|
17
|
+
const BiometricReferenceSourceEnum_1 = require("../../enums/BiometricReferenceSourceEnum");
|
|
17
18
|
const BiometricTypeEnum_1 = require("../../enums/BiometricTypeEnum");
|
|
18
19
|
const BiometricSubject_1 = require("../BiometricSubject");
|
|
19
20
|
/**
|
|
@@ -65,6 +66,12 @@ __decorate([
|
|
|
65
66
|
(0, class_validator_1.IsNotEmpty)(),
|
|
66
67
|
__metadata("design:type", String)
|
|
67
68
|
], CreateBiometricVerificationRequest.prototype, "referenceImageUrl", void 0);
|
|
69
|
+
__decorate([
|
|
70
|
+
(0, class_transformer_1.Expose)(),
|
|
71
|
+
(0, class_validator_1.IsOptional)(),
|
|
72
|
+
(0, class_validator_1.IsIn)([BiometricReferenceSourceEnum_1.BiometricReferenceSourceEnum.KYC_SELFIE, BiometricReferenceSourceEnum_1.BiometricReferenceSourceEnum.ID_DOCUMENT]),
|
|
73
|
+
__metadata("design:type", String)
|
|
74
|
+
], CreateBiometricVerificationRequest.prototype, "referenceImageSource", void 0);
|
|
68
75
|
__decorate([
|
|
69
76
|
(0, class_transformer_1.Expose)(),
|
|
70
77
|
(0, class_validator_1.IsOptional)(),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BiometricDeliveryModeEnum } from '../../enums/BiometricDeliveryModeEnum';
|
|
2
2
|
import { BiometricProviderEnum } from '../../enums/BiometricProviderEnum';
|
|
3
|
+
import { BiometricReferenceSourceEnum } from '../../enums/BiometricReferenceSourceEnum';
|
|
3
4
|
import { BiometricResultEnum } from '../../enums/BiometricResultEnum';
|
|
4
5
|
import { BiometricTypeEnum } from '../../enums/BiometricTypeEnum';
|
|
5
6
|
import { BiometricVerificationStatusEnum } from '../../enums/BiometricVerificationStatusEnum';
|
|
@@ -48,6 +49,14 @@ export declare class BiometricVerificationResponse {
|
|
|
48
49
|
* seguridad. El contrato lo garantiza el productor, que es un solo lambda.
|
|
49
50
|
*/
|
|
50
51
|
delivery: BiometricDelivery;
|
|
52
|
+
/**
|
|
53
|
+
* Contra qué foto se comparó. **Siempre poblado.**
|
|
54
|
+
*
|
|
55
|
+
* `CALLER_PROVIDED` significa que la foto la mandaste tú en `referenceImageUrl`. Es un valor
|
|
56
|
+
* distinto y no el default, porque decir `KYC_SELFIE` cuando la foto la pusiste tú sería mentir
|
|
57
|
+
* sobre contra qué se comparó — y eso es exactamente lo que este campo existe para evitar.
|
|
58
|
+
*/
|
|
59
|
+
referenceImageSource: BiometricReferenceSourceEnum;
|
|
51
60
|
/**
|
|
52
61
|
* Similitud reportada por el proveedor, 0–100, cuando la expone. Rekognition da score; Metamap
|
|
53
62
|
* responde pass/fail y esto viene ausente.
|
|
@@ -14,6 +14,7 @@ const class_transformer_1 = require("class-transformer");
|
|
|
14
14
|
const class_validator_1 = require("class-validator");
|
|
15
15
|
const BiometricDeliveryModeEnum_1 = require("../../enums/BiometricDeliveryModeEnum");
|
|
16
16
|
const BiometricProviderEnum_1 = require("../../enums/BiometricProviderEnum");
|
|
17
|
+
const BiometricReferenceSourceEnum_1 = require("../../enums/BiometricReferenceSourceEnum");
|
|
17
18
|
const BiometricResultEnum_1 = require("../../enums/BiometricResultEnum");
|
|
18
19
|
const BiometricTypeEnum_1 = require("../../enums/BiometricTypeEnum");
|
|
19
20
|
const BiometricVerificationStatusEnum_1 = require("../../enums/BiometricVerificationStatusEnum");
|
|
@@ -72,6 +73,11 @@ __decorate([
|
|
|
72
73
|
(0, class_transformer_1.Expose)(),
|
|
73
74
|
__metadata("design:type", Object)
|
|
74
75
|
], BiometricVerificationResponse.prototype, "delivery", void 0);
|
|
76
|
+
__decorate([
|
|
77
|
+
(0, class_transformer_1.Expose)(),
|
|
78
|
+
(0, class_validator_1.IsEnum)(BiometricReferenceSourceEnum_1.BiometricReferenceSourceEnum),
|
|
79
|
+
__metadata("design:type", String)
|
|
80
|
+
], BiometricVerificationResponse.prototype, "referenceImageSource", void 0);
|
|
75
81
|
__decorate([
|
|
76
82
|
(0, class_transformer_1.Expose)(),
|
|
77
83
|
(0, class_validator_1.IsOptional)(),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contra QUÉ foto compara el biométrico.
|
|
3
|
+
*
|
|
4
|
+
* `CALLER_PROVIDED` es SOLO DE SALIDA: lo emite la respuesta cuando el caller mandó su propia
|
|
5
|
+
* `referenceImageUrl`. El request lo rechaza — pedirlo no significa nada.
|
|
6
|
+
*/
|
|
7
|
+
export declare enum BiometricReferenceSourceEnum {
|
|
8
|
+
/** La selfie del KYC. El default. */
|
|
9
|
+
KYC_SELFIE = "KYC_SELFIE",
|
|
10
|
+
/** El frente de la identificación, resuelto por `fiado-identity-lambda`. */
|
|
11
|
+
ID_DOCUMENT = "ID_DOCUMENT",
|
|
12
|
+
/** Solo de salida: la foto la puso el caller en `referenceImageUrl`. */
|
|
13
|
+
CALLER_PROVIDED = "CALLER_PROVIDED"
|
|
14
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BiometricReferenceSourceEnum = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Contra QUÉ foto compara el biométrico.
|
|
6
|
+
*
|
|
7
|
+
* `CALLER_PROVIDED` es SOLO DE SALIDA: lo emite la respuesta cuando el caller mandó su propia
|
|
8
|
+
* `referenceImageUrl`. El request lo rechaza — pedirlo no significa nada.
|
|
9
|
+
*/
|
|
10
|
+
var BiometricReferenceSourceEnum;
|
|
11
|
+
(function (BiometricReferenceSourceEnum) {
|
|
12
|
+
/** La selfie del KYC. El default. */
|
|
13
|
+
BiometricReferenceSourceEnum["KYC_SELFIE"] = "KYC_SELFIE";
|
|
14
|
+
/** El frente de la identificación, resuelto por `fiado-identity-lambda`. */
|
|
15
|
+
BiometricReferenceSourceEnum["ID_DOCUMENT"] = "ID_DOCUMENT";
|
|
16
|
+
/** Solo de salida: la foto la puso el caller en `referenceImageUrl`. */
|
|
17
|
+
BiometricReferenceSourceEnum["CALLER_PROVIDED"] = "CALLER_PROVIDED";
|
|
18
|
+
})(BiometricReferenceSourceEnum || (exports.BiometricReferenceSourceEnum = BiometricReferenceSourceEnum = {}));
|
|
@@ -4,20 +4,15 @@ import { BiometricResultEnum } from '../enums/BiometricResultEnum';
|
|
|
4
4
|
/**
|
|
5
5
|
* Lo que le pasó a una verificación biométrica, según el proveedor.
|
|
6
6
|
*
|
|
7
|
-
* **El recorrido:** Metamap → `kyc-metamap-webhook
|
|
8
|
-
*
|
|
7
|
+
* **El recorrido:** Metamap → `kyc-metamap-webhook`, que valida la firma HMAC y traduce → llamada
|
|
8
|
+
* HTTP síncrona a `biometrics-business`, que aplica la transición.
|
|
9
9
|
*
|
|
10
|
-
* **
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* traga el evento en silencio y la verificación queda `IN_PROGRESS` para siempre, con el caller
|
|
14
|
-
* poleando al vacío y sin alarma. La cola da durabilidad, DLQ y alarma sin tocar esa disciplina.
|
|
10
|
+
* 🔴 **No se loguea entero:**
|
|
11
|
+
* loguea los campos que necesites, nunca el objeto. El resto son identificadores operacionales y el
|
|
12
|
+
* veredicto.
|
|
15
13
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* partiría sus KYC a la mitad, en producción, al azar y sin un solo error en los logs.
|
|
19
|
-
*
|
|
20
|
-
* 🔴 **Sin PII.** Solo identificadores operacionales y el veredicto.
|
|
14
|
+
* Los duplicados son la norma —Metamap reintenta el webhook completo ante cualquier fallo—, así que
|
|
15
|
+
* el consumer deduplica por `eventId` y ordena por `occurredAt`.
|
|
21
16
|
*
|
|
22
17
|
* `biometrics-business` — Entrega 1.
|
|
23
18
|
*/
|
|
@@ -30,15 +25,12 @@ export declare class BiometricVerificationChangedV1 {
|
|
|
30
25
|
/**
|
|
31
26
|
* 🔴 **Identificador ÚNICO de este evento. La clave de deduplicación.**
|
|
32
27
|
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
28
|
+
* La entrega es *at-least-once*: Metamap reintenta el webhook completo, así que los duplicados
|
|
29
|
+
* son la norma, no la excepción. Y **el candado temporal por `occurredAt` NO alcanza para
|
|
30
|
+
* esto**: dos entregas del mismo evento traen exactamente el mismo `occurredAt`, así que una
|
|
31
|
+
* regla "descartar si es más viejo" las deja pasar a las dos.
|
|
36
32
|
*
|
|
37
33
|
* El consumer guarda los `eventId` ya aplicados y descarta los repetidos.
|
|
38
|
-
*
|
|
39
|
-
* ⚠️ **No deduplicar por el `MessageId` de SQS**: cambia en cada reintento de entrega, así que
|
|
40
|
-
* no deduplica nada. Es el error clásico y por eso queda escrito acá y no en la cabeza de cada
|
|
41
|
-
* consumidor.
|
|
42
34
|
*/
|
|
43
35
|
eventId: string;
|
|
44
36
|
/**
|
|
@@ -73,7 +65,7 @@ export declare class BiometricVerificationChangedV1 {
|
|
|
73
65
|
* el evento real, y la transición no se aplicaría nunca — sin un solo error.
|
|
74
66
|
*
|
|
75
67
|
* Normalizar a UTC es trabajo del traductor del proveedor (`kyc-metamap-webhook`). Este candado
|
|
76
|
-
* existe para que si algún día deja de hacerlo, el
|
|
68
|
+
* existe para que si algún día deja de hacerlo, el evento se rechace en el boundary en vez de
|
|
77
69
|
* corromper el orden en silencio.
|
|
78
70
|
*/
|
|
79
71
|
occurredAt: string;
|
|
@@ -18,20 +18,15 @@ const BiometricResultEnum_1 = require("../enums/BiometricResultEnum");
|
|
|
18
18
|
/**
|
|
19
19
|
* Lo que le pasó a una verificación biométrica, según el proveedor.
|
|
20
20
|
*
|
|
21
|
-
* **El recorrido:** Metamap → `kyc-metamap-webhook
|
|
22
|
-
*
|
|
21
|
+
* **El recorrido:** Metamap → `kyc-metamap-webhook`, que valida la firma HMAC y traduce → llamada
|
|
22
|
+
* HTTP síncrona a `biometrics-business`, que aplica la transición.
|
|
23
23
|
*
|
|
24
|
-
* **
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* traga el evento en silencio y la verificación queda `IN_PROGRESS` para siempre, con el caller
|
|
28
|
-
* poleando al vacío y sin alarma. La cola da durabilidad, DLQ y alarma sin tocar esa disciplina.
|
|
24
|
+
* 🔴 **No se loguea entero:**
|
|
25
|
+
* loguea los campos que necesites, nunca el objeto. El resto son identificadores operacionales y el
|
|
26
|
+
* veredicto.
|
|
29
27
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* partiría sus KYC a la mitad, en producción, al azar y sin un solo error en los logs.
|
|
33
|
-
*
|
|
34
|
-
* 🔴 **Sin PII.** Solo identificadores operacionales y el veredicto.
|
|
28
|
+
* Los duplicados son la norma —Metamap reintenta el webhook completo ante cualquier fallo—, así que
|
|
29
|
+
* el consumer deduplica por `eventId` y ordena por `occurredAt`.
|
|
35
30
|
*
|
|
36
31
|
* `biometrics-business` — Entrega 1.
|
|
37
32
|
*/
|
|
@@ -4,6 +4,7 @@ export * from './enums/BiometricDeliveryModeEnum';
|
|
|
4
4
|
export * from './enums/BiometricVerificationStatusEnum';
|
|
5
5
|
export * from './enums/BiometricResultEnum';
|
|
6
6
|
export * from './enums/BiometricEventTypeEnum';
|
|
7
|
+
export * from './enums/BiometricReferenceSourceEnum';
|
|
7
8
|
export * from './dtos/BiometricSubject';
|
|
8
9
|
export * from './dtos/BiometricDelivery';
|
|
9
10
|
export * from './dtos/requests/CreateBiometricVerificationRequest';
|
package/bin/biometrics/index.js
CHANGED
|
@@ -24,6 +24,7 @@ __exportStar(require("./enums/BiometricDeliveryModeEnum"), exports);
|
|
|
24
24
|
__exportStar(require("./enums/BiometricVerificationStatusEnum"), exports);
|
|
25
25
|
__exportStar(require("./enums/BiometricResultEnum"), exports);
|
|
26
26
|
__exportStar(require("./enums/BiometricEventTypeEnum"), exports);
|
|
27
|
+
__exportStar(require("./enums/BiometricReferenceSourceEnum"), exports);
|
|
27
28
|
// DTOs compartidos
|
|
28
29
|
__exportStar(require("./dtos/BiometricSubject"), exports);
|
|
29
30
|
__exportStar(require("./dtos/BiometricDelivery"), exports);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Respuesta del endpoint privado que devuelve el FRENTE de la identificación de un usuario:
|
|
3
|
+
* el URL presignado de S3 + su vigencia. Gemelo de `PeopleSelfieResponse`.
|
|
4
|
+
*
|
|
5
|
+
* Es la otra fuente posible del `userPhotoLink` del facematch. Se declara aparte y no se reusa
|
|
6
|
+
* `PeopleSelfieResponse` porque son dos endpoints distintos: compartir el tipo haría que un cambio
|
|
7
|
+
* en uno arrastrara al otro sin que nadie lo decida.
|
|
8
|
+
*/
|
|
9
|
+
export declare class PeopleIdPhotoResponse {
|
|
10
|
+
directoryId: string;
|
|
11
|
+
/** URL presignado de S3 del frente del documento. */
|
|
12
|
+
url: string;
|
|
13
|
+
/** Nombre del archivo en S3, sin el prefijo `USER/{directoryId}/`. */
|
|
14
|
+
key: string;
|
|
15
|
+
/** Vigencia del presigned URL en segundos. */
|
|
16
|
+
expiresInSeconds: number;
|
|
17
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
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.PeopleIdPhotoResponse = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/**
|
|
16
|
+
* Respuesta del endpoint privado que devuelve el FRENTE de la identificación de un usuario:
|
|
17
|
+
* el URL presignado de S3 + su vigencia. Gemelo de `PeopleSelfieResponse`.
|
|
18
|
+
*
|
|
19
|
+
* Es la otra fuente posible del `userPhotoLink` del facematch. Se declara aparte y no se reusa
|
|
20
|
+
* `PeopleSelfieResponse` porque son dos endpoints distintos: compartir el tipo haría que un cambio
|
|
21
|
+
* en uno arrastrara al otro sin que nadie lo decida.
|
|
22
|
+
*/
|
|
23
|
+
class PeopleIdPhotoResponse {
|
|
24
|
+
}
|
|
25
|
+
exports.PeopleIdPhotoResponse = PeopleIdPhotoResponse;
|
|
26
|
+
__decorate([
|
|
27
|
+
(0, class_transformer_1.Expose)(),
|
|
28
|
+
(0, class_validator_1.IsString)(),
|
|
29
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
30
|
+
__metadata("design:type", String)
|
|
31
|
+
], PeopleIdPhotoResponse.prototype, "directoryId", void 0);
|
|
32
|
+
__decorate([
|
|
33
|
+
(0, class_transformer_1.Expose)(),
|
|
34
|
+
(0, class_validator_1.IsString)(),
|
|
35
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
36
|
+
__metadata("design:type", String)
|
|
37
|
+
], PeopleIdPhotoResponse.prototype, "url", void 0);
|
|
38
|
+
__decorate([
|
|
39
|
+
(0, class_transformer_1.Expose)(),
|
|
40
|
+
(0, class_validator_1.IsString)(),
|
|
41
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
42
|
+
__metadata("design:type", String)
|
|
43
|
+
], PeopleIdPhotoResponse.prototype, "key", void 0);
|
|
44
|
+
__decorate([
|
|
45
|
+
(0, class_transformer_1.Expose)(),
|
|
46
|
+
(0, class_validator_1.IsInt)(),
|
|
47
|
+
(0, class_validator_1.IsPositive)(),
|
|
48
|
+
__metadata("design:type", Number)
|
|
49
|
+
], PeopleIdPhotoResponse.prototype, "expiresInSeconds", void 0);
|
package/bin/identity/index.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './dtos/PeopleSelfVerifiedRequest';
|
|
|
12
12
|
export * from './dtos/AgentDocumentKeyResponse';
|
|
13
13
|
export * from './dtos/DocumentUploadResponse';
|
|
14
14
|
export * from './dtos/PeopleSelfieResponse';
|
|
15
|
+
export * from './dtos/PeopleIdPhotoResponse';
|
|
15
16
|
export * from './enums/IdentificationDocumentStatus';
|
|
16
17
|
export * from './enums/SexDocument';
|
|
17
18
|
export * from './enums/InfoSelfVerifiedStatus';
|
package/bin/identity/index.js
CHANGED
|
@@ -29,6 +29,7 @@ __exportStar(require("./dtos/PeopleSelfVerifiedRequest"), exports);
|
|
|
29
29
|
__exportStar(require("./dtos/AgentDocumentKeyResponse"), exports);
|
|
30
30
|
__exportStar(require("./dtos/DocumentUploadResponse"), exports);
|
|
31
31
|
__exportStar(require("./dtos/PeopleSelfieResponse"), exports);
|
|
32
|
+
__exportStar(require("./dtos/PeopleIdPhotoResponse"), exports);
|
|
32
33
|
//enums
|
|
33
34
|
__exportStar(require("./enums/IdentificationDocumentStatus"), exports);
|
|
34
35
|
__exportStar(require("./enums/SexDocument"), exports);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH = void 0;
|
|
4
|
+
/** Largo máximo del actor y de la referencia de pago de los dos hooks de cobranza del crédito. */
|
|
5
|
+
exports.CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH = 120;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Body de `POST /private/credits/:creditId/payment-applied` (loan-credit-business). Es OPCIONAL:
|
|
3
|
+
* sin él el pago se atribuye al sistema. `paymentReference` es sólo trazabilidad — no decide nada.
|
|
4
|
+
*/
|
|
5
|
+
export declare class CreditPaymentAppliedRequest {
|
|
6
|
+
/** Quién aplicó el pago; queda en la bitácora del expediente. */
|
|
7
|
+
actor?: string;
|
|
8
|
+
/** Referencia del pago en el sistema que lo aplicó. Sólo trazabilidad. */
|
|
9
|
+
paymentReference?: string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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.CreditPaymentAppliedRequest = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const creditPaymentHook_1 = require("../../constants/creditPaymentHook");
|
|
16
|
+
/**
|
|
17
|
+
* Body de `POST /private/credits/:creditId/payment-applied` (loan-credit-business). Es OPCIONAL:
|
|
18
|
+
* sin él el pago se atribuye al sistema. `paymentReference` es sólo trazabilidad — no decide nada.
|
|
19
|
+
*/
|
|
20
|
+
class CreditPaymentAppliedRequest {
|
|
21
|
+
}
|
|
22
|
+
exports.CreditPaymentAppliedRequest = CreditPaymentAppliedRequest;
|
|
23
|
+
__decorate([
|
|
24
|
+
(0, class_transformer_1.Expose)(),
|
|
25
|
+
(0, class_validator_1.IsOptional)(),
|
|
26
|
+
(0, class_validator_1.IsString)(),
|
|
27
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
28
|
+
(0, class_validator_1.MaxLength)(creditPaymentHook_1.CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH),
|
|
29
|
+
__metadata("design:type", String)
|
|
30
|
+
], CreditPaymentAppliedRequest.prototype, "actor", void 0);
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, class_transformer_1.Expose)(),
|
|
33
|
+
(0, class_validator_1.IsOptional)(),
|
|
34
|
+
(0, class_validator_1.IsString)(),
|
|
35
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
36
|
+
(0, class_validator_1.MaxLength)(creditPaymentHook_1.CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH),
|
|
37
|
+
__metadata("design:type", String)
|
|
38
|
+
], CreditPaymentAppliedRequest.prototype, "paymentReference", void 0);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Body de `POST /private/credits/:creditId/settled` (loan-credit-business). También opcional.
|
|
3
|
+
* La ruta VERIFICA que el crédito no deba nada: no le cree al caller.
|
|
4
|
+
*/
|
|
5
|
+
export declare class CreditSettledRequest {
|
|
6
|
+
/** Quién declaró la liquidación; queda en la bitácora del expediente. */
|
|
7
|
+
actor?: string;
|
|
8
|
+
/** Referencia del pago que liquidó. Sólo trazabilidad. */
|
|
9
|
+
paymentReference?: string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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.CreditSettledRequest = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const creditPaymentHook_1 = require("../../constants/creditPaymentHook");
|
|
16
|
+
/**
|
|
17
|
+
* Body de `POST /private/credits/:creditId/settled` (loan-credit-business). También opcional.
|
|
18
|
+
* La ruta VERIFICA que el crédito no deba nada: no le cree al caller.
|
|
19
|
+
*/
|
|
20
|
+
class CreditSettledRequest {
|
|
21
|
+
}
|
|
22
|
+
exports.CreditSettledRequest = CreditSettledRequest;
|
|
23
|
+
__decorate([
|
|
24
|
+
(0, class_transformer_1.Expose)(),
|
|
25
|
+
(0, class_validator_1.IsOptional)(),
|
|
26
|
+
(0, class_validator_1.IsString)(),
|
|
27
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
28
|
+
(0, class_validator_1.MaxLength)(creditPaymentHook_1.CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH),
|
|
29
|
+
__metadata("design:type", String)
|
|
30
|
+
], CreditSettledRequest.prototype, "actor", void 0);
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, class_transformer_1.Expose)(),
|
|
33
|
+
(0, class_validator_1.IsOptional)(),
|
|
34
|
+
(0, class_validator_1.IsString)(),
|
|
35
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
36
|
+
(0, class_validator_1.MaxLength)(creditPaymentHook_1.CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH),
|
|
37
|
+
__metadata("design:type", String)
|
|
38
|
+
], CreditSettledRequest.prototype, "paymentReference", void 0);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CreditPaymentUnlockDecisionEnum } from '../../enums/CreditPaymentUnlockDecisionEnum';
|
|
2
|
+
/** Resultado de aplicar un pago: el crédito sale de mora y el equipo se suelta si corresponde. */
|
|
3
|
+
export interface CreditPaymentAppliedResponse {
|
|
4
|
+
creditId: string;
|
|
5
|
+
/** El crédito salió de mora. Pasa aunque no haya equipo, esté sin candado, o sea SCHEDULED. */
|
|
6
|
+
creditReactivated: boolean;
|
|
7
|
+
unlockDecision: CreditPaymentUnlockDecisionEnum;
|
|
8
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { CreditSettlementDecisionEnum } from '../../enums/CreditSettlementDecisionEnum';
|
|
2
|
+
import { CreditSettlementReleaseDecisionEnum } from '../../enums/CreditSettlementReleaseDecisionEnum';
|
|
3
|
+
/** Resultado de liquidar el crédito; `releaseDecision` es null si el equipo no salió al proveedor. */
|
|
4
|
+
export interface CreditSettledResponse {
|
|
5
|
+
creditId: string;
|
|
6
|
+
settlementDecision: CreditSettlementDecisionEnum;
|
|
7
|
+
releaseDecision: CreditSettlementReleaseDecisionEnum | null;
|
|
8
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qué pasó con el equipo cuando se aplicó un pago al crédito.
|
|
3
|
+
* @enum {string}
|
|
4
|
+
*/
|
|
5
|
+
export declare enum CreditPaymentUnlockDecisionEnum {
|
|
6
|
+
CREDIT_NOT_FOUND = "CREDIT_NOT_FOUND",
|
|
7
|
+
/** El crédito no está en un estado al que el pago le suelte el equipo. */
|
|
8
|
+
CREDIT_NOT_UNLOCKABLE = "CREDIT_NOT_UNLOCKABLE",
|
|
9
|
+
NOT_ENROLLED = "NOT_ENROLLED",
|
|
10
|
+
/** El equipo no estaba bloqueado: no hay nada que soltar. */
|
|
11
|
+
NOT_LOCKED = "NOT_LOCKED",
|
|
12
|
+
/** El candado no es el de la mora (fraude, manual, o sin motivo): un pago no lo suelta. */
|
|
13
|
+
LOCKED_FOR_OTHER_REASON = "LOCKED_FOR_OTHER_REASON",
|
|
14
|
+
/** El pago no alcanzó el umbral escalonado: sigue bloqueado y no se reprograma nada. */
|
|
15
|
+
THRESHOLD_NOT_MET = "THRESHOLD_NOT_MET",
|
|
16
|
+
UNLOCKED = "UNLOCKED",
|
|
17
|
+
/** El proveedor aceptó la orden y todavía no la dio por hecha. */
|
|
18
|
+
UNLOCK_PENDING = "UNLOCK_PENDING",
|
|
19
|
+
UNLOCK_FAILED = "UNLOCK_FAILED"
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CreditPaymentUnlockDecisionEnum = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Qué pasó con el equipo cuando se aplicó un pago al crédito.
|
|
6
|
+
* @enum {string}
|
|
7
|
+
*/
|
|
8
|
+
var CreditPaymentUnlockDecisionEnum;
|
|
9
|
+
(function (CreditPaymentUnlockDecisionEnum) {
|
|
10
|
+
CreditPaymentUnlockDecisionEnum["CREDIT_NOT_FOUND"] = "CREDIT_NOT_FOUND";
|
|
11
|
+
/** El crédito no está en un estado al que el pago le suelte el equipo. */
|
|
12
|
+
CreditPaymentUnlockDecisionEnum["CREDIT_NOT_UNLOCKABLE"] = "CREDIT_NOT_UNLOCKABLE";
|
|
13
|
+
CreditPaymentUnlockDecisionEnum["NOT_ENROLLED"] = "NOT_ENROLLED";
|
|
14
|
+
/** El equipo no estaba bloqueado: no hay nada que soltar. */
|
|
15
|
+
CreditPaymentUnlockDecisionEnum["NOT_LOCKED"] = "NOT_LOCKED";
|
|
16
|
+
/** El candado no es el de la mora (fraude, manual, o sin motivo): un pago no lo suelta. */
|
|
17
|
+
CreditPaymentUnlockDecisionEnum["LOCKED_FOR_OTHER_REASON"] = "LOCKED_FOR_OTHER_REASON";
|
|
18
|
+
/** El pago no alcanzó el umbral escalonado: sigue bloqueado y no se reprograma nada. */
|
|
19
|
+
CreditPaymentUnlockDecisionEnum["THRESHOLD_NOT_MET"] = "THRESHOLD_NOT_MET";
|
|
20
|
+
CreditPaymentUnlockDecisionEnum["UNLOCKED"] = "UNLOCKED";
|
|
21
|
+
/** El proveedor aceptó la orden y todavía no la dio por hecha. */
|
|
22
|
+
CreditPaymentUnlockDecisionEnum["UNLOCK_PENDING"] = "UNLOCK_PENDING";
|
|
23
|
+
CreditPaymentUnlockDecisionEnum["UNLOCK_FAILED"] = "UNLOCK_FAILED";
|
|
24
|
+
})(CreditPaymentUnlockDecisionEnum || (exports.CreditPaymentUnlockDecisionEnum = CreditPaymentUnlockDecisionEnum = {}));
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qué pasó al intentar dejar el crédito liquidado. La ruta VERIFICA el saldo, no cree al caller.
|
|
3
|
+
* @enum {string}
|
|
4
|
+
*/
|
|
5
|
+
export declare enum CreditSettlementDecisionEnum {
|
|
6
|
+
CREDIT_NOT_FOUND = "CREDIT_NOT_FOUND",
|
|
7
|
+
/** Ya estaba liquidado: la ruta es idempotente y la liberación corre igual. */
|
|
8
|
+
ALREADY_SETTLED = "ALREADY_SETTLED",
|
|
9
|
+
/** El estado del crédito no admite liquidación (sólo ACTIVE e IN_ARREARS la admiten). */
|
|
10
|
+
CREDIT_NOT_SETTLEABLE = "CREDIT_NOT_SETTLEABLE",
|
|
11
|
+
/** Sin plan de cuotas no hay evidencia de que deba cero; fail-closed. */
|
|
12
|
+
NO_INSTALLMENTS = "NO_INSTALLMENTS",
|
|
13
|
+
/** Al plan le falta alguna cuota del plazo: la deuda que no se persistió no se puede saldar. */
|
|
14
|
+
INCOMPLETE_PLAN = "INCOMPLETE_PLAN",
|
|
15
|
+
/** Alguna cuota sigue debiendo: liquidar acá liberaría un equipo con deuda viva. */
|
|
16
|
+
BALANCE_OUTSTANDING = "BALANCE_OUTSTANDING",
|
|
17
|
+
SETTLED = "SETTLED",
|
|
18
|
+
/** Otro movió el estado entre la lectura y la escritura; el caller relee y reintenta. */
|
|
19
|
+
SETTLE_CONFLICT = "SETTLE_CONFLICT",
|
|
20
|
+
SETTLE_FAILED = "SETTLE_FAILED"
|
|
21
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CreditSettlementDecisionEnum = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Qué pasó al intentar dejar el crédito liquidado. La ruta VERIFICA el saldo, no cree al caller.
|
|
6
|
+
* @enum {string}
|
|
7
|
+
*/
|
|
8
|
+
var CreditSettlementDecisionEnum;
|
|
9
|
+
(function (CreditSettlementDecisionEnum) {
|
|
10
|
+
CreditSettlementDecisionEnum["CREDIT_NOT_FOUND"] = "CREDIT_NOT_FOUND";
|
|
11
|
+
/** Ya estaba liquidado: la ruta es idempotente y la liberación corre igual. */
|
|
12
|
+
CreditSettlementDecisionEnum["ALREADY_SETTLED"] = "ALREADY_SETTLED";
|
|
13
|
+
/** El estado del crédito no admite liquidación (sólo ACTIVE e IN_ARREARS la admiten). */
|
|
14
|
+
CreditSettlementDecisionEnum["CREDIT_NOT_SETTLEABLE"] = "CREDIT_NOT_SETTLEABLE";
|
|
15
|
+
/** Sin plan de cuotas no hay evidencia de que deba cero; fail-closed. */
|
|
16
|
+
CreditSettlementDecisionEnum["NO_INSTALLMENTS"] = "NO_INSTALLMENTS";
|
|
17
|
+
/** Al plan le falta alguna cuota del plazo: la deuda que no se persistió no se puede saldar. */
|
|
18
|
+
CreditSettlementDecisionEnum["INCOMPLETE_PLAN"] = "INCOMPLETE_PLAN";
|
|
19
|
+
/** Alguna cuota sigue debiendo: liquidar acá liberaría un equipo con deuda viva. */
|
|
20
|
+
CreditSettlementDecisionEnum["BALANCE_OUTSTANDING"] = "BALANCE_OUTSTANDING";
|
|
21
|
+
CreditSettlementDecisionEnum["SETTLED"] = "SETTLED";
|
|
22
|
+
/** Otro movió el estado entre la lectura y la escritura; el caller relee y reintenta. */
|
|
23
|
+
CreditSettlementDecisionEnum["SETTLE_CONFLICT"] = "SETTLE_CONFLICT";
|
|
24
|
+
CreditSettlementDecisionEnum["SETTLE_FAILED"] = "SETTLE_FAILED";
|
|
25
|
+
})(CreditSettlementDecisionEnum || (exports.CreditSettlementDecisionEnum = CreditSettlementDecisionEnum = {}));
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qué pasó con el equipo al liquidarse el crédito. El verbo es Release, terminal: el equipo SALE
|
|
3
|
+
* del enrolamiento, no se queda desbloqueado.
|
|
4
|
+
* @enum {string}
|
|
5
|
+
*/
|
|
6
|
+
export declare enum CreditSettlementReleaseDecisionEnum {
|
|
7
|
+
CREDIT_NOT_FOUND = "CREDIT_NOT_FOUND",
|
|
8
|
+
/** El crédito no está liquidado: liberar el equipo sería irreversible y prematuro. */
|
|
9
|
+
CREDIT_NOT_SETTLED = "CREDIT_NOT_SETTLED",
|
|
10
|
+
NOT_ENROLLED = "NOT_ENROLLED",
|
|
11
|
+
/** El expediente ya salió del MDM; la liberación es idempotente y no vuelve a salir. */
|
|
12
|
+
ALREADY_RELEASED = "ALREADY_RELEASED",
|
|
13
|
+
RELEASED = "RELEASED",
|
|
14
|
+
/** El proveedor aceptó la liberación y todavía no la dio por hecha. */
|
|
15
|
+
RELEASE_PENDING = "RELEASE_PENDING",
|
|
16
|
+
RELEASE_FAILED = "RELEASE_FAILED"
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CreditSettlementReleaseDecisionEnum = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Qué pasó con el equipo al liquidarse el crédito. El verbo es Release, terminal: el equipo SALE
|
|
6
|
+
* del enrolamiento, no se queda desbloqueado.
|
|
7
|
+
* @enum {string}
|
|
8
|
+
*/
|
|
9
|
+
var CreditSettlementReleaseDecisionEnum;
|
|
10
|
+
(function (CreditSettlementReleaseDecisionEnum) {
|
|
11
|
+
CreditSettlementReleaseDecisionEnum["CREDIT_NOT_FOUND"] = "CREDIT_NOT_FOUND";
|
|
12
|
+
/** El crédito no está liquidado: liberar el equipo sería irreversible y prematuro. */
|
|
13
|
+
CreditSettlementReleaseDecisionEnum["CREDIT_NOT_SETTLED"] = "CREDIT_NOT_SETTLED";
|
|
14
|
+
CreditSettlementReleaseDecisionEnum["NOT_ENROLLED"] = "NOT_ENROLLED";
|
|
15
|
+
/** El expediente ya salió del MDM; la liberación es idempotente y no vuelve a salir. */
|
|
16
|
+
CreditSettlementReleaseDecisionEnum["ALREADY_RELEASED"] = "ALREADY_RELEASED";
|
|
17
|
+
CreditSettlementReleaseDecisionEnum["RELEASED"] = "RELEASED";
|
|
18
|
+
/** El proveedor aceptó la liberación y todavía no la dio por hecha. */
|
|
19
|
+
CreditSettlementReleaseDecisionEnum["RELEASE_PENDING"] = "RELEASE_PENDING";
|
|
20
|
+
CreditSettlementReleaseDecisionEnum["RELEASE_FAILED"] = "RELEASE_FAILED";
|
|
21
|
+
})(CreditSettlementReleaseDecisionEnum || (exports.CreditSettlementReleaseDecisionEnum = CreditSettlementReleaseDecisionEnum = {}));
|
|
@@ -17,6 +17,14 @@ export * from './dtos/requests/OriginateLoanCreditRequest';
|
|
|
17
17
|
export * from './dtos/requests/QuoteLoanCreditRequest';
|
|
18
18
|
export * from './dtos/requests/SignLoanCreditRequest';
|
|
19
19
|
export * from './dtos/requests/ActivationCheckRequest';
|
|
20
|
+
export * from './dtos/requests/CreditPaymentAppliedRequest';
|
|
21
|
+
export * from './dtos/requests/CreditSettledRequest';
|
|
22
|
+
export * from './dtos/responses/CreditPaymentAppliedResponse';
|
|
23
|
+
export * from './dtos/responses/CreditSettledResponse';
|
|
24
|
+
export * from './enums/CreditPaymentUnlockDecisionEnum';
|
|
25
|
+
export * from './enums/CreditSettlementDecisionEnum';
|
|
26
|
+
export * from './enums/CreditSettlementReleaseDecisionEnum';
|
|
27
|
+
export * from './constants/creditPaymentHook';
|
|
20
28
|
export * from './dtos/requests/ChangeLoanCreditStatusRequest';
|
|
21
29
|
export * from './dtos/responses/LoanBorrowerResponse';
|
|
22
30
|
export * from './dtos/responses/LoanCreditResponse';
|
package/bin/loanCredit/index.js
CHANGED
|
@@ -39,6 +39,14 @@ __exportStar(require("./dtos/requests/OriginateLoanCreditRequest"), exports);
|
|
|
39
39
|
__exportStar(require("./dtos/requests/QuoteLoanCreditRequest"), exports);
|
|
40
40
|
__exportStar(require("./dtos/requests/SignLoanCreditRequest"), exports);
|
|
41
41
|
__exportStar(require("./dtos/requests/ActivationCheckRequest"), exports);
|
|
42
|
+
__exportStar(require("./dtos/requests/CreditPaymentAppliedRequest"), exports);
|
|
43
|
+
__exportStar(require("./dtos/requests/CreditSettledRequest"), exports);
|
|
44
|
+
__exportStar(require("./dtos/responses/CreditPaymentAppliedResponse"), exports);
|
|
45
|
+
__exportStar(require("./dtos/responses/CreditSettledResponse"), exports);
|
|
46
|
+
__exportStar(require("./enums/CreditPaymentUnlockDecisionEnum"), exports);
|
|
47
|
+
__exportStar(require("./enums/CreditSettlementDecisionEnum"), exports);
|
|
48
|
+
__exportStar(require("./enums/CreditSettlementReleaseDecisionEnum"), exports);
|
|
49
|
+
__exportStar(require("./constants/creditPaymentHook"), exports);
|
|
42
50
|
__exportStar(require("./dtos/requests/ChangeLoanCreditStatusRequest"), exports);
|
|
43
51
|
// Response DTOs
|
|
44
52
|
__exportStar(require("./dtos/responses/LoanBorrowerResponse"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Expose, Type } from 'class-transformer';
|
|
2
2
|
import {
|
|
3
3
|
IsEnum,
|
|
4
|
+
IsIn,
|
|
4
5
|
IsInt,
|
|
5
6
|
IsNotEmpty,
|
|
6
7
|
IsOptional,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
} from 'class-validator';
|
|
13
14
|
import { BiometricDeliveryModeEnum } from '../../enums/BiometricDeliveryModeEnum';
|
|
14
15
|
import { BiometricProviderEnum } from '../../enums/BiometricProviderEnum';
|
|
16
|
+
import { BiometricReferenceSourceEnum } from '../../enums/BiometricReferenceSourceEnum';
|
|
15
17
|
import { BiometricTypeEnum } from '../../enums/BiometricTypeEnum';
|
|
16
18
|
import { BiometricSubject } from '../BiometricSubject';
|
|
17
19
|
|
|
@@ -81,6 +83,24 @@ export class CreateBiometricVerificationRequest {
|
|
|
81
83
|
@Expose() @IsOptional() @IsString() @IsNotEmpty()
|
|
82
84
|
referenceImageUrl?: string;
|
|
83
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Contra QUÉ foto se compara. Default `KYC_SELFIE`, que aplica el servicio: acá viaja ausente
|
|
88
|
+
* cuando no lo mandas, para que se pueda distinguir de haberlo pedido explícitamente.
|
|
89
|
+
*
|
|
90
|
+
* **Sin fallback:** si la fuente pedida no tiene foto, responde `REFERENCE_PHOTO_UNAVAILABLE`;
|
|
91
|
+
* no se busca la otra. Quien pide contra el documento y recibe un match sabe que fue contra el
|
|
92
|
+
* documento.
|
|
93
|
+
*
|
|
94
|
+
* 🔴 `CALLER_PROVIDED` NO es válido acá — solo lo emite la respuesta. Y mandar esto junto con
|
|
95
|
+
* `referenceImageUrl` responde `422 CONFLICTING_REFERENCE_IMAGE`: son contradictorios.
|
|
96
|
+
*/
|
|
97
|
+
@Expose()
|
|
98
|
+
@IsOptional()
|
|
99
|
+
@IsIn([BiometricReferenceSourceEnum.KYC_SELFIE, BiometricReferenceSourceEnum.ID_DOCUMENT])
|
|
100
|
+
referenceImageSource?:
|
|
101
|
+
| BiometricReferenceSourceEnum.KYC_SELFIE
|
|
102
|
+
| BiometricReferenceSourceEnum.ID_DOCUMENT;
|
|
103
|
+
|
|
84
104
|
/**
|
|
85
105
|
* Vigencia de la entrega, en segundos. Default 3600.
|
|
86
106
|
*
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from 'class-validator';
|
|
13
13
|
import { BiometricDeliveryModeEnum } from '../../enums/BiometricDeliveryModeEnum';
|
|
14
14
|
import { BiometricProviderEnum } from '../../enums/BiometricProviderEnum';
|
|
15
|
+
import { BiometricReferenceSourceEnum } from '../../enums/BiometricReferenceSourceEnum';
|
|
15
16
|
import { BiometricResultEnum } from '../../enums/BiometricResultEnum';
|
|
16
17
|
import { BiometricTypeEnum } from '../../enums/BiometricTypeEnum';
|
|
17
18
|
import { BiometricVerificationStatusEnum } from '../../enums/BiometricVerificationStatusEnum';
|
|
@@ -77,6 +78,16 @@ export class BiometricVerificationResponse {
|
|
|
77
78
|
@Expose()
|
|
78
79
|
delivery!: BiometricDelivery;
|
|
79
80
|
|
|
81
|
+
/**
|
|
82
|
+
* Contra qué foto se comparó. **Siempre poblado.**
|
|
83
|
+
*
|
|
84
|
+
* `CALLER_PROVIDED` significa que la foto la mandaste tú en `referenceImageUrl`. Es un valor
|
|
85
|
+
* distinto y no el default, porque decir `KYC_SELFIE` cuando la foto la pusiste tú sería mentir
|
|
86
|
+
* sobre contra qué se comparó — y eso es exactamente lo que este campo existe para evitar.
|
|
87
|
+
*/
|
|
88
|
+
@Expose() @IsEnum(BiometricReferenceSourceEnum)
|
|
89
|
+
referenceImageSource!: BiometricReferenceSourceEnum;
|
|
90
|
+
|
|
80
91
|
/**
|
|
81
92
|
* Similitud reportada por el proveedor, 0–100, cuando la expone. Rekognition da score; Metamap
|
|
82
93
|
* responde pass/fail y esto viene ausente.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contra QUÉ foto compara el biométrico.
|
|
3
|
+
*
|
|
4
|
+
* `CALLER_PROVIDED` es SOLO DE SALIDA: lo emite la respuesta cuando el caller mandó su propia
|
|
5
|
+
* `referenceImageUrl`. El request lo rechaza — pedirlo no significa nada.
|
|
6
|
+
*/
|
|
7
|
+
export enum BiometricReferenceSourceEnum {
|
|
8
|
+
/** La selfie del KYC. El default. */
|
|
9
|
+
KYC_SELFIE = 'KYC_SELFIE',
|
|
10
|
+
|
|
11
|
+
/** El frente de la identificación, resuelto por `fiado-identity-lambda`. */
|
|
12
|
+
ID_DOCUMENT = 'ID_DOCUMENT',
|
|
13
|
+
|
|
14
|
+
/** Solo de salida: la foto la puso el caller en `referenceImageUrl`. */
|
|
15
|
+
CALLER_PROVIDED = 'CALLER_PROVIDED',
|
|
16
|
+
}
|
|
@@ -18,20 +18,15 @@ import { BiometricResultEnum } from '../enums/BiometricResultEnum';
|
|
|
18
18
|
/**
|
|
19
19
|
* Lo que le pasó a una verificación biométrica, según el proveedor.
|
|
20
20
|
*
|
|
21
|
-
* **El recorrido:** Metamap → `kyc-metamap-webhook
|
|
22
|
-
*
|
|
21
|
+
* **El recorrido:** Metamap → `kyc-metamap-webhook`, que valida la firma HMAC y traduce → llamada
|
|
22
|
+
* HTTP síncrona a `biometrics-business`, que aplica la transición.
|
|
23
23
|
*
|
|
24
|
-
* **
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* traga el evento en silencio y la verificación queda `IN_PROGRESS` para siempre, con el caller
|
|
28
|
-
* poleando al vacío y sin alarma. La cola da durabilidad, DLQ y alarma sin tocar esa disciplina.
|
|
24
|
+
* 🔴 **No se loguea entero:**
|
|
25
|
+
* loguea los campos que necesites, nunca el objeto. El resto son identificadores operacionales y el
|
|
26
|
+
* veredicto.
|
|
29
27
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* partiría sus KYC a la mitad, en producción, al azar y sin un solo error en los logs.
|
|
33
|
-
*
|
|
34
|
-
* 🔴 **Sin PII.** Solo identificadores operacionales y el veredicto.
|
|
28
|
+
* Los duplicados son la norma —Metamap reintenta el webhook completo ante cualquier fallo—, así que
|
|
29
|
+
* el consumer deduplica por `eventId` y ordena por `occurredAt`.
|
|
35
30
|
*
|
|
36
31
|
* `biometrics-business` — Entrega 1.
|
|
37
32
|
*/
|
|
@@ -46,15 +41,12 @@ export class BiometricVerificationChangedV1 {
|
|
|
46
41
|
/**
|
|
47
42
|
* 🔴 **Identificador ÚNICO de este evento. La clave de deduplicación.**
|
|
48
43
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
44
|
+
* La entrega es *at-least-once*: Metamap reintenta el webhook completo, así que los duplicados
|
|
45
|
+
* son la norma, no la excepción. Y **el candado temporal por `occurredAt` NO alcanza para
|
|
46
|
+
* esto**: dos entregas del mismo evento traen exactamente el mismo `occurredAt`, así que una
|
|
47
|
+
* regla "descartar si es más viejo" las deja pasar a las dos.
|
|
52
48
|
*
|
|
53
49
|
* El consumer guarda los `eventId` ya aplicados y descarta los repetidos.
|
|
54
|
-
*
|
|
55
|
-
* ⚠️ **No deduplicar por el `MessageId` de SQS**: cambia en cada reintento de entrega, así que
|
|
56
|
-
* no deduplica nada. Es el error clásico y por eso queda escrito acá y no en la cabeza de cada
|
|
57
|
-
* consumidor.
|
|
58
50
|
*/
|
|
59
51
|
@Expose() @IsString() @IsNotEmpty()
|
|
60
52
|
eventId!: string;
|
|
@@ -103,7 +95,7 @@ export class BiometricVerificationChangedV1 {
|
|
|
103
95
|
* el evento real, y la transición no se aplicaría nunca — sin un solo error.
|
|
104
96
|
*
|
|
105
97
|
* Normalizar a UTC es trabajo del traductor del proveedor (`kyc-metamap-webhook`). Este candado
|
|
106
|
-
* existe para que si algún día deja de hacerlo, el
|
|
98
|
+
* existe para que si algún día deja de hacerlo, el evento se rechace en el boundary en vez de
|
|
107
99
|
* corromper el orden en silencio.
|
|
108
100
|
*/
|
|
109
101
|
@Expose() @IsString() @IsISO8601({ strict: true })
|
package/src/biometrics/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './enums/BiometricDeliveryModeEnum';
|
|
|
9
9
|
export * from './enums/BiometricVerificationStatusEnum';
|
|
10
10
|
export * from './enums/BiometricResultEnum';
|
|
11
11
|
export * from './enums/BiometricEventTypeEnum';
|
|
12
|
+
export * from './enums/BiometricReferenceSourceEnum';
|
|
12
13
|
|
|
13
14
|
// DTOs compartidos
|
|
14
15
|
export * from './dtos/BiometricSubject';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Respuesta del endpoint privado que devuelve el FRENTE de la identificación de un usuario:
|
|
6
|
+
* el URL presignado de S3 + su vigencia. Gemelo de `PeopleSelfieResponse`.
|
|
7
|
+
*
|
|
8
|
+
* Es la otra fuente posible del `userPhotoLink` del facematch. Se declara aparte y no se reusa
|
|
9
|
+
* `PeopleSelfieResponse` porque son dos endpoints distintos: compartir el tipo haría que un cambio
|
|
10
|
+
* en uno arrastrara al otro sin que nadie lo decida.
|
|
11
|
+
*/
|
|
12
|
+
export class PeopleIdPhotoResponse {
|
|
13
|
+
@Expose() @IsString() @IsNotEmpty()
|
|
14
|
+
directoryId!: string;
|
|
15
|
+
|
|
16
|
+
/** URL presignado de S3 del frente del documento. */
|
|
17
|
+
@Expose() @IsString() @IsNotEmpty()
|
|
18
|
+
url!: string;
|
|
19
|
+
|
|
20
|
+
/** Nombre del archivo en S3, sin el prefijo `USER/{directoryId}/`. */
|
|
21
|
+
@Expose() @IsString() @IsNotEmpty()
|
|
22
|
+
key!: string;
|
|
23
|
+
|
|
24
|
+
/** Vigencia del presigned URL en segundos. */
|
|
25
|
+
@Expose() @IsInt() @IsPositive()
|
|
26
|
+
expiresInSeconds!: number;
|
|
27
|
+
}
|
package/src/identity/index.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './dtos/PeopleSelfVerifiedRequest';
|
|
|
14
14
|
export * from './dtos/AgentDocumentKeyResponse';
|
|
15
15
|
export * from './dtos/DocumentUploadResponse';
|
|
16
16
|
export * from './dtos/PeopleSelfieResponse';
|
|
17
|
+
export * from './dtos/PeopleIdPhotoResponse';
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
//enums
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
|
|
3
|
+
import { CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH } from '../../constants/creditPaymentHook';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Body de `POST /private/credits/:creditId/payment-applied` (loan-credit-business). Es OPCIONAL:
|
|
7
|
+
* sin él el pago se atribuye al sistema. `paymentReference` es sólo trazabilidad — no decide nada.
|
|
8
|
+
*/
|
|
9
|
+
export class CreditPaymentAppliedRequest {
|
|
10
|
+
/** Quién aplicó el pago; queda en la bitácora del expediente. */
|
|
11
|
+
@Expose()
|
|
12
|
+
@IsOptional()
|
|
13
|
+
@IsString()
|
|
14
|
+
@IsNotEmpty()
|
|
15
|
+
@MaxLength(CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH)
|
|
16
|
+
actor?: string;
|
|
17
|
+
|
|
18
|
+
/** Referencia del pago en el sistema que lo aplicó. Sólo trazabilidad. */
|
|
19
|
+
@Expose()
|
|
20
|
+
@IsOptional()
|
|
21
|
+
@IsString()
|
|
22
|
+
@IsNotEmpty()
|
|
23
|
+
@MaxLength(CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH)
|
|
24
|
+
paymentReference?: string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
|
|
3
|
+
import { CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH } from '../../constants/creditPaymentHook';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Body de `POST /private/credits/:creditId/settled` (loan-credit-business). También opcional.
|
|
7
|
+
* La ruta VERIFICA que el crédito no deba nada: no le cree al caller.
|
|
8
|
+
*/
|
|
9
|
+
export class CreditSettledRequest {
|
|
10
|
+
/** Quién declaró la liquidación; queda en la bitácora del expediente. */
|
|
11
|
+
@Expose()
|
|
12
|
+
@IsOptional()
|
|
13
|
+
@IsString()
|
|
14
|
+
@IsNotEmpty()
|
|
15
|
+
@MaxLength(CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH)
|
|
16
|
+
actor?: string;
|
|
17
|
+
|
|
18
|
+
/** Referencia del pago que liquidó. Sólo trazabilidad. */
|
|
19
|
+
@Expose()
|
|
20
|
+
@IsOptional()
|
|
21
|
+
@IsString()
|
|
22
|
+
@IsNotEmpty()
|
|
23
|
+
@MaxLength(CREDIT_PAYMENT_HOOK_TEXT_MAX_LENGTH)
|
|
24
|
+
paymentReference?: string;
|
|
25
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CreditPaymentUnlockDecisionEnum } from '../../enums/CreditPaymentUnlockDecisionEnum';
|
|
2
|
+
|
|
3
|
+
/** Resultado de aplicar un pago: el crédito sale de mora y el equipo se suelta si corresponde. */
|
|
4
|
+
export interface CreditPaymentAppliedResponse {
|
|
5
|
+
creditId: string;
|
|
6
|
+
/** El crédito salió de mora. Pasa aunque no haya equipo, esté sin candado, o sea SCHEDULED. */
|
|
7
|
+
creditReactivated: boolean;
|
|
8
|
+
unlockDecision: CreditPaymentUnlockDecisionEnum;
|
|
9
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { CreditSettlementDecisionEnum } from '../../enums/CreditSettlementDecisionEnum';
|
|
2
|
+
import { CreditSettlementReleaseDecisionEnum } from '../../enums/CreditSettlementReleaseDecisionEnum';
|
|
3
|
+
|
|
4
|
+
/** Resultado de liquidar el crédito; `releaseDecision` es null si el equipo no salió al proveedor. */
|
|
5
|
+
export interface CreditSettledResponse {
|
|
6
|
+
creditId: string;
|
|
7
|
+
settlementDecision: CreditSettlementDecisionEnum;
|
|
8
|
+
releaseDecision: CreditSettlementReleaseDecisionEnum | null;
|
|
9
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qué pasó con el equipo cuando se aplicó un pago al crédito.
|
|
3
|
+
* @enum {string}
|
|
4
|
+
*/
|
|
5
|
+
export enum CreditPaymentUnlockDecisionEnum {
|
|
6
|
+
CREDIT_NOT_FOUND = 'CREDIT_NOT_FOUND',
|
|
7
|
+
/** El crédito no está en un estado al que el pago le suelte el equipo. */
|
|
8
|
+
CREDIT_NOT_UNLOCKABLE = 'CREDIT_NOT_UNLOCKABLE',
|
|
9
|
+
NOT_ENROLLED = 'NOT_ENROLLED',
|
|
10
|
+
/** El equipo no estaba bloqueado: no hay nada que soltar. */
|
|
11
|
+
NOT_LOCKED = 'NOT_LOCKED',
|
|
12
|
+
/** El candado no es el de la mora (fraude, manual, o sin motivo): un pago no lo suelta. */
|
|
13
|
+
LOCKED_FOR_OTHER_REASON = 'LOCKED_FOR_OTHER_REASON',
|
|
14
|
+
/** El pago no alcanzó el umbral escalonado: sigue bloqueado y no se reprograma nada. */
|
|
15
|
+
THRESHOLD_NOT_MET = 'THRESHOLD_NOT_MET',
|
|
16
|
+
UNLOCKED = 'UNLOCKED',
|
|
17
|
+
/** El proveedor aceptó la orden y todavía no la dio por hecha. */
|
|
18
|
+
UNLOCK_PENDING = 'UNLOCK_PENDING',
|
|
19
|
+
UNLOCK_FAILED = 'UNLOCK_FAILED',
|
|
20
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qué pasó al intentar dejar el crédito liquidado. La ruta VERIFICA el saldo, no cree al caller.
|
|
3
|
+
* @enum {string}
|
|
4
|
+
*/
|
|
5
|
+
export enum CreditSettlementDecisionEnum {
|
|
6
|
+
CREDIT_NOT_FOUND = 'CREDIT_NOT_FOUND',
|
|
7
|
+
/** Ya estaba liquidado: la ruta es idempotente y la liberación corre igual. */
|
|
8
|
+
ALREADY_SETTLED = 'ALREADY_SETTLED',
|
|
9
|
+
/** El estado del crédito no admite liquidación (sólo ACTIVE e IN_ARREARS la admiten). */
|
|
10
|
+
CREDIT_NOT_SETTLEABLE = 'CREDIT_NOT_SETTLEABLE',
|
|
11
|
+
/** Sin plan de cuotas no hay evidencia de que deba cero; fail-closed. */
|
|
12
|
+
NO_INSTALLMENTS = 'NO_INSTALLMENTS',
|
|
13
|
+
/** Al plan le falta alguna cuota del plazo: la deuda que no se persistió no se puede saldar. */
|
|
14
|
+
INCOMPLETE_PLAN = 'INCOMPLETE_PLAN',
|
|
15
|
+
/** Alguna cuota sigue debiendo: liquidar acá liberaría un equipo con deuda viva. */
|
|
16
|
+
BALANCE_OUTSTANDING = 'BALANCE_OUTSTANDING',
|
|
17
|
+
SETTLED = 'SETTLED',
|
|
18
|
+
/** Otro movió el estado entre la lectura y la escritura; el caller relee y reintenta. */
|
|
19
|
+
SETTLE_CONFLICT = 'SETTLE_CONFLICT',
|
|
20
|
+
SETTLE_FAILED = 'SETTLE_FAILED',
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Qué pasó con el equipo al liquidarse el crédito. El verbo es Release, terminal: el equipo SALE
|
|
3
|
+
* del enrolamiento, no se queda desbloqueado.
|
|
4
|
+
* @enum {string}
|
|
5
|
+
*/
|
|
6
|
+
export enum CreditSettlementReleaseDecisionEnum {
|
|
7
|
+
CREDIT_NOT_FOUND = 'CREDIT_NOT_FOUND',
|
|
8
|
+
/** El crédito no está liquidado: liberar el equipo sería irreversible y prematuro. */
|
|
9
|
+
CREDIT_NOT_SETTLED = 'CREDIT_NOT_SETTLED',
|
|
10
|
+
NOT_ENROLLED = 'NOT_ENROLLED',
|
|
11
|
+
/** El expediente ya salió del MDM; la liberación es idempotente y no vuelve a salir. */
|
|
12
|
+
ALREADY_RELEASED = 'ALREADY_RELEASED',
|
|
13
|
+
RELEASED = 'RELEASED',
|
|
14
|
+
/** El proveedor aceptó la liberación y todavía no la dio por hecha. */
|
|
15
|
+
RELEASE_PENDING = 'RELEASE_PENDING',
|
|
16
|
+
RELEASE_FAILED = 'RELEASE_FAILED',
|
|
17
|
+
}
|
package/src/loanCredit/index.ts
CHANGED
|
@@ -23,6 +23,14 @@ export * from './dtos/requests/OriginateLoanCreditRequest';
|
|
|
23
23
|
export * from './dtos/requests/QuoteLoanCreditRequest';
|
|
24
24
|
export * from './dtos/requests/SignLoanCreditRequest';
|
|
25
25
|
export * from './dtos/requests/ActivationCheckRequest';
|
|
26
|
+
export * from './dtos/requests/CreditPaymentAppliedRequest';
|
|
27
|
+
export * from './dtos/requests/CreditSettledRequest';
|
|
28
|
+
export * from './dtos/responses/CreditPaymentAppliedResponse';
|
|
29
|
+
export * from './dtos/responses/CreditSettledResponse';
|
|
30
|
+
export * from './enums/CreditPaymentUnlockDecisionEnum';
|
|
31
|
+
export * from './enums/CreditSettlementDecisionEnum';
|
|
32
|
+
export * from './enums/CreditSettlementReleaseDecisionEnum';
|
|
33
|
+
export * from './constants/creditPaymentHook';
|
|
26
34
|
export * from './dtos/requests/ChangeLoanCreditStatusRequest';
|
|
27
35
|
|
|
28
36
|
// Response DTOs
|