@fiado/type-kit 3.495.0 → 3.497.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/dtos/createSellerPaymentRequest.test.ts +63 -0
- package/_test_/unit/loanCredit/inStorePaymentDtos.test.ts +141 -0
- package/_test_/unit/retailIntegration/applyRetailEventRequest.test.ts +43 -0
- package/_test_/unit/retailIntegration/isIsoDateTimeWithZone.test.ts +85 -0
- package/_test_/unit/retailIntegration/receiveRetailEventRequest.test.ts +93 -0
- package/_test_/unit/retailIntegration/retailOutboundRequests.test.ts +69 -0
- package/_test_/unit/retailIntegration/retailSystemEnums.test.ts +42 -0
- package/bin/index.d.ts +1 -0
- package/bin/index.js +3 -1
- package/bin/loanCredit/dtos/requests/CreateSellerPaymentRequest.d.ts +15 -0
- package/bin/loanCredit/dtos/requests/CreateSellerPaymentRequest.js +56 -0
- package/bin/loanCredit/dtos/requests/InStorePaymentDetail.d.ts +12 -0
- package/bin/loanCredit/dtos/requests/InStorePaymentDetail.js +40 -0
- package/bin/loanCredit/dtos/responses/CreditCustomerListItem.d.ts +46 -0
- package/bin/loanCredit/dtos/responses/CreditCustomerListItem.js +2 -0
- package/bin/loanCredit/dtos/responses/InStorePaymentListItem.d.ts +19 -0
- package/bin/loanCredit/dtos/responses/InStorePaymentListItem.js +2 -0
- package/bin/loanCredit/dtos/responses/LoanPaymentListItem.d.ts +14 -1
- package/bin/loanCredit/dtos/responses/SellerCreditLookupResult.d.ts +10 -0
- package/bin/loanCredit/dtos/responses/SellerCreditLookupResult.js +2 -0
- package/bin/loanCredit/dtos/responses/SellerPaymentOptions.d.ts +36 -0
- package/bin/loanCredit/dtos/responses/SellerPaymentOptions.js +2 -0
- package/bin/loanCredit/dtos/responses/SellerPaymentResult.d.ts +39 -0
- package/bin/loanCredit/dtos/responses/SellerPaymentResult.js +2 -0
- package/bin/loanCredit/enums/CreditCustomerStateEnum.d.ts +6 -0
- package/bin/loanCredit/enums/CreditCustomerStateEnum.js +10 -0
- package/bin/loanCredit/enums/InStorePaymentMethodEnum.d.ts +6 -0
- package/bin/loanCredit/enums/InStorePaymentMethodEnum.js +10 -0
- package/bin/loanCredit/enums/LoanPaymentOriginEnum.d.ts +5 -0
- package/bin/loanCredit/enums/LoanPaymentOriginEnum.js +9 -0
- package/bin/loanCredit/index.d.ts +10 -0
- package/bin/loanCredit/index.js +11 -0
- package/bin/retailIntegration/constants/retailIntegrationLimits.d.ts +7 -0
- package/bin/retailIntegration/constants/retailIntegrationLimits.js +10 -0
- package/bin/retailIntegration/dtos/ApplyRetailEventRequest.d.ts +29 -0
- package/bin/retailIntegration/dtos/ApplyRetailEventRequest.js +54 -0
- package/bin/retailIntegration/dtos/GetRetailInventoryRequest.d.ts +5 -0
- package/bin/retailIntegration/dtos/GetRetailInventoryRequest.js +23 -0
- package/bin/retailIntegration/dtos/ListRetailCatalogRequest.d.ts +4 -0
- package/bin/retailIntegration/dtos/ListRetailCatalogRequest.js +8 -0
- package/bin/retailIntegration/dtos/ListRetailStoresRequest.d.ts +4 -0
- package/bin/retailIntegration/dtos/ListRetailStoresRequest.js +8 -0
- package/bin/retailIntegration/dtos/ListRetailUsersRequest.d.ts +5 -0
- package/bin/retailIntegration/dtos/ListRetailUsersRequest.js +24 -0
- package/bin/retailIntegration/dtos/ReceiveInventoryEventRequest.d.ts +6 -0
- package/bin/retailIntegration/dtos/ReceiveInventoryEventRequest.js +23 -0
- package/bin/retailIntegration/dtos/ReceiveProductEventRequest.d.ts +6 -0
- package/bin/retailIntegration/dtos/ReceiveProductEventRequest.js +23 -0
- package/bin/retailIntegration/dtos/ReceiveRetailEventRequest.d.ts +12 -0
- package/bin/retailIntegration/dtos/ReceiveRetailEventRequest.js +2 -0
- package/bin/retailIntegration/dtos/ReceiveRetailUserEventRequest.d.ts +6 -0
- package/bin/retailIntegration/dtos/ReceiveRetailUserEventRequest.js +23 -0
- package/bin/retailIntegration/dtos/ReceiveStoreEventRequest.d.ts +6 -0
- package/bin/retailIntegration/dtos/ReceiveStoreEventRequest.js +23 -0
- package/bin/retailIntegration/dtos/RegisterRetailSaleRequest.d.ts +4 -0
- package/bin/retailIntegration/dtos/RegisterRetailSaleRequest.js +8 -0
- package/bin/retailIntegration/dtos/RetailEventEnvelope.d.ts +8 -0
- package/bin/retailIntegration/dtos/RetailEventEnvelope.js +33 -0
- package/bin/retailIntegration/dtos/RetailEventResult.d.ts +12 -0
- package/bin/retailIntegration/dtos/RetailEventResult.js +2 -0
- package/bin/retailIntegration/dtos/RetailOutboundResponses.d.ts +30 -0
- package/bin/retailIntegration/dtos/RetailOutboundResponses.js +2 -0
- package/bin/retailIntegration/dtos/RetailPagedQuery.d.ts +6 -0
- package/bin/retailIntegration/dtos/RetailPagedQuery.js +34 -0
- package/bin/retailIntegration/dtos/RetailTenantQuery.d.ts +4 -0
- package/bin/retailIntegration/dtos/RetailTenantQuery.js +23 -0
- package/bin/retailIntegration/enums/InventoryEventTypeEnum.d.ts +4 -0
- package/bin/retailIntegration/enums/InventoryEventTypeEnum.js +8 -0
- package/bin/retailIntegration/enums/ProductEventTypeEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/ProductEventTypeEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailCurrencyEnum.d.ts +5 -0
- package/bin/retailIntegration/enums/RetailCurrencyEnum.js +9 -0
- package/bin/retailIntegration/enums/RetailEventResultEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/RetailEventResultEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailFinancierEnum.d.ts +8 -0
- package/bin/retailIntegration/enums/RetailFinancierEnum.js +12 -0
- package/bin/retailIntegration/enums/RetailLinePaymentTypeEnum.d.ts +5 -0
- package/bin/retailIntegration/enums/RetailLinePaymentTypeEnum.js +9 -0
- package/bin/retailIntegration/enums/RetailMdmProviderEnum.d.ts +5 -0
- package/bin/retailIntegration/enums/RetailMdmProviderEnum.js +9 -0
- package/bin/retailIntegration/enums/RetailPaymentMethodEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/RetailPaymentMethodEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailPieceReasonEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/RetailPieceReasonEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailPieceStatusEnum.d.ts +7 -0
- package/bin/retailIntegration/enums/RetailPieceStatusEnum.js +11 -0
- package/bin/retailIntegration/enums/RetailProductCategoryEnum.d.ts +7 -0
- package/bin/retailIntegration/enums/RetailProductCategoryEnum.js +11 -0
- package/bin/retailIntegration/enums/RetailProductStatusEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/RetailProductStatusEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailProductTierEnum.d.ts +7 -0
- package/bin/retailIntegration/enums/RetailProductTierEnum.js +11 -0
- package/bin/retailIntegration/enums/RetailSaleFinancierEnum.d.ts +9 -0
- package/bin/retailIntegration/enums/RetailSaleFinancierEnum.js +13 -0
- package/bin/retailIntegration/enums/RetailSaleTypeEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/RetailSaleTypeEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailStoreStatusEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/RetailStoreStatusEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailTrackingModeEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/RetailTrackingModeEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailUserAccessStatusEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/RetailUserAccessStatusEnum.js +10 -0
- package/bin/retailIntegration/enums/RetailUserEventTypeEnum.d.ts +7 -0
- package/bin/retailIntegration/enums/RetailUserEventTypeEnum.js +11 -0
- package/bin/retailIntegration/enums/RetailUserRoleEnum.d.ts +7 -0
- package/bin/retailIntegration/enums/RetailUserRoleEnum.js +11 -0
- package/bin/retailIntegration/enums/StoreEventTypeEnum.d.ts +6 -0
- package/bin/retailIntegration/enums/StoreEventTypeEnum.js +10 -0
- package/bin/retailIntegration/enums/index.d.ts +21 -0
- package/bin/retailIntegration/enums/index.js +37 -0
- package/bin/retailIntegration/index.d.ts +25 -0
- package/bin/retailIntegration/index.js +41 -0
- package/bin/retailIntegration/models/RetailPageMeta.d.ts +10 -0
- package/bin/retailIntegration/models/RetailPageMeta.js +2 -0
- package/bin/retailIntegration/models/RetailSystemInventory.d.ts +17 -0
- package/bin/retailIntegration/models/RetailSystemInventory.js +2 -0
- package/bin/retailIntegration/models/RetailSystemProduct.d.ts +32 -0
- package/bin/retailIntegration/models/RetailSystemProduct.js +2 -0
- package/bin/retailIntegration/models/RetailSystemSale.d.ts +46 -0
- package/bin/retailIntegration/models/RetailSystemSale.js +2 -0
- package/bin/retailIntegration/models/RetailSystemStore.d.ts +29 -0
- package/bin/retailIntegration/models/RetailSystemStore.js +2 -0
- package/bin/retailIntegration/models/RetailSystemUser.d.ts +14 -0
- package/bin/retailIntegration/models/RetailSystemUser.js +2 -0
- package/bin/retailIntegration/validators/IsIsoDateTimeWithZone.d.ts +6 -0
- package/bin/retailIntegration/validators/IsIsoDateTimeWithZone.js +29 -0
- package/package.json +1 -1
- package/src/index.ts +2 -0
- package/src/loanCredit/dtos/requests/CreateSellerPaymentRequest.ts +40 -0
- package/src/loanCredit/dtos/requests/InStorePaymentDetail.ts +27 -0
- package/src/loanCredit/dtos/responses/CreditCustomerListItem.ts +51 -0
- package/src/loanCredit/dtos/responses/InStorePaymentListItem.ts +21 -0
- package/src/loanCredit/dtos/responses/LoanPaymentListItem.ts +11 -1
- package/src/loanCredit/dtos/responses/SellerCreditLookupResult.ts +11 -0
- package/src/loanCredit/dtos/responses/SellerPaymentOptions.ts +29 -0
- package/src/loanCredit/dtos/responses/SellerPaymentResult.ts +43 -0
- package/src/loanCredit/enums/CreditCustomerStateEnum.ts +6 -0
- package/src/loanCredit/enums/InStorePaymentMethodEnum.ts +6 -0
- package/src/loanCredit/enums/LoanPaymentOriginEnum.ts +5 -0
- package/src/loanCredit/index.ts +12 -0
- package/src/retailIntegration/constants/retailIntegrationLimits.ts +9 -0
- package/src/retailIntegration/dtos/ApplyRetailEventRequest.ts +49 -0
- package/src/retailIntegration/dtos/GetRetailInventoryRequest.ts +9 -0
- package/src/retailIntegration/dtos/ListRetailCatalogRequest.ts +4 -0
- package/src/retailIntegration/dtos/ListRetailStoresRequest.ts +4 -0
- package/src/retailIntegration/dtos/ListRetailUsersRequest.ts +10 -0
- package/src/retailIntegration/dtos/ReceiveInventoryEventRequest.ts +9 -0
- package/src/retailIntegration/dtos/ReceiveProductEventRequest.ts +9 -0
- package/src/retailIntegration/dtos/ReceiveRetailEventRequest.ts +18 -0
- package/src/retailIntegration/dtos/ReceiveRetailUserEventRequest.ts +9 -0
- package/src/retailIntegration/dtos/ReceiveStoreEventRequest.ts +9 -0
- package/src/retailIntegration/dtos/RegisterRetailSaleRequest.ts +4 -0
- package/src/retailIntegration/dtos/RetailEventEnvelope.ts +20 -0
- package/src/retailIntegration/dtos/RetailEventResult.ts +14 -0
- package/src/retailIntegration/dtos/RetailOutboundResponses.ts +35 -0
- package/src/retailIntegration/dtos/RetailPagedQuery.ts +19 -0
- package/src/retailIntegration/dtos/RetailTenantQuery.ts +9 -0
- package/src/retailIntegration/enums/InventoryEventTypeEnum.ts +4 -0
- package/src/retailIntegration/enums/ProductEventTypeEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailCurrencyEnum.ts +5 -0
- package/src/retailIntegration/enums/RetailEventResultEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailFinancierEnum.ts +8 -0
- package/src/retailIntegration/enums/RetailLinePaymentTypeEnum.ts +5 -0
- package/src/retailIntegration/enums/RetailMdmProviderEnum.ts +5 -0
- package/src/retailIntegration/enums/RetailPaymentMethodEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailPieceReasonEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailPieceStatusEnum.ts +7 -0
- package/src/retailIntegration/enums/RetailProductCategoryEnum.ts +7 -0
- package/src/retailIntegration/enums/RetailProductStatusEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailProductTierEnum.ts +7 -0
- package/src/retailIntegration/enums/RetailSaleFinancierEnum.ts +9 -0
- package/src/retailIntegration/enums/RetailSaleTypeEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailStoreStatusEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailTrackingModeEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailUserAccessStatusEnum.ts +6 -0
- package/src/retailIntegration/enums/RetailUserEventTypeEnum.ts +7 -0
- package/src/retailIntegration/enums/RetailUserRoleEnum.ts +7 -0
- package/src/retailIntegration/enums/StoreEventTypeEnum.ts +6 -0
- package/src/retailIntegration/enums/index.ts +21 -0
- package/src/retailIntegration/index.ts +25 -0
- package/src/retailIntegration/models/RetailPageMeta.ts +11 -0
- package/src/retailIntegration/models/RetailSystemInventory.ts +20 -0
- package/src/retailIntegration/models/RetailSystemProduct.ts +43 -0
- package/src/retailIntegration/models/RetailSystemSale.ts +51 -0
- package/src/retailIntegration/models/RetailSystemStore.ts +33 -0
- package/src/retailIntegration/models/RetailSystemUser.ts +16 -0
- package/src/retailIntegration/validators/IsIsoDateTimeWithZone.ts +21 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import { CreateSellerPaymentRequest } from '../../../../src/loanCredit/index';
|
|
5
|
+
|
|
6
|
+
const errorPaths = async (body: object): Promise<string[]> => {
|
|
7
|
+
const dto = plainToInstance(CreateSellerPaymentRequest, body);
|
|
8
|
+
const errors = await validate(dto, { whitelist: true, forbidNonWhitelisted: false });
|
|
9
|
+
const pathsOf = (error: (typeof errors)[number], parent: string): string[] => {
|
|
10
|
+
const path = parent ? `${parent}.${error.property}` : error.property;
|
|
11
|
+
return [...(error.constraints ? [path] : []), ...(error.children ?? []).flatMap((child) => pathsOf(child, path))];
|
|
12
|
+
};
|
|
13
|
+
return errors.flatMap((error) => pathsOf(error, ''));
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const BASE = {
|
|
17
|
+
type: 'NEXT_INSTALLMENT',
|
|
18
|
+
expectedAmountCents: 48_700,
|
|
19
|
+
method: 'CASH',
|
|
20
|
+
idempotencyKey: '7b0e3a52-6a0f-4f1f-9f43-6b4d5c1e2a10',
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
describe('CreateSellerPaymentRequest', () => {
|
|
24
|
+
it('acepta efectivo sin detalle', async () => {
|
|
25
|
+
expect(await errorPaths(BASE)).toEqual([]);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('acepta tarjeta con últimos 4 y autorización', async () => {
|
|
29
|
+
expect(await errorPaths({ ...BASE, method: 'CARD', detail: { cardLast4: '4242', authCode: 'A1B2C3' } })).toEqual([]);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('acepta SPEI con clave de rastreo de hasta 30', async () => {
|
|
33
|
+
expect(await errorPaths({ ...BASE, method: 'WIRE', detail: { speiTrackingKey: 'X'.repeat(30) } })).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('rechaza últimos 4 que no son 4 dígitos', async () => {
|
|
37
|
+
expect(await errorPaths({ ...BASE, method: 'CARD', detail: { cardLast4: '42a2', authCode: 'A1' } })).toEqual(['detail.cardLast4']);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('rechaza clave de rastreo vacía o de más de 30', async () => {
|
|
41
|
+
expect(await errorPaths({ ...BASE, method: 'WIRE', detail: { speiTrackingKey: '' } })).toEqual(['detail.speiTrackingKey']);
|
|
42
|
+
expect(await errorPaths({ ...BASE, method: 'WIRE', detail: { speiTrackingKey: 'X'.repeat(31) } })).toEqual([
|
|
43
|
+
'detail.speiTrackingKey',
|
|
44
|
+
]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('rechaza forma de pago, tipo, monto o llave inválidos', async () => {
|
|
48
|
+
expect(await errorPaths({ ...BASE, method: 'CHEQUE' })).toEqual(['method']);
|
|
49
|
+
expect(await errorPaths({ ...BASE, type: 'OTHER' })).toEqual(['type']);
|
|
50
|
+
expect(await errorPaths({ ...BASE, expectedAmountCents: 0 })).toEqual(['expectedAmountCents']);
|
|
51
|
+
expect(await errorPaths({ ...BASE, idempotencyKey: 'no-uuid' })).toEqual(['idempotencyKey']);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('cuotas solo de 2 en adelante', async () => {
|
|
55
|
+
expect(await errorPaths({ ...BASE, type: 'ADVANCE', installmentCount: 1 })).toEqual(['installmentCount']);
|
|
56
|
+
expect(await errorPaths({ ...BASE, type: 'ADVANCE', installmentCount: 2 })).toEqual([]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('no declara CLABE: con whitelist se descarta y nunca llega al dominio', () => {
|
|
60
|
+
const dto = plainToInstance(CreateSellerPaymentRequest, { ...BASE, clabe: '012345678901234567' }, { excludeExtraneousValues: true });
|
|
61
|
+
expect(dto).not.toHaveProperty('clabe');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import type {
|
|
3
|
+
CreditCustomerListItem,
|
|
4
|
+
InStorePaymentListResponse,
|
|
5
|
+
LoanPaymentListItem,
|
|
6
|
+
SellerCreditLookupResult,
|
|
7
|
+
SellerPaymentOptions,
|
|
8
|
+
SellerPaymentResult,
|
|
9
|
+
} from '../../../src/loanCredit/index';
|
|
10
|
+
import {
|
|
11
|
+
CreditCustomerStateEnum,
|
|
12
|
+
InStorePaymentMethodEnum,
|
|
13
|
+
LoanCustomerPaymentTypeEnum,
|
|
14
|
+
LoanInstallmentStatusEnum,
|
|
15
|
+
LoanPaymentOriginEnum,
|
|
16
|
+
} from '../../../src/loanCredit/index';
|
|
17
|
+
|
|
18
|
+
describe.each([
|
|
19
|
+
['InStorePaymentMethodEnum', InStorePaymentMethodEnum, ['CASH', 'CARD', 'WIRE']],
|
|
20
|
+
['LoanPaymentOriginEnum', LoanPaymentOriginEnum, ['COLLECTION_ENGINE', 'IN_STORE']],
|
|
21
|
+
['CreditCustomerStateEnum', CreditCustomerStateEnum, ['READ', 'NO_BORROWER', 'UNAVAILABLE']],
|
|
22
|
+
])('%s', (_name, enumObject, values) => {
|
|
23
|
+
it('tiene exactamente los valores del contrato', () => {
|
|
24
|
+
expect(Object.values(enumObject).sort()).toEqual([...values].sort());
|
|
25
|
+
});
|
|
26
|
+
it('cada llave es igual a su valor', () => {
|
|
27
|
+
for (const [key, value] of Object.entries(enumObject)) {
|
|
28
|
+
expect(key).toBe(value);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('loanCredit — contrato del cobro en tienda', () => {
|
|
34
|
+
it('el resultado lleva folio, tienda, vendedor, siguiente cuota y equipo', () => {
|
|
35
|
+
const result: SellerPaymentResult = {
|
|
36
|
+
creditId: 'CR-1',
|
|
37
|
+
receipt: 'SK-TD-0123456789ab',
|
|
38
|
+
amountCents: 48_700,
|
|
39
|
+
type: LoanCustomerPaymentTypeEnum.NEXT_INSTALLMENT,
|
|
40
|
+
method: InStorePaymentMethodEnum.CASH,
|
|
41
|
+
appliedAt: '2026-10-08T17:00:00.000Z',
|
|
42
|
+
outstandingBalanceAfterCents: 400_000,
|
|
43
|
+
collectedAtStore: { id: 'ST-1', name: 'Tienda Limpia' },
|
|
44
|
+
collectedBySeller: { id: 'RU-1', name: 'Ana' },
|
|
45
|
+
nextInstallment: { installmentNumber: 4, dueDate: '2026-10-15', amountCents: 48_700, status: LoanInstallmentStatusEnum.PENDING },
|
|
46
|
+
credit: { creditId: 'CR-1', imei: '356789012345678', productBrand: 'Samsung', productModel: 'A15' },
|
|
47
|
+
};
|
|
48
|
+
expect(result.receipt.startsWith('SK-TD-')).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('las opciones traen el resumen y cada tipo con su monto o rango', () => {
|
|
52
|
+
const options: SellerPaymentOptions = {
|
|
53
|
+
creditId: 'CR-1',
|
|
54
|
+
summary: { totalCents: 1_000_000, paidCents: 600_000, remainingCents: 400_000, nextInstallment: null },
|
|
55
|
+
nextInstallment: { available: true, amountCents: 97_400, installmentNumbers: [3, 4], overdueCount: 1 },
|
|
56
|
+
advance: { available: false, unavailableReason: 'CREDIT_NOT_CURRENT' as never },
|
|
57
|
+
prepayment: { available: false },
|
|
58
|
+
settlement: { available: true, amountCents: 380_000 },
|
|
59
|
+
};
|
|
60
|
+
expect(options.nextInstallment.installmentNumbers).toEqual([3, 4]);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('la búsqueda responde lo mínimo, sin el identificador que no se buscó', () => {
|
|
64
|
+
const found: SellerCreditLookupResult = {
|
|
65
|
+
creditId: 'CR-1',
|
|
66
|
+
customerName: 'Juan P.',
|
|
67
|
+
productBrand: 'Samsung',
|
|
68
|
+
productModel: 'A15',
|
|
69
|
+
nextInstallment: null,
|
|
70
|
+
};
|
|
71
|
+
expect(found).not.toHaveProperty('imei');
|
|
72
|
+
expect(found).not.toHaveProperty('phone');
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it('la conciliación pagina los cobros de una tienda', () => {
|
|
76
|
+
const page: InStorePaymentListResponse = {
|
|
77
|
+
items: [
|
|
78
|
+
{
|
|
79
|
+
receipt: 'SK-TD-0123456789ab',
|
|
80
|
+
creditId: 'CR-1',
|
|
81
|
+
paymentId: '01J00000000000000000000000',
|
|
82
|
+
chargeKind: 'INSTALLMENT' as never,
|
|
83
|
+
amountCents: 48_700,
|
|
84
|
+
method: InStorePaymentMethodEnum.CARD,
|
|
85
|
+
collectedBySeller: { id: 'RU-1', name: 'Ana' },
|
|
86
|
+
appliedAt: '2026-10-08T17:00:00.000Z',
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
};
|
|
90
|
+
expect(page.nextToken).toBeUndefined();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it('el historial dice dónde, cómo y quién; mechanism es opcional', () => {
|
|
94
|
+
const item: LoanPaymentListItem = {
|
|
95
|
+
paymentId: 'P-1',
|
|
96
|
+
receipt: 'SK-TD-0123456789ab',
|
|
97
|
+
installmentNumber: 3,
|
|
98
|
+
attemptId: 'IN_STORE#k',
|
|
99
|
+
result: 'FULL' as never,
|
|
100
|
+
currency: 'MXN' as never,
|
|
101
|
+
collectedCents: 48_700,
|
|
102
|
+
appliedCents: 48_700,
|
|
103
|
+
overpaidCents: 0,
|
|
104
|
+
reservedCents: 0,
|
|
105
|
+
needsReview: false,
|
|
106
|
+
appliedAt: '2026-10-08T17:00:00.000Z',
|
|
107
|
+
origin: LoanPaymentOriginEnum.IN_STORE,
|
|
108
|
+
inStoreMethod: InStorePaymentMethodEnum.CASH,
|
|
109
|
+
collectedAtStore: { id: 'ST-1', name: 'Tienda Limpia' },
|
|
110
|
+
collectedBySeller: { id: 'RU-1', name: 'Ana' },
|
|
111
|
+
};
|
|
112
|
+
expect(item.mechanism).toBeUndefined();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('la fila de Clientes trae el último pago con su lugar', () => {
|
|
116
|
+
const row: CreditCustomerListItem = {
|
|
117
|
+
retailCustomerId: 'RC-1',
|
|
118
|
+
fullName: null,
|
|
119
|
+
phone: null,
|
|
120
|
+
originStoreId: null,
|
|
121
|
+
segments: [],
|
|
122
|
+
segmentsRead: true,
|
|
123
|
+
credit: {
|
|
124
|
+
state: CreditCustomerStateEnum.READ,
|
|
125
|
+
clientLevel: null,
|
|
126
|
+
sciScore: null,
|
|
127
|
+
sciSource: null,
|
|
128
|
+
creditsCount: 1,
|
|
129
|
+
activeCreditsCount: 1,
|
|
130
|
+
settledCreditsCount: 0,
|
|
131
|
+
writtenOffCreditsCount: 0,
|
|
132
|
+
outstandingBalanceCents: 0,
|
|
133
|
+
arrearsDays: 0,
|
|
134
|
+
lastPaymentAt: '2026-10-08T17:00:00.000Z',
|
|
135
|
+
lastPayment: { at: '2026-10-08T17:00:00.000Z', origin: LoanPaymentOriginEnum.IN_STORE, storeId: 'ST-1', storeName: 'Tienda Limpia' },
|
|
136
|
+
activeCreditId: 'CR-1',
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
expect(row.credit.lastPayment?.storeName).toBe('Tienda Limpia');
|
|
140
|
+
});
|
|
141
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import {
|
|
5
|
+
ApplyInventoryEventRequest,
|
|
6
|
+
ApplyProductEventRequest,
|
|
7
|
+
ApplyRetailUserEventRequest,
|
|
8
|
+
ApplyStoreEventRequest,
|
|
9
|
+
} from '../../../src/retailIntegration/dtos/ApplyRetailEventRequest';
|
|
10
|
+
|
|
11
|
+
const base = {
|
|
12
|
+
tenantId: 'surekeep',
|
|
13
|
+
eventId: 'evt_01J8ZA1B2C3D4E5F6G7H8J9K0L',
|
|
14
|
+
occurredAt: '2026-08-01T15:00:00Z',
|
|
15
|
+
payload: { storeId: '12' },
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
async function propertiesWithErrors(cls: new () => object, plain: Record<string, unknown>): Promise<string[]> {
|
|
19
|
+
const errors = await validate(plainToInstance(cls, plain));
|
|
20
|
+
return errors.map((error) => error.property);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('DTOs del contrato connector → destino', () => {
|
|
24
|
+
it.each([
|
|
25
|
+
[ApplyStoreEventRequest, 'StoreCreatedV1', 'RetailUserCreatedV1'],
|
|
26
|
+
[ApplyRetailUserEventRequest, 'RetailUserTransferredV1', 'StoreCreatedV1'],
|
|
27
|
+
[ApplyProductEventRequest, 'ProductCreatedV1', 'InventoryMovementV1'],
|
|
28
|
+
[ApplyInventoryEventRequest, 'InventoryMovementV1', 'ProductUpdatedV1'],
|
|
29
|
+
])('%p acepta %s y rechaza %s de otra ruta', async (cls, own, foreign) => {
|
|
30
|
+
expect(await propertiesWithErrors(cls, { ...base, eventType: own })).toEqual([]);
|
|
31
|
+
expect(await propertiesWithErrors(cls, { ...base, eventType: foreign })).toEqual(['eventType']);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it.each([ApplyStoreEventRequest, ApplyRetailUserEventRequest, ApplyProductEventRequest, ApplyInventoryEventRequest])(
|
|
35
|
+
'%p valida tenantId',
|
|
36
|
+
async (cls) => {
|
|
37
|
+
const eventType = { ApplyStoreEventRequest: 'StoreCreatedV1', ApplyRetailUserEventRequest: 'RetailUserCreatedV1', ApplyProductEventRequest: 'ProductCreatedV1', ApplyInventoryEventRequest: 'InventoryMovementV1' }[cls.name];
|
|
38
|
+
for (const tenantId of [undefined, '', 'sure/keep', 'a'.repeat(65)]) {
|
|
39
|
+
expect(await propertiesWithErrors(cls, { ...base, eventType, tenantId })).toEqual(['tenantId']);
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
);
|
|
43
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { IsIsoDateTimeWithZone } from '../../../src/retailIntegration/validators/IsIsoDateTimeWithZone';
|
|
3
|
+
import {
|
|
4
|
+
InventoryEventTypeEnum,
|
|
5
|
+
ProductEventTypeEnum,
|
|
6
|
+
RetailEventResultEnum,
|
|
7
|
+
RetailUserEventTypeEnum,
|
|
8
|
+
StoreEventTypeEnum,
|
|
9
|
+
} from '../../../src/retailIntegration/enums';
|
|
10
|
+
import {
|
|
11
|
+
RETAIL_EVENT_ID_MAX_LENGTH,
|
|
12
|
+
RETAIL_LIST_LIMIT_MAX,
|
|
13
|
+
RETAIL_LIST_LIMIT_MIN,
|
|
14
|
+
RETAIL_TENANT_ID_PATTERN,
|
|
15
|
+
} from '../../../src/retailIntegration/constants/retailIntegrationLimits';
|
|
16
|
+
|
|
17
|
+
describe('IsIsoDateTimeWithZone', () => {
|
|
18
|
+
const validator = new IsIsoDateTimeWithZone();
|
|
19
|
+
|
|
20
|
+
it.each([
|
|
21
|
+
'2026-08-17T20:32:05Z',
|
|
22
|
+
'2026-08-17T20:32:05.123Z',
|
|
23
|
+
'2026-08-17T20:32:05-06:00',
|
|
24
|
+
'2026-08-17T20:32:05+05:30',
|
|
25
|
+
])('acepta %s', (value) => {
|
|
26
|
+
expect(validator.validate(value)).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it.each([
|
|
30
|
+
['sin zona', '2026-08-17T20:32:05'],
|
|
31
|
+
['solo fecha', '2026-08-17'],
|
|
32
|
+
['sin segundos', '2026-08-17T20:32Z'],
|
|
33
|
+
['mes inválido', '2026-13-01T00:00:00Z'],
|
|
34
|
+
['hora inválida', '2026-08-17T25:00:00Z'],
|
|
35
|
+
['31 de febrero', '2026-02-31T00:00:00Z'],
|
|
36
|
+
['31 de abril', '2026-04-31T10:00:00-06:00'],
|
|
37
|
+
['texto', 'ayer'],
|
|
38
|
+
['vacío', ''],
|
|
39
|
+
['espacios', ' '],
|
|
40
|
+
])('rechaza %s', (_label, value) => {
|
|
41
|
+
expect(validator.validate(value)).toBe(false);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it.each([null, undefined, 1786998725000, {}, []])('rechaza tipos que no son string: %p', (value) => {
|
|
45
|
+
expect(validator.validate(value)).toBe(false);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('explica el formato esperado en el mensaje', () => {
|
|
49
|
+
expect(validator.defaultMessage()).toContain('ISO-8601 con zona');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
describe('enums de retailIntegration', () => {
|
|
54
|
+
it('los resultados son los de la doc', () => {
|
|
55
|
+
expect(Object.values(RetailEventResultEnum)).toEqual(['APPLIED', 'NOOP', 'REJECTED']);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('los eventType por ruta son los de la doc', () => {
|
|
59
|
+
expect(Object.values(StoreEventTypeEnum)).toEqual(['StoreCreatedV1', 'StoreUpdatedV1', 'StoreStatusChangedV1']);
|
|
60
|
+
expect(Object.values(ProductEventTypeEnum)).toEqual(['ProductCreatedV1', 'ProductUpdatedV1', 'ProductStatusChangedV1']);
|
|
61
|
+
expect(Object.values(InventoryEventTypeEnum)).toEqual(['InventoryMovementV1']);
|
|
62
|
+
expect(Object.values(RetailUserEventTypeEnum)).toEqual([
|
|
63
|
+
'RetailUserCreatedV1',
|
|
64
|
+
'RetailUserUpdatedV1',
|
|
65
|
+
'RetailUserTransferredV1',
|
|
66
|
+
'RetailUserStatusChangedV1',
|
|
67
|
+
]);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
describe('límites de retailIntegration', () => {
|
|
72
|
+
it('fija los topes del contrato', () => {
|
|
73
|
+
expect(RETAIL_EVENT_ID_MAX_LENGTH).toBe(1024);
|
|
74
|
+
expect(RETAIL_LIST_LIMIT_MIN).toBe(1);
|
|
75
|
+
expect(RETAIL_LIST_LIMIT_MAX).toBe(200);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('el patrón de tenantId acepta slugs y rechaza separadores de ruta', () => {
|
|
79
|
+
expect(RETAIL_TENANT_ID_PATTERN.test('surekeep')).toBe(true);
|
|
80
|
+
expect(RETAIL_TENANT_ID_PATTERN.test('tenant_2-a')).toBe(true);
|
|
81
|
+
expect(RETAIL_TENANT_ID_PATTERN.test('sure/keep')).toBe(false);
|
|
82
|
+
expect(RETAIL_TENANT_ID_PATTERN.test('')).toBe(false);
|
|
83
|
+
expect(RETAIL_TENANT_ID_PATTERN.test('a'.repeat(65))).toBe(false);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import { ReceiveStoreEventRequest } from '../../../src/retailIntegration/dtos/ReceiveStoreEventRequest';
|
|
5
|
+
import { ReceiveRetailUserEventRequest } from '../../../src/retailIntegration/dtos/ReceiveRetailUserEventRequest';
|
|
6
|
+
import { ReceiveProductEventRequest } from '../../../src/retailIntegration/dtos/ReceiveProductEventRequest';
|
|
7
|
+
import { ReceiveInventoryEventRequest } from '../../../src/retailIntegration/dtos/ReceiveInventoryEventRequest';
|
|
8
|
+
|
|
9
|
+
const base = {
|
|
10
|
+
eventId: 'evt_01J8ZA1B2C3D4E5F6G7H8J9K0L',
|
|
11
|
+
occurredAt: '2026-08-01T15:00:00Z',
|
|
12
|
+
payload: { storeId: '12', name: 'Sucursal Centro' },
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
async function propertiesWithErrors(cls: new () => object, plain: Record<string, unknown>): Promise<string[]> {
|
|
16
|
+
const errors = await validate(plainToInstance(cls, plain));
|
|
17
|
+
return errors.map((error) => error.property);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
describe('DTOs de entrada de los webhooks', () => {
|
|
21
|
+
it.each([
|
|
22
|
+
[ReceiveStoreEventRequest, 'StoreStatusChangedV1'],
|
|
23
|
+
[ReceiveRetailUserEventRequest, 'RetailUserTransferredV1'],
|
|
24
|
+
[ReceiveProductEventRequest, 'ProductCreatedV1'],
|
|
25
|
+
[ReceiveInventoryEventRequest, 'InventoryMovementV1'],
|
|
26
|
+
])('%p acepta un sobre válido con %s', async (cls, eventType) => {
|
|
27
|
+
expect(await propertiesWithErrors(cls, { ...base, eventType })).toEqual([]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it.each([
|
|
31
|
+
[ReceiveStoreEventRequest, 'RetailUserCreatedV1'],
|
|
32
|
+
[ReceiveRetailUserEventRequest, 'StoreCreatedV1'],
|
|
33
|
+
[ReceiveProductEventRequest, 'InventoryMovementV1'],
|
|
34
|
+
[ReceiveInventoryEventRequest, 'ProductUpdatedV1'],
|
|
35
|
+
])('%p rechaza el eventType %s de otra ruta', async (cls, eventType) => {
|
|
36
|
+
expect(await propertiesWithErrors(cls, { ...base, eventType })).toEqual(['eventType']);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('eventId', () => {
|
|
40
|
+
const valid = { ...base, eventType: 'StoreCreatedV1' };
|
|
41
|
+
|
|
42
|
+
it('acepta 1024 caracteres', async () => {
|
|
43
|
+
expect(await propertiesWithErrors(ReceiveStoreEventRequest, { ...valid, eventId: 'e'.repeat(1024) })).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it.each([
|
|
47
|
+
['ausente', undefined],
|
|
48
|
+
['vacío', ''],
|
|
49
|
+
['solo espacios', ' '],
|
|
50
|
+
['número', 123],
|
|
51
|
+
['1025 caracteres', 'e'.repeat(1025)],
|
|
52
|
+
])('rechaza %s', async (_label, eventId) => {
|
|
53
|
+
expect(await propertiesWithErrors(ReceiveStoreEventRequest, { ...valid, eventId })).toEqual(['eventId']);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('occurredAt', () => {
|
|
58
|
+
const valid = { ...base, eventType: 'StoreCreatedV1' };
|
|
59
|
+
|
|
60
|
+
it.each([
|
|
61
|
+
['sin zona', '2026-08-01T15:00:00'],
|
|
62
|
+
['ausente', undefined],
|
|
63
|
+
['texto', 'hoy'],
|
|
64
|
+
])('rechaza %s', async (_label, occurredAt) => {
|
|
65
|
+
expect(await propertiesWithErrors(ReceiveStoreEventRequest, { ...valid, occurredAt })).toEqual(['occurredAt']);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('acepta un offset', async () => {
|
|
69
|
+
expect(await propertiesWithErrors(ReceiveStoreEventRequest, { ...valid, occurredAt: '2026-08-01T09:00:00-06:00' })).toEqual([]);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('payload', () => {
|
|
74
|
+
const valid = { ...base, eventType: 'StoreCreatedV1' };
|
|
75
|
+
|
|
76
|
+
it.each([
|
|
77
|
+
['ausente', undefined],
|
|
78
|
+
['null', null],
|
|
79
|
+
['arreglo', [1, 2]],
|
|
80
|
+
['string', 'tienda'],
|
|
81
|
+
])('rechaza %s', async (_label, payload) => {
|
|
82
|
+
expect(await propertiesWithErrors(ReceiveStoreEventRequest, { ...valid, payload })).toEqual(['payload']);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('no valida el contenido del payload', async () => {
|
|
86
|
+
expect(await propertiesWithErrors(ReceiveStoreEventRequest, { ...valid, payload: { cualquierCosa: [1, { x: null }] } })).toEqual([]);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('reporta todos los campos que faltan en un sobre vacío', async () => {
|
|
91
|
+
expect((await propertiesWithErrors(ReceiveStoreEventRequest, {})).sort()).toEqual(['eventId', 'eventType', 'occurredAt', 'payload']);
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import {
|
|
5
|
+
GetRetailInventoryRequest,
|
|
6
|
+
ListRetailCatalogRequest,
|
|
7
|
+
ListRetailStoresRequest,
|
|
8
|
+
ListRetailUsersRequest,
|
|
9
|
+
RegisterRetailSaleRequest,
|
|
10
|
+
} from '../../../src/retailIntegration';
|
|
11
|
+
import { RetailIntegration } from '../../../src';
|
|
12
|
+
|
|
13
|
+
async function propertiesWithErrors(cls: new () => object, plain: Record<string, unknown>): Promise<string[]> {
|
|
14
|
+
const errors = await validate(plainToInstance(cls, plain));
|
|
15
|
+
return errors.map((error) => error.property);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('DTOs de salida hacia el retailer', () => {
|
|
19
|
+
describe.each([ListRetailStoresRequest, ListRetailCatalogRequest, ListRetailUsersRequest])('%p (paginada)', (cls) => {
|
|
20
|
+
it('acepta solo tenantId', async () => {
|
|
21
|
+
expect(await propertiesWithErrors(cls, { tenantId: 'surekeep' })).toEqual([]);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('convierte limit de string a número', async () => {
|
|
25
|
+
const dto = plainToInstance(cls, { tenantId: 'surekeep', limit: '50' }) as { limit?: number };
|
|
26
|
+
expect(dto.limit).toBe(50);
|
|
27
|
+
expect(await validate(dto)).toEqual([]);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it.each(['0', '201', 'abc', '1.5', ''])('rechaza limit=%p', async (limit) => {
|
|
31
|
+
expect(await propertiesWithErrors(cls, { tenantId: 'surekeep', limit })).toEqual(['limit']);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('acepta nextToken opaco y rechaza nextToken vacío', async () => {
|
|
35
|
+
expect(await propertiesWithErrors(cls, { tenantId: 'surekeep', nextToken: 'eyJpZCI6MTQwMH0' })).toEqual([]);
|
|
36
|
+
expect(await propertiesWithErrors(cls, { tenantId: 'surekeep', nextToken: '' })).toEqual(['nextToken']);
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it.each([
|
|
41
|
+
['ausente', undefined],
|
|
42
|
+
['con diagonal', 'sure/keep'],
|
|
43
|
+
['vacío', ''],
|
|
44
|
+
])('rechaza tenantId %s', async (_label, tenantId) => {
|
|
45
|
+
expect(await propertiesWithErrors(ListRetailStoresRequest, { tenantId })).toEqual(['tenantId']);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('inventario exige storeId', async () => {
|
|
49
|
+
expect(await propertiesWithErrors(GetRetailInventoryRequest, { tenantId: 'surekeep', storeId: '12' })).toEqual([]);
|
|
50
|
+
expect(await propertiesWithErrors(GetRetailInventoryRequest, { tenantId: 'surekeep' })).toEqual(['storeId']);
|
|
51
|
+
expect(await propertiesWithErrors(GetRetailInventoryRequest, { tenantId: 'surekeep', storeId: ' ' })).toEqual(['storeId']);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('usuarios acepta storeId opcional', async () => {
|
|
55
|
+
expect(await propertiesWithErrors(ListRetailUsersRequest, { tenantId: 'surekeep', storeId: '12' })).toEqual([]);
|
|
56
|
+
expect(await propertiesWithErrors(ListRetailUsersRequest, { tenantId: 'surekeep', storeId: '' })).toEqual(['storeId']);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('venta solo valida tenantId', async () => {
|
|
60
|
+
expect(await propertiesWithErrors(RegisterRetailSaleRequest, { tenantId: 'surekeep' })).toEqual([]);
|
|
61
|
+
expect(await propertiesWithErrors(RegisterRetailSaleRequest, {})).toEqual(['tenantId']);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('el módulo se expone en la raíz como RetailIntegration', () => {
|
|
65
|
+
expect(RetailIntegration.ListRetailStoresRequest).toBe(ListRetailStoresRequest);
|
|
66
|
+
expect(RetailIntegration.ReceiveStoreEventRequest).toBeDefined();
|
|
67
|
+
expect(RetailIntegration.RetailEventResultEnum.APPLIED).toBe('APPLIED');
|
|
68
|
+
});
|
|
69
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import {
|
|
3
|
+
RetailCurrencyEnum,
|
|
4
|
+
RetailFinancierEnum,
|
|
5
|
+
RetailLinePaymentTypeEnum,
|
|
6
|
+
RetailMdmProviderEnum,
|
|
7
|
+
RetailPaymentMethodEnum,
|
|
8
|
+
RetailPieceReasonEnum,
|
|
9
|
+
RetailPieceStatusEnum,
|
|
10
|
+
RetailProductCategoryEnum,
|
|
11
|
+
RetailProductStatusEnum,
|
|
12
|
+
RetailProductTierEnum,
|
|
13
|
+
RetailSaleFinancierEnum,
|
|
14
|
+
RetailSaleTypeEnum,
|
|
15
|
+
RetailStoreStatusEnum,
|
|
16
|
+
RetailTrackingModeEnum,
|
|
17
|
+
RetailUserAccessStatusEnum,
|
|
18
|
+
RetailUserRoleEnum,
|
|
19
|
+
} from '../../../src/retailIntegration';
|
|
20
|
+
|
|
21
|
+
describe('enums de los objetos del retailer', () => {
|
|
22
|
+
it.each([
|
|
23
|
+
[RetailStoreStatusEnum, ['ACTIVE', 'SUSPENDED', 'INACTIVE']],
|
|
24
|
+
[RetailProductCategoryEnum, ['PHONE', 'MODEM', 'ACCESSORY', 'SIM']],
|
|
25
|
+
[RetailTrackingModeEnum, ['IMEI', 'SERIAL', 'QUANTITY']],
|
|
26
|
+
[RetailProductTierEnum, ['LOW', 'MID', 'HIGH', 'PREMIUM']],
|
|
27
|
+
[RetailCurrencyEnum, ['MXN', 'USD']],
|
|
28
|
+
[RetailFinancierEnum, ['SUREKEEP', 'PAYJOY', 'CREDIYA', 'LESPAGO', 'INNOVA']],
|
|
29
|
+
[RetailMdmProviderEnum, ['TRUSTONIC', 'DATACULTR']],
|
|
30
|
+
[RetailProductStatusEnum, ['ACTIVE', 'INACTIVE', 'DISCONTINUED']],
|
|
31
|
+
[RetailPieceStatusEnum, ['AVAILABLE', 'IN_TRANSIT', 'SOLD', 'DAMAGED']],
|
|
32
|
+
[RetailPieceReasonEnum, ['WARRANTY', 'DAMAGED_RETURN', 'SHRINKAGE']],
|
|
33
|
+
[RetailUserRoleEnum, ['SELLER', 'STORE_MANAGER', 'RETAILER_ADMIN', 'COLLECTION_AGENT']],
|
|
34
|
+
[RetailUserAccessStatusEnum, ['ACTIVE', 'SUSPENDED', 'INACTIVE']],
|
|
35
|
+
[RetailSaleTypeEnum, ['CASH', 'CREDIT', 'EXTERNAL_REFERRAL']],
|
|
36
|
+
[RetailSaleFinancierEnum, ['NONE', 'SUREKEEP', 'PAYJOY', 'CREDIYA', 'LESPAGO', 'INNOVA']],
|
|
37
|
+
[RetailPaymentMethodEnum, ['CASH', 'CARD', 'SPEI']],
|
|
38
|
+
[RetailLinePaymentTypeEnum, ['CASH', 'CREDIT']],
|
|
39
|
+
])('%p trae exactamente los valores del contrato', (enumObject, values) => {
|
|
40
|
+
expect(Object.values(enumObject)).toEqual(values);
|
|
41
|
+
});
|
|
42
|
+
});
|
package/bin/index.d.ts
CHANGED
|
@@ -98,6 +98,7 @@ export * as RetailCards from './retailCards';
|
|
|
98
98
|
export * as RetailCustomer from './retailCustomer';
|
|
99
99
|
export * as RetailWizard from './retailWizard';
|
|
100
100
|
export * as RetailPromotions from './retailPromotions';
|
|
101
|
+
export * as RetailIntegration from './retailIntegration';
|
|
101
102
|
export * as DatalakeQuery from './datalakeQuery';
|
|
102
103
|
export * as LoanConfig from './loanConfig';
|
|
103
104
|
export * as Shortlink from './shortlink';
|
package/bin/index.js
CHANGED
|
@@ -38,7 +38,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
38
38
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
39
|
exports.IssuanceBusiness = exports.Blacklist = exports.CentralPayments = exports.Helpdesk = exports.FiadoApiResponse = exports.Auth = exports.LegalDocumentsBusiness = exports.Role = exports.STPAccount = exports.RiskProfile = exports.FraudPreventionEngine = exports.BBVARst = exports.Stp = exports.BenefitCenter = exports.BankAccount = exports.P2pContact = exports.CreditContract = exports.Contract = exports.ProductCatalog = exports.ContactInfo = exports.TransactionAnalytics = exports.Transaction = exports.TransactionProcessor = exports.GenericMessage = exports.EventBridgeMessage = exports.SessionActivity = exports.NotificationMessages = exports.ServicePayment = exports.Header = exports.Identity = exports.UserTags = exports.Group = exports.File = exports.ExchangeRate = exports.Directory = exports.Currency = exports.Country = exports.Card = exports.Authentication = exports.AppContent = exports.App = exports.Offices = exports.Places = exports.Address = exports.Beneficiary = exports.Activity = exports.Biometrics = exports.MetamapConnector = exports.Account = exports.Crypto = void 0;
|
|
40
40
|
exports.RetailPromotions = exports.RetailWizard = exports.RetailCustomer = exports.RetailCards = exports.RetailCatalog = exports.RetailCommission = exports.RetailOrg = exports.EmailVerification = exports.NetworkConnector = exports.Modelias = exports.TotpSecurity = exports.Passport = exports.WalletFunding = exports.Remittance = exports.PlatformRbac = exports.CognitoBackofficeConnector = exports.WhatsappConnector = exports.TwilioConnector = exports.MessagesConnector = exports.Mdm = exports.MilestoneBusiness = exports.CirculoCredito = exports.CreditStatements = exports.Sentry = exports.AiEngine = exports.Funnel = exports.TeamsConnector = exports.PlatformErrorEvents = exports.CustomerFile = exports.CreditBackoffice = exports.CreditDashboard = exports.CreditEngine = exports.Credit = exports.ComissionBusiness = exports.ReferralBusiness = exports.ZendeskMessaging = exports.NotificationWS = exports.Event = exports.PayrollBusiness = exports.Cnbv = exports.DirectorySetting = exports.InvoiceCollector = exports.Collector = exports.Pricelist = exports.Company = exports.Services = exports.AccountIssuanceBusiness = exports.AppSelectionData = exports.Device = exports.Observations = void 0;
|
|
41
|
-
exports.FileStorage = exports.MoneyTransfer = exports.RetailLoan = exports.Membership = exports.WebhookBusiness = exports.PeopleBusiness = exports.UserConfirmations = exports.Collection = exports.Shipping = exports.PhoneSales = exports.Onboarding = exports.Kyc = exports.LoanScoring = exports.LoanCredit = exports.LoanCollectorAssignment = exports.LoanOfferings = exports.Shortlink = exports.LoanConfig = exports.DatalakeQuery = void 0;
|
|
41
|
+
exports.FileStorage = exports.MoneyTransfer = exports.RetailLoan = exports.Membership = exports.WebhookBusiness = exports.PeopleBusiness = exports.UserConfirmations = exports.Collection = exports.Shipping = exports.PhoneSales = exports.Onboarding = exports.Kyc = exports.LoanScoring = exports.LoanCredit = exports.LoanCollectorAssignment = exports.LoanOfferings = exports.Shortlink = exports.LoanConfig = exports.DatalakeQuery = exports.RetailIntegration = void 0;
|
|
42
42
|
exports.Crypto = __importStar(require("./crypto"));
|
|
43
43
|
exports.Account = __importStar(require("./account"));
|
|
44
44
|
exports.MetamapConnector = __importStar(require("./metamapConnector"));
|
|
@@ -166,6 +166,8 @@ exports.RetailWizard = __importStar(require("./retailWizard"));
|
|
|
166
166
|
// RetailPromotions: DTOs/enums de retail-promotions-business (promos de venta, códigos de descuento y
|
|
167
167
|
// cupones de VentasLuga). Porcentajes en puntos base, dinero en centavos.
|
|
168
168
|
exports.RetailPromotions = __importStar(require("./retailPromotions"));
|
|
169
|
+
// RetailIntegration: DTOs del retail-integration-connector (webhooks del retailer y salida hacia su sistema).
|
|
170
|
+
exports.RetailIntegration = __importStar(require("./retailIntegration"));
|
|
169
171
|
exports.DatalakeQuery = __importStar(require("./datalakeQuery"));
|
|
170
172
|
// LoanConfig: DTOs/enums del lambda loan-config-business (comp 09 — parámetros operativos del SOFOM).
|
|
171
173
|
exports.LoanConfig = __importStar(require("./loanConfig"));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { InStorePaymentMethodEnum } from '../../enums/InStorePaymentMethodEnum';
|
|
2
|
+
import { LoanCustomerPaymentTypeEnum } from '../../enums/LoanCustomerPaymentTypeEnum';
|
|
3
|
+
import { InStorePaymentDetail } from './InStorePaymentDetail';
|
|
4
|
+
/** Body de `POST /seller/credits/{creditId}/payments`: el vendedor anota un pago recibido en tienda. */
|
|
5
|
+
export declare class CreateSellerPaymentRequest {
|
|
6
|
+
type: LoanCustomerPaymentTypeEnum;
|
|
7
|
+
/** El monto que vio el vendedor en las opciones; distinto al de hoy → 409 CUSTOMER_PAYMENT_AMOUNT_CHANGED. */
|
|
8
|
+
expectedAmountCents: number;
|
|
9
|
+
/** Solo ADVANCE: cuántas cuotas adelanta. */
|
|
10
|
+
installmentCount?: number;
|
|
11
|
+
method: InStorePaymentMethodEnum;
|
|
12
|
+
/** Tarjeta: `cardLast4` + `authCode`; SPEI: `speiTrackingKey`; efectivo: sin detalle. */
|
|
13
|
+
detail?: InStorePaymentDetail;
|
|
14
|
+
idempotencyKey: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
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.CreateSellerPaymentRequest = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const InStorePaymentMethodEnum_1 = require("../../enums/InStorePaymentMethodEnum");
|
|
16
|
+
const LoanCustomerPaymentTypeEnum_1 = require("../../enums/LoanCustomerPaymentTypeEnum");
|
|
17
|
+
const InStorePaymentDetail_1 = require("./InStorePaymentDetail");
|
|
18
|
+
/** Body de `POST /seller/credits/{creditId}/payments`: el vendedor anota un pago recibido en tienda. */
|
|
19
|
+
class CreateSellerPaymentRequest {
|
|
20
|
+
}
|
|
21
|
+
exports.CreateSellerPaymentRequest = CreateSellerPaymentRequest;
|
|
22
|
+
__decorate([
|
|
23
|
+
(0, class_transformer_1.Expose)(),
|
|
24
|
+
(0, class_validator_1.IsEnum)(LoanCustomerPaymentTypeEnum_1.LoanCustomerPaymentTypeEnum),
|
|
25
|
+
__metadata("design:type", String)
|
|
26
|
+
], CreateSellerPaymentRequest.prototype, "type", void 0);
|
|
27
|
+
__decorate([
|
|
28
|
+
(0, class_transformer_1.Expose)(),
|
|
29
|
+
(0, class_validator_1.IsInt)(),
|
|
30
|
+
(0, class_validator_1.Min)(1),
|
|
31
|
+
__metadata("design:type", Number)
|
|
32
|
+
], CreateSellerPaymentRequest.prototype, "expectedAmountCents", void 0);
|
|
33
|
+
__decorate([
|
|
34
|
+
(0, class_transformer_1.Expose)(),
|
|
35
|
+
(0, class_validator_1.IsOptional)(),
|
|
36
|
+
(0, class_validator_1.IsInt)(),
|
|
37
|
+
(0, class_validator_1.Min)(2),
|
|
38
|
+
__metadata("design:type", Number)
|
|
39
|
+
], CreateSellerPaymentRequest.prototype, "installmentCount", void 0);
|
|
40
|
+
__decorate([
|
|
41
|
+
(0, class_transformer_1.Expose)(),
|
|
42
|
+
(0, class_validator_1.IsEnum)(InStorePaymentMethodEnum_1.InStorePaymentMethodEnum),
|
|
43
|
+
__metadata("design:type", String)
|
|
44
|
+
], CreateSellerPaymentRequest.prototype, "method", void 0);
|
|
45
|
+
__decorate([
|
|
46
|
+
(0, class_transformer_1.Expose)(),
|
|
47
|
+
(0, class_validator_1.IsOptional)(),
|
|
48
|
+
(0, class_validator_1.ValidateNested)(),
|
|
49
|
+
(0, class_transformer_1.Type)(() => InStorePaymentDetail_1.InStorePaymentDetail),
|
|
50
|
+
__metadata("design:type", InStorePaymentDetail_1.InStorePaymentDetail)
|
|
51
|
+
], CreateSellerPaymentRequest.prototype, "detail", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
(0, class_transformer_1.Expose)(),
|
|
54
|
+
(0, class_validator_1.IsUUID)(),
|
|
55
|
+
__metadata("design:type", String)
|
|
56
|
+
], CreateSellerPaymentRequest.prototype, "idempotencyKey", void 0);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dato de la forma de pago anotada en tienda; solo valida la forma, nunca lleva CLABE.
|
|
3
|
+
* Qué campo exige cada método lo decide loan-credit (400 INVALID_PAYMENT_DETAIL).
|
|
4
|
+
*/
|
|
5
|
+
export declare class InStorePaymentDetail {
|
|
6
|
+
/** Tarjeta: últimos 4 dígitos. */
|
|
7
|
+
cardLast4?: string;
|
|
8
|
+
/** Tarjeta: número de autorización del voucher. */
|
|
9
|
+
authCode?: string;
|
|
10
|
+
/** SPEI: clave de rastreo. */
|
|
11
|
+
speiTrackingKey?: string;
|
|
12
|
+
}
|