@fiado/type-kit 3.328.0 → 3.329.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/_test_/unit/loanCredit/dtos/loanDeviceContract.test.ts +283 -0
  2. package/bin/loanCredit/constants/LoanDeviceBatchLimits.d.ts +2 -0
  3. package/bin/loanCredit/constants/LoanDeviceBatchLimits.js +5 -0
  4. package/bin/loanCredit/dtos/LoanDeviceCreditRefItem.d.ts +4 -0
  5. package/bin/{retailWizard/dtos/requests/MarkPcfCardDeliveredRequest.js → loanCredit/dtos/LoanDeviceCreditRefItem.js} +6 -6
  6. package/bin/loanCredit/dtos/LoanDeviceEnrollItem.d.ts +11 -0
  7. package/bin/loanCredit/dtos/LoanDeviceEnrollItem.js +62 -0
  8. package/bin/loanCredit/dtos/LoanDeviceManualLockItem.d.ts +9 -0
  9. package/bin/loanCredit/dtos/LoanDeviceManualLockItem.js +37 -0
  10. package/bin/loanCredit/dtos/LoanDeviceOperationResult.d.ts +9 -0
  11. package/bin/loanCredit/dtos/LoanDeviceOperationResult.js +8 -0
  12. package/bin/loanCredit/dtos/LoanDeviceResult.d.ts +9 -0
  13. package/bin/loanCredit/dtos/LoanDeviceResult.js +7 -0
  14. package/bin/loanCredit/dtos/requests/LoanDeviceEnrollRequest.d.ts +7 -0
  15. package/bin/loanCredit/dtos/requests/LoanDeviceEnrollRequest.js +37 -0
  16. package/bin/loanCredit/dtos/requests/LoanDeviceEnrollStatusRequest.d.ts +4 -0
  17. package/bin/{retailWizard/dtos/requests/CompleteSaleRequest.js → loanCredit/dtos/requests/LoanDeviceEnrollStatusRequest.js} +12 -13
  18. package/bin/loanCredit/dtos/requests/LoanDeviceLastSeenRequest.d.ts +4 -0
  19. package/bin/{retailCards/dtos/requests/CancelCardRequest.js → loanCredit/dtos/requests/LoanDeviceLastSeenRequest.js} +14 -8
  20. package/bin/loanCredit/dtos/requests/LoanDeviceManualLockRequest.d.ts +7 -0
  21. package/bin/loanCredit/dtos/requests/LoanDeviceManualLockRequest.js +37 -0
  22. package/bin/loanCredit/dtos/requests/LoanDeviceManualUnlockRequest.d.ts +7 -0
  23. package/bin/loanCredit/dtos/requests/LoanDeviceManualUnlockRequest.js +37 -0
  24. package/bin/loanCredit/dtos/requests/LoanDeviceStatusRequest.d.ts +4 -0
  25. package/bin/{retailCards/dtos/requests/AssignCardRequest.js → loanCredit/dtos/requests/LoanDeviceStatusRequest.js} +14 -16
  26. package/bin/loanCredit/dtos/responses/LoanDeviceEnrollResponse.d.ts +5 -0
  27. package/bin/loanCredit/dtos/responses/LoanDeviceEnrollResponse.js +7 -0
  28. package/bin/loanCredit/dtos/responses/LoanDeviceEnrollResult.d.ts +7 -0
  29. package/bin/loanCredit/dtos/responses/LoanDeviceEnrollResult.js +8 -0
  30. package/bin/loanCredit/dtos/responses/LoanDeviceEnrollStatusResponse.d.ts +5 -0
  31. package/bin/loanCredit/dtos/responses/LoanDeviceEnrollStatusResponse.js +7 -0
  32. package/bin/loanCredit/dtos/responses/LoanDeviceEnrollStatusResult.d.ts +16 -0
  33. package/bin/loanCredit/dtos/responses/LoanDeviceEnrollStatusResult.js +8 -0
  34. package/bin/loanCredit/dtos/responses/LoanDeviceLastSeenResponse.d.ts +5 -0
  35. package/bin/loanCredit/dtos/responses/LoanDeviceLastSeenResponse.js +7 -0
  36. package/bin/loanCredit/dtos/responses/LoanDeviceLastSeenResult.d.ts +5 -0
  37. package/bin/loanCredit/dtos/responses/LoanDeviceLastSeenResult.js +8 -0
  38. package/bin/loanCredit/dtos/responses/LoanDeviceLockResult.d.ts +8 -0
  39. package/bin/loanCredit/dtos/responses/LoanDeviceLockResult.js +8 -0
  40. package/bin/loanCredit/dtos/responses/LoanDeviceManualLockResponse.d.ts +5 -0
  41. package/bin/loanCredit/dtos/responses/LoanDeviceManualLockResponse.js +7 -0
  42. package/bin/loanCredit/dtos/responses/LoanDeviceManualUnlockResponse.d.ts +5 -0
  43. package/bin/loanCredit/dtos/responses/LoanDeviceManualUnlockResponse.js +7 -0
  44. package/bin/loanCredit/dtos/responses/LoanDeviceStatusResponse.d.ts +5 -0
  45. package/bin/loanCredit/dtos/responses/LoanDeviceStatusResponse.js +7 -0
  46. package/bin/loanCredit/dtos/responses/LoanDeviceStatusResult.d.ts +28 -0
  47. package/bin/loanCredit/dtos/responses/LoanDeviceStatusResult.js +8 -0
  48. package/bin/loanCredit/dtos/responses/LoanDeviceUnlockResult.d.ts +8 -0
  49. package/bin/loanCredit/dtos/responses/LoanDeviceUnlockResult.js +8 -0
  50. package/bin/loanCredit/enums/LoanDeviceLockReasonEnum.d.ts +12 -0
  51. package/bin/loanCredit/enums/LoanDeviceLockReasonEnum.js +16 -0
  52. package/bin/loanCredit/enums/LoanDeviceMdmStatusEnum.d.ts +25 -0
  53. package/bin/loanCredit/enums/LoanDeviceMdmStatusEnum.js +29 -0
  54. package/bin/loanCredit/index.d.ts +34 -0
  55. package/bin/loanCredit/index.js +45 -1
  56. package/package.json +1 -1
  57. package/src/loanCredit/constants/LoanDeviceBatchLimits.ts +2 -0
  58. package/src/loanCredit/dtos/LoanDeviceCreditRefItem.ts +9 -0
  59. package/src/loanCredit/dtos/LoanDeviceEnrollItem.ts +47 -0
  60. package/src/loanCredit/dtos/LoanDeviceManualLockItem.ts +22 -0
  61. package/src/loanCredit/dtos/LoanDeviceOperationResult.ts +11 -0
  62. package/src/loanCredit/dtos/LoanDeviceResult.ts +12 -0
  63. package/src/loanCredit/dtos/requests/LoanDeviceEnrollRequest.ts +23 -0
  64. package/src/loanCredit/dtos/requests/LoanDeviceEnrollStatusRequest.ts +14 -0
  65. package/src/loanCredit/dtos/requests/LoanDeviceLastSeenRequest.ts +14 -0
  66. package/src/loanCredit/dtos/requests/LoanDeviceManualLockRequest.ts +23 -0
  67. package/src/loanCredit/dtos/requests/LoanDeviceManualUnlockRequest.ts +23 -0
  68. package/src/loanCredit/dtos/requests/LoanDeviceStatusRequest.ts +14 -0
  69. package/src/loanCredit/dtos/responses/LoanDeviceEnrollResponse.ts +6 -0
  70. package/src/loanCredit/dtos/responses/LoanDeviceEnrollResult.ts +8 -0
  71. package/src/loanCredit/dtos/responses/LoanDeviceEnrollStatusResponse.ts +6 -0
  72. package/src/loanCredit/dtos/responses/LoanDeviceEnrollStatusResult.ts +21 -0
  73. package/src/loanCredit/dtos/responses/LoanDeviceLastSeenResponse.ts +6 -0
  74. package/src/loanCredit/dtos/responses/LoanDeviceLastSeenResult.ts +6 -0
  75. package/src/loanCredit/dtos/responses/LoanDeviceLockResult.ts +10 -0
  76. package/src/loanCredit/dtos/responses/LoanDeviceManualLockResponse.ts +6 -0
  77. package/src/loanCredit/dtos/responses/LoanDeviceManualUnlockResponse.ts +6 -0
  78. package/src/loanCredit/dtos/responses/LoanDeviceStatusResponse.ts +6 -0
  79. package/src/loanCredit/dtos/responses/LoanDeviceStatusResult.ts +39 -0
  80. package/src/loanCredit/dtos/responses/LoanDeviceUnlockResult.ts +10 -0
  81. package/src/loanCredit/enums/LoanDeviceLockReasonEnum.ts +12 -0
  82. package/src/loanCredit/enums/LoanDeviceMdmStatusEnum.ts +25 -0
  83. package/src/loanCredit/index.ts +41 -0
  84. package/src/mdm/README.md +4 -10
  85. package/bin/benefitCenter/enums/BenefitFlowEnum.d.ts +0 -11
  86. package/bin/benefitCenter/enums/BenefitFlowEnum.js +0 -15
  87. package/bin/identity/enums/SelfieSourceEnum.d.ts +0 -10
  88. package/bin/identity/enums/SelfieSourceEnum.js +0 -14
  89. package/bin/loanCredit/dtos/requests/UpdateActivationChecklistRequest.d.ts +0 -11
  90. package/bin/loanCredit/dtos/requests/UpdateActivationChecklistRequest.js +0 -46
  91. package/bin/loanCredit/enums/ClientLevelEnum.d.ts +0 -11
  92. package/bin/loanCredit/enums/ClientLevelEnum.js +0 -15
  93. package/bin/retailCards/dtos/requests/AssignCardRequest.d.ts +0 -6
  94. package/bin/retailCards/dtos/requests/CancelCardRequest.d.ts +0 -5
  95. package/bin/retailCards/dtos/responses/RetailCardResponse.d.ts +0 -12
  96. package/bin/retailCards/dtos/responses/RetailCardResponse.js +0 -2
  97. package/bin/retailCards/enums/CardBatchStatusEnum.d.ts +0 -17
  98. package/bin/retailCards/enums/CardBatchStatusEnum.js +0 -21
  99. package/bin/retailCards/enums/CardCancelReasonEnum.d.ts +0 -13
  100. package/bin/retailCards/enums/CardCancelReasonEnum.js +0 -17
  101. package/bin/retailCards/enums/RetailCardStatusEnum.d.ts +0 -13
  102. package/bin/retailCards/enums/RetailCardStatusEnum.js +0 -17
  103. package/bin/retailCards/events/RetailCardAssignedV1.d.ts +0 -10
  104. package/bin/retailCards/events/RetailCardAssignedV1.js +0 -2
  105. package/bin/retailCards/events/RetailCardCancelledV1.d.ts +0 -9
  106. package/bin/retailCards/events/RetailCardCancelledV1.js +0 -2
  107. package/bin/retailCards/events/RetailCardReleasedV1.d.ts +0 -7
  108. package/bin/retailCards/events/RetailCardReleasedV1.js +0 -2
  109. package/bin/retailWizard/dtos/requests/CompleteSaleRequest.d.ts +0 -9
  110. package/bin/retailWizard/dtos/requests/MarkPcfCardDeliveredRequest.d.ts +0 -4
  111. package/bin/walletFunding/dtos/CancelFundingReferenceRequest.d.ts +0 -6
  112. package/bin/walletFunding/dtos/CancelFundingReferenceRequest.js +0 -31
  113. package/bin/walletFunding/dtos/CancelFundingReferenceResponse.d.ts +0 -7
  114. package/bin/walletFunding/dtos/CancelFundingReferenceResponse.js +0 -6
  115. package/bin/walletFunding/dtos/CancelFundingRequest.d.ts +0 -11
  116. package/bin/walletFunding/dtos/CancelFundingRequest.js +0 -33
  117. package/bin/walletFunding/dtos/CancelFundingResponse.d.ts +0 -14
  118. package/bin/walletFunding/dtos/CancelFundingResponse.js +0 -12
  119. package/bin/walletFunding/dtos/CancelWalletFundingRequest.d.ts +0 -3
  120. package/bin/walletFunding/dtos/CancelWalletFundingRequest.js +0 -21
  121. package/bin/walletFunding/dtos/CancelWalletFundingResponse.d.ts +0 -7
  122. package/bin/walletFunding/dtos/CancelWalletFundingResponse.js +0 -6
@@ -0,0 +1,283 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validate, ValidationError } from 'class-validator';
4
+ import { LoanDeviceEnrollRequest } from '../../../../src/loanCredit/dtos/requests/LoanDeviceEnrollRequest';
5
+ import { LoanDeviceEnrollStatusRequest } from '../../../../src/loanCredit/dtos/requests/LoanDeviceEnrollStatusRequest';
6
+ import { LoanDeviceLastSeenRequest } from '../../../../src/loanCredit/dtos/requests/LoanDeviceLastSeenRequest';
7
+ import { LoanDeviceStatusRequest } from '../../../../src/loanCredit/dtos/requests/LoanDeviceStatusRequest';
8
+ import { LoanDeviceManualLockRequest } from '../../../../src/loanCredit/dtos/requests/LoanDeviceManualLockRequest';
9
+ import { LoanDeviceManualUnlockRequest } from '../../../../src/loanCredit/dtos/requests/LoanDeviceManualUnlockRequest';
10
+ import { LoanDeviceLockReasonEnum } from '../../../../src/loanCredit/enums/LoanDeviceLockReasonEnum';
11
+ import { LOAN_DEVICE_MAX_BATCH } from '../../../../src/loanCredit/constants/LoanDeviceBatchLimits';
12
+
13
+ const CREDIT_ID = '5f7c8a90-1234-4abc-9def-0123456789ab';
14
+ const OTHER_CREDIT_ID = '5f7c8a90-1234-4abc-9def-0123456789ac';
15
+
16
+ /** Genera un creditId válido y distinto por índice, para armar lotes grandes. */
17
+ const creditIdAt = (index: number): string =>
18
+ `5f7c8a90-1234-4abc-9def-${index.toString(16).padStart(12, '0')}`;
19
+
20
+ /** True si el error de `property` trae ese constraint puntual (no solo "algo falló"). */
21
+ const hasConstraint = (errors: ValidationError[], property: string, constraint: string): boolean =>
22
+ errors.some(e => e.property === property && Boolean(e.constraints?.[constraint]));
23
+
24
+ const validEnrollItem = {
25
+ creditId: CREDIT_ID,
26
+ imei: '351756051523999',
27
+ productSku: 'SKU-MOTO-G54-128',
28
+ termMonths: 6,
29
+ firstDueDate: '2026-09-01',
30
+ };
31
+
32
+ const validEnroll = {
33
+ items: [validEnrollItem],
34
+ operationReference: 'enroll-2026-08-18-0001',
35
+ };
36
+
37
+ const enrollWithItems = (items: unknown[]) => ({ ...validEnroll, items });
38
+
39
+ describe('LoanDeviceEnrollRequest', () => {
40
+ it('valida happy path (0 errores)', async () => {
41
+ const dto = plainToInstance(LoanDeviceEnrollRequest, validEnroll);
42
+ const errors = await validate(dto);
43
+ expect(errors).toEqual([]);
44
+ });
45
+
46
+ it('valida con imei2 presente', async () => {
47
+ const items = [{ ...validEnrollItem, imei2: '351756051523998' }];
48
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems(items));
49
+ const errors = await validate(dto);
50
+ expect(errors).toEqual([]);
51
+ });
52
+
53
+ it('falla si items viene vacío', async () => {
54
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems([]));
55
+ const errors = await validate(dto);
56
+ expect(errors.some(e => e.property === 'items')).toBe(true);
57
+ });
58
+
59
+ it('falla si el imei tiene 14 dígitos', async () => {
60
+ const items = [{ ...validEnrollItem, imei: '35175605152399' }];
61
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems(items));
62
+ const errors = await validate(dto);
63
+ const itemsError = errors.find(e => e.property === 'items');
64
+ expect(itemsError).toBeDefined();
65
+ expect(JSON.stringify(itemsError)).toContain('imei');
66
+ });
67
+
68
+ it('falla si el imei tiene 15 caracteres pero no son dígitos', async () => {
69
+ const items = [{ ...validEnrollItem, imei: 'ABCDEFGHIJKLMNO' }];
70
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems(items));
71
+ const errors = await validate(dto);
72
+ const itemsError = errors.find(e => e.property === 'items');
73
+ expect(itemsError).toBeDefined();
74
+ expect(JSON.stringify(itemsError)).toContain('imei');
75
+ });
76
+
77
+ it('falla si el imei2 tiene 15 caracteres pero no son dígitos', async () => {
78
+ const items = [{ ...validEnrollItem, imei2: 'ABCDEFGHIJKLMNO' }];
79
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems(items));
80
+ const errors = await validate(dto);
81
+ const itemsError = errors.find(e => e.property === 'items');
82
+ expect(itemsError).toBeDefined();
83
+ expect(JSON.stringify(itemsError)).toContain('imei2');
84
+ });
85
+
86
+ it(`falla si el lote supera ${LOAN_DEVICE_MAX_BATCH} ítems`, async () => {
87
+ const items = Array.from({ length: LOAN_DEVICE_MAX_BATCH + 1 }, (_, i) => ({
88
+ ...validEnrollItem,
89
+ creditId: creditIdAt(i),
90
+ }));
91
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems(items));
92
+ const errors = await validate(dto);
93
+ expect(hasConstraint(errors, 'items', 'arrayMaxSize')).toBe(true);
94
+ });
95
+
96
+ it('falla si dos ítems traen el mismo creditId', async () => {
97
+ const items = [validEnrollItem, { ...validEnrollItem }];
98
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems(items));
99
+ const errors = await validate(dto);
100
+ expect(hasConstraint(errors, 'items', 'arrayUnique')).toBe(true);
101
+ });
102
+
103
+ it('falla si el productSku trae caracteres fuera del patrón canónico', async () => {
104
+ const items = [{ ...validEnrollItem, productSku: 'SKU MOTO_G54!' }];
105
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems(items));
106
+ const errors = await validate(dto);
107
+ const itemsError = errors.find(e => e.property === 'items');
108
+ expect(itemsError).toBeDefined();
109
+ expect(JSON.stringify(itemsError)).toContain('productSku');
110
+ });
111
+
112
+ it('falla si termMonths supera el plazo máximo', async () => {
113
+ const items = [{ ...validEnrollItem, termMonths: 9999 }];
114
+ const dto = plainToInstance(LoanDeviceEnrollRequest, enrollWithItems(items));
115
+ const errors = await validate(dto);
116
+ const itemsError = errors.find(e => e.property === 'items');
117
+ expect(itemsError).toBeDefined();
118
+ expect(JSON.stringify(itemsError)).toContain('termMonths');
119
+ });
120
+
121
+ it('falla si operationReference supera los 64 caracteres', async () => {
122
+ const dto = plainToInstance(LoanDeviceEnrollRequest, {
123
+ ...validEnroll,
124
+ operationReference: 'x'.repeat(200),
125
+ });
126
+ const errors = await validate(dto);
127
+ expect(hasConstraint(errors, 'operationReference', 'isLength')).toBe(true);
128
+ });
129
+ });
130
+
131
+ describe('LoanDeviceManualLockRequest', () => {
132
+ const validLockItem = { creditId: CREDIT_ID, reason: LoanDeviceLockReasonEnum.FRAUD };
133
+ const validLock = { items: [validLockItem], operationReference: 'lock-2026-08-18-0001' };
134
+
135
+ it('valida happy path (0 errores)', async () => {
136
+ const dto = plainToInstance(LoanDeviceManualLockRequest, validLock);
137
+ const errors = await validate(dto);
138
+ expect(errors).toEqual([]);
139
+ });
140
+
141
+ it('valida con screenMessage bien formado', async () => {
142
+ const items = [{ ...validLockItem, screenMessage: { title: 'Equipo bloqueado', content: 'Ponte al corriente.' } }];
143
+ const dto = plainToInstance(LoanDeviceManualLockRequest, { ...validLock, items });
144
+ const errors = await validate(dto);
145
+ expect(errors).toEqual([]);
146
+ });
147
+
148
+ it('falla si el screenMessage anidado es inválido', async () => {
149
+ const items = [{ ...validLockItem, screenMessage: { title: '', content: 5 } }];
150
+ const dto = plainToInstance(LoanDeviceManualLockRequest, { ...validLock, items });
151
+ const errors = await validate(dto);
152
+ const itemsError = errors.find(e => e.property === 'items');
153
+ expect(itemsError).toBeDefined();
154
+ expect(JSON.stringify(itemsError)).toContain('title');
155
+ });
156
+
157
+ it('falla si reason está fuera del enum', async () => {
158
+ const dto = plainToInstance(LoanDeviceManualLockRequest, {
159
+ items: [{ creditId: CREDIT_ID, reason: 'PORQUE_SI' }],
160
+ operationReference: 'lock-2026-08-18-0002',
161
+ });
162
+ const errors = await validate(dto);
163
+ const itemsError = errors.find(e => e.property === 'items');
164
+ expect(itemsError).toBeDefined();
165
+ expect(JSON.stringify(itemsError)).toContain('reason');
166
+ });
167
+
168
+ it(`falla si el lote supera ${LOAN_DEVICE_MAX_BATCH} ítems`, async () => {
169
+ const items = Array.from({ length: LOAN_DEVICE_MAX_BATCH + 1 }, (_, i) => ({
170
+ ...validLockItem,
171
+ creditId: creditIdAt(i),
172
+ }));
173
+ const dto = plainToInstance(LoanDeviceManualLockRequest, { ...validLock, items });
174
+ const errors = await validate(dto);
175
+ expect(hasConstraint(errors, 'items', 'arrayMaxSize')).toBe(true);
176
+ });
177
+
178
+ it('falla si dos ítems traen el mismo creditId', async () => {
179
+ const dto = plainToInstance(LoanDeviceManualLockRequest, {
180
+ ...validLock,
181
+ items: [validLockItem, { ...validLockItem }],
182
+ });
183
+ const errors = await validate(dto);
184
+ expect(hasConstraint(errors, 'items', 'arrayUnique')).toBe(true);
185
+ });
186
+
187
+ it('falla si operationReference supera los 64 caracteres', async () => {
188
+ const dto = plainToInstance(LoanDeviceManualLockRequest, {
189
+ ...validLock,
190
+ operationReference: 'x'.repeat(200),
191
+ });
192
+ const errors = await validate(dto);
193
+ expect(hasConstraint(errors, 'operationReference', 'isLength')).toBe(true);
194
+ });
195
+ });
196
+
197
+ describe('LoanDeviceManualUnlockRequest', () => {
198
+ const validUnlock = {
199
+ items: [{ creditId: CREDIT_ID }],
200
+ operationReference: 'unlock-2026-08-18-0001',
201
+ };
202
+
203
+ it('valida happy path (0 errores)', async () => {
204
+ const dto = plainToInstance(LoanDeviceManualUnlockRequest, validUnlock);
205
+ const errors = await validate(dto);
206
+ expect(errors).toEqual([]);
207
+ });
208
+
209
+ it('falla si algún creditId no es UUID', async () => {
210
+ const dto = plainToInstance(LoanDeviceManualUnlockRequest, {
211
+ ...validUnlock,
212
+ items: [{ creditId: 'no-es-uuid' }],
213
+ });
214
+ const errors = await validate(dto);
215
+ const itemsError = errors.find(e => e.property === 'items');
216
+ expect(itemsError).toBeDefined();
217
+ expect(JSON.stringify(itemsError)).toContain('creditId');
218
+ });
219
+
220
+ it(`falla si el lote supera ${LOAN_DEVICE_MAX_BATCH} ítems`, async () => {
221
+ const items = Array.from({ length: LOAN_DEVICE_MAX_BATCH + 1 }, (_, i) => ({
222
+ creditId: creditIdAt(i),
223
+ }));
224
+ const dto = plainToInstance(LoanDeviceManualUnlockRequest, { ...validUnlock, items });
225
+ const errors = await validate(dto);
226
+ expect(hasConstraint(errors, 'items', 'arrayMaxSize')).toBe(true);
227
+ });
228
+
229
+ it('falla si dos ítems traen el mismo creditId', async () => {
230
+ const dto = plainToInstance(LoanDeviceManualUnlockRequest, {
231
+ ...validUnlock,
232
+ items: [{ creditId: CREDIT_ID }, { creditId: CREDIT_ID }],
233
+ });
234
+ const errors = await validate(dto);
235
+ expect(hasConstraint(errors, 'items', 'arrayUnique')).toBe(true);
236
+ });
237
+
238
+ it('falla si operationReference supera los 64 caracteres', async () => {
239
+ const dto = plainToInstance(LoanDeviceManualUnlockRequest, {
240
+ ...validUnlock,
241
+ operationReference: 'x'.repeat(200),
242
+ });
243
+ const errors = await validate(dto);
244
+ expect(hasConstraint(errors, 'operationReference', 'isLength')).toBe(true);
245
+ });
246
+ });
247
+
248
+ describe.each([
249
+ ['LoanDeviceStatusRequest', LoanDeviceStatusRequest],
250
+ ['LoanDeviceEnrollStatusRequest', LoanDeviceEnrollStatusRequest],
251
+ ['LoanDeviceLastSeenRequest', LoanDeviceLastSeenRequest],
252
+ ] as const)('%s', (_name, RequestClass) => {
253
+ it('valida happy path (0 errores)', async () => {
254
+ const dto = plainToInstance(RequestClass, { creditIds: [CREDIT_ID, OTHER_CREDIT_ID] });
255
+ const errors = await validate(dto);
256
+ expect(errors).toEqual([]);
257
+ });
258
+
259
+ it('falla si algún creditId no es UUID', async () => {
260
+ const dto = plainToInstance(RequestClass, { creditIds: [CREDIT_ID, 'no-es-uuid'] });
261
+ const errors = await validate(dto);
262
+ expect(errors.some(e => e.property === 'creditIds')).toBe(true);
263
+ });
264
+
265
+ it('falla si creditIds viene vacío', async () => {
266
+ const dto = plainToInstance(RequestClass, { creditIds: [] });
267
+ const errors = await validate(dto);
268
+ expect(hasConstraint(errors, 'creditIds', 'arrayNotEmpty')).toBe(true);
269
+ });
270
+
271
+ it(`falla si el lote supera ${LOAN_DEVICE_MAX_BATCH} creditIds`, async () => {
272
+ const creditIds = Array.from({ length: LOAN_DEVICE_MAX_BATCH + 1 }, (_, i) => creditIdAt(i));
273
+ const dto = plainToInstance(RequestClass, { creditIds });
274
+ const errors = await validate(dto);
275
+ expect(hasConstraint(errors, 'creditIds', 'arrayMaxSize')).toBe(true);
276
+ });
277
+
278
+ it('falla si creditIds trae un id repetido', async () => {
279
+ const dto = plainToInstance(RequestClass, { creditIds: [CREDIT_ID, CREDIT_ID] });
280
+ const errors = await validate(dto);
281
+ expect(hasConstraint(errors, 'creditIds', 'arrayUnique')).toBe(true);
282
+ });
283
+ });
@@ -0,0 +1,2 @@
1
+ /** Cota de ítems por request; es el tamaño de lote del fan-out SQS de cobranza. */
2
+ export declare const LOAN_DEVICE_MAX_BATCH = 500;
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LOAN_DEVICE_MAX_BATCH = void 0;
4
+ /** Cota de ítems por request; es el tamaño de lote del fan-out SQS de cobranza. */
5
+ exports.LOAN_DEVICE_MAX_BATCH = 500;
@@ -0,0 +1,4 @@
1
+ /** Ítem que solo referencia un crédito, para las mutaciones que no necesitan más datos. */
2
+ export declare class LoanDeviceCreditRefItem {
3
+ creditId: string;
4
+ }
@@ -9,15 +9,15 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.MarkPcfCardDeliveredRequest = void 0;
12
+ exports.LoanDeviceCreditRefItem = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
- /** POST /wizard/sessions/:id/pcf-card/mark-delivered marca la tarjeta física PCF como entregada (S7). SureKeep Fase 2 — pista Retail. */
16
- class MarkPcfCardDeliveredRequest {
15
+ /** Ítem que solo referencia un crédito, para las mutaciones que no necesitan más datos. */
16
+ class LoanDeviceCreditRefItem {
17
17
  }
18
- exports.MarkPcfCardDeliveredRequest = MarkPcfCardDeliveredRequest;
18
+ exports.LoanDeviceCreditRefItem = LoanDeviceCreditRefItem;
19
19
  __decorate([
20
20
  (0, class_transformer_1.Expose)(),
21
- (0, class_validator_1.IsString)(),
21
+ (0, class_validator_1.IsUUID)(),
22
22
  __metadata("design:type", String)
23
- ], MarkPcfCardDeliveredRequest.prototype, "cardNumber", void 0);
23
+ ], LoanDeviceCreditRefItem.prototype, "creditId", void 0);
@@ -0,0 +1,11 @@
1
+ /** Ítem de enrolamiento: un crédito con el equipo que se va a enrolar en el MDM. */
2
+ export declare class LoanDeviceEnrollItem {
3
+ creditId: string;
4
+ imei: string;
5
+ /** Segundo IMEI del equipo (dual SIM), si lo tiene. */
6
+ imei2?: string;
7
+ productSku: string;
8
+ termMonths: number;
9
+ /** En modo SCHEDULED es el primer autolock. */
10
+ firstDueDate: string;
11
+ }
@@ -0,0 +1,62 @@
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.LoanDeviceEnrollItem = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const SkuPattern_1 = require("../../retailCatalog/constants/SkuPattern");
16
+ /** Charset y largo del IMEI: exactamente 15 dígitos. */
17
+ const IMEI_PATTERN = /^\d{15}$/;
18
+ /** Plazo máximo del crédito en meses. */
19
+ const MAX_TERM_MONTHS = 60;
20
+ /** Ítem de enrolamiento: un crédito con el equipo que se va a enrolar en el MDM. */
21
+ class LoanDeviceEnrollItem {
22
+ }
23
+ exports.LoanDeviceEnrollItem = LoanDeviceEnrollItem;
24
+ __decorate([
25
+ (0, class_transformer_1.Expose)(),
26
+ (0, class_validator_1.IsUUID)(),
27
+ __metadata("design:type", String)
28
+ ], LoanDeviceEnrollItem.prototype, "creditId", void 0);
29
+ __decorate([
30
+ (0, class_transformer_1.Expose)(),
31
+ (0, class_validator_1.IsString)(),
32
+ (0, class_validator_1.IsNotEmpty)(),
33
+ (0, class_validator_1.Matches)(IMEI_PATTERN, { message: 'imei admite solo 15 dígitos' }),
34
+ __metadata("design:type", String)
35
+ ], LoanDeviceEnrollItem.prototype, "imei", void 0);
36
+ __decorate([
37
+ (0, class_transformer_1.Expose)(),
38
+ (0, class_validator_1.IsOptional)(),
39
+ (0, class_validator_1.IsString)(),
40
+ (0, class_validator_1.Matches)(IMEI_PATTERN, { message: 'imei2 admite solo 15 dígitos' }),
41
+ __metadata("design:type", String)
42
+ ], LoanDeviceEnrollItem.prototype, "imei2", void 0);
43
+ __decorate([
44
+ (0, class_transformer_1.Expose)(),
45
+ (0, class_validator_1.IsString)(),
46
+ (0, class_validator_1.IsNotEmpty)(),
47
+ (0, class_validator_1.MaxLength)(64),
48
+ (0, class_validator_1.Matches)(SkuPattern_1.SKU_PATTERN, { message: 'productSku admite solo [A-Za-z0-9-]' }),
49
+ __metadata("design:type", String)
50
+ ], LoanDeviceEnrollItem.prototype, "productSku", void 0);
51
+ __decorate([
52
+ (0, class_transformer_1.Expose)(),
53
+ (0, class_validator_1.IsInt)(),
54
+ (0, class_validator_1.IsPositive)(),
55
+ (0, class_validator_1.Max)(MAX_TERM_MONTHS),
56
+ __metadata("design:type", Number)
57
+ ], LoanDeviceEnrollItem.prototype, "termMonths", void 0);
58
+ __decorate([
59
+ (0, class_transformer_1.Expose)(),
60
+ (0, class_validator_1.IsISO8601)(),
61
+ __metadata("design:type", String)
62
+ ], LoanDeviceEnrollItem.prototype, "firstDueDate", void 0);
@@ -0,0 +1,9 @@
1
+ import { LoanDeviceLockReasonEnum } from '../enums/LoanDeviceLockReasonEnum';
2
+ import { DeviceLockScreenMessage } from '../../mdm/dtos/DeviceLockScreenMessage';
3
+ /** Ítem de bloqueo manual: qué crédito se bloquea, por qué y con qué mensaje en pantalla. */
4
+ export declare class LoanDeviceManualLockItem {
5
+ creditId: string;
6
+ reason: LoanDeviceLockReasonEnum;
7
+ /** Mensaje que ve el usuario en la pantalla bloqueada; si no viene, el lambda usa el default. */
8
+ screenMessage?: DeviceLockScreenMessage;
9
+ }
@@ -0,0 +1,37 @@
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.LoanDeviceManualLockItem = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const LoanDeviceLockReasonEnum_1 = require("../enums/LoanDeviceLockReasonEnum");
16
+ const DeviceLockScreenMessage_1 = require("../../mdm/dtos/DeviceLockScreenMessage");
17
+ /** Ítem de bloqueo manual: qué crédito se bloquea, por qué y con qué mensaje en pantalla. */
18
+ class LoanDeviceManualLockItem {
19
+ }
20
+ exports.LoanDeviceManualLockItem = LoanDeviceManualLockItem;
21
+ __decorate([
22
+ (0, class_transformer_1.Expose)(),
23
+ (0, class_validator_1.IsUUID)(),
24
+ __metadata("design:type", String)
25
+ ], LoanDeviceManualLockItem.prototype, "creditId", void 0);
26
+ __decorate([
27
+ (0, class_transformer_1.Expose)(),
28
+ (0, class_validator_1.IsEnum)(LoanDeviceLockReasonEnum_1.LoanDeviceLockReasonEnum),
29
+ __metadata("design:type", String)
30
+ ], LoanDeviceManualLockItem.prototype, "reason", void 0);
31
+ __decorate([
32
+ (0, class_transformer_1.Expose)(),
33
+ (0, class_validator_1.IsOptional)(),
34
+ (0, class_validator_1.ValidateNested)(),
35
+ (0, class_transformer_1.Type)(() => DeviceLockScreenMessage_1.DeviceLockScreenMessage),
36
+ __metadata("design:type", DeviceLockScreenMessage_1.DeviceLockScreenMessage)
37
+ ], LoanDeviceManualLockItem.prototype, "screenMessage", void 0);
@@ -0,0 +1,9 @@
1
+ import { LoanDeviceResult } from './LoanDeviceResult';
2
+ /** Resultado por ítem de las mutaciones (enroll, lock, unlock), que sí llevan referencia de operación. */
3
+ export declare class LoanDeviceOperationResult extends LoanDeviceResult {
4
+ /** Referencia de la operación con la que el caller correlaciona el batch. */
5
+ operationReference: string;
6
+ /** Referencia opaca del proveedor, solo para trazabilidad de soporte.
7
+ * El avance se consulta por `creditId` en `enroll-status` (enroll) o `status` (lock/unlock). */
8
+ pollingHandle?: string;
9
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoanDeviceOperationResult = void 0;
4
+ const LoanDeviceResult_1 = require("./LoanDeviceResult");
5
+ /** Resultado por ítem de las mutaciones (enroll, lock, unlock), que sí llevan referencia de operación. */
6
+ class LoanDeviceOperationResult extends LoanDeviceResult_1.LoanDeviceResult {
7
+ }
8
+ exports.LoanDeviceOperationResult = LoanDeviceOperationResult;
@@ -0,0 +1,9 @@
1
+ import { MdmOperationStatusEnum } from '../../mdm/enums/MdmOperationStatusEnum';
2
+ import { MdmError } from '../../mdm/dtos/MdmError';
3
+ /** Base de todo resultado por ítem: un ítem puede fallar sin tumbar el batch completo. */
4
+ export declare class LoanDeviceResult {
5
+ creditId: string;
6
+ /** Solo toma SUCCESS | PENDING | ERROR; el motivo del fallo viaja en `error.code`. */
7
+ status: MdmOperationStatusEnum;
8
+ error?: MdmError;
9
+ }
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LoanDeviceResult = void 0;
4
+ /** Base de todo resultado por ítem: un ítem puede fallar sin tumbar el batch completo. */
5
+ class LoanDeviceResult {
6
+ }
7
+ exports.LoanDeviceResult = LoanDeviceResult;
@@ -0,0 +1,7 @@
1
+ import { LoanDeviceEnrollItem } from '../LoanDeviceEnrollItem';
2
+ /** Body de `POST /private/devices/enroll` (loan-credit-business). Enrola en lote. */
3
+ export declare class LoanDeviceEnrollRequest {
4
+ items: LoanDeviceEnrollItem[];
5
+ /** Referencia con la que el caller correlaciona este batch; vuelve en cada resultado. */
6
+ operationReference: string;
7
+ }
@@ -0,0 +1,37 @@
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.LoanDeviceEnrollRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const LoanDeviceEnrollItem_1 = require("../LoanDeviceEnrollItem");
16
+ const LoanDeviceBatchLimits_1 = require("../../constants/LoanDeviceBatchLimits");
17
+ /** Body de `POST /private/devices/enroll` (loan-credit-business). Enrola en lote. */
18
+ class LoanDeviceEnrollRequest {
19
+ }
20
+ exports.LoanDeviceEnrollRequest = LoanDeviceEnrollRequest;
21
+ __decorate([
22
+ (0, class_transformer_1.Expose)(),
23
+ (0, class_validator_1.IsArray)(),
24
+ (0, class_validator_1.ArrayNotEmpty)(),
25
+ (0, class_validator_1.ArrayMaxSize)(LoanDeviceBatchLimits_1.LOAN_DEVICE_MAX_BATCH),
26
+ (0, class_validator_1.ArrayUnique)((item) => item.creditId),
27
+ (0, class_validator_1.ValidateNested)({ each: true }),
28
+ (0, class_transformer_1.Type)(() => LoanDeviceEnrollItem_1.LoanDeviceEnrollItem),
29
+ __metadata("design:type", Array)
30
+ ], LoanDeviceEnrollRequest.prototype, "items", void 0);
31
+ __decorate([
32
+ (0, class_transformer_1.Expose)(),
33
+ (0, class_validator_1.IsString)(),
34
+ (0, class_validator_1.IsNotEmpty)(),
35
+ (0, class_validator_1.Length)(1, 64),
36
+ __metadata("design:type", String)
37
+ ], LoanDeviceEnrollRequest.prototype, "operationReference", void 0);
@@ -0,0 +1,4 @@
1
+ /** Body de `POST /private/devices/enroll-status` (loan-credit-business). Consulta en lote. */
2
+ export declare class LoanDeviceEnrollStatusRequest {
3
+ creditIds: string[];
4
+ }
@@ -9,21 +9,20 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.CompleteSaleRequest = void 0;
12
+ exports.LoanDeviceEnrollStatusRequest = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
- /**
16
- * POST /wizard/sessions/:id/complete-sale — cierra la venta (saga de 2 pasos, flujo 09). Exige
17
- * payment registrado (regla dura). Consume el IMEI del silo (SOLD), asigna la tarjeta PCF, persiste
18
- * la Sale con `UNIQ#FOLIO` y emite el outbox `SaleCompletedV1` en la MISMA tx. Cierra el prospecto
19
- * vinculado si lo hay. `cardNumber` = tarjeta física entregada en tienda (S7). SureKeep Fase 2 — pista Retail.
20
- */
21
- class CompleteSaleRequest {
15
+ const LoanDeviceBatchLimits_1 = require("../../constants/LoanDeviceBatchLimits");
16
+ /** Body de `POST /private/devices/enroll-status` (loan-credit-business). Consulta en lote. */
17
+ class LoanDeviceEnrollStatusRequest {
22
18
  }
23
- exports.CompleteSaleRequest = CompleteSaleRequest;
19
+ exports.LoanDeviceEnrollStatusRequest = LoanDeviceEnrollStatusRequest;
24
20
  __decorate([
25
21
  (0, class_transformer_1.Expose)(),
26
- (0, class_validator_1.IsOptional)(),
27
- (0, class_validator_1.IsString)(),
28
- __metadata("design:type", String)
29
- ], CompleteSaleRequest.prototype, "cardNumber", void 0);
22
+ (0, class_validator_1.IsArray)(),
23
+ (0, class_validator_1.ArrayNotEmpty)(),
24
+ (0, class_validator_1.ArrayMaxSize)(LoanDeviceBatchLimits_1.LOAN_DEVICE_MAX_BATCH),
25
+ (0, class_validator_1.ArrayUnique)(),
26
+ (0, class_validator_1.IsUUID)(undefined, { each: true }),
27
+ __metadata("design:type", Array)
28
+ ], LoanDeviceEnrollStatusRequest.prototype, "creditIds", void 0);
@@ -0,0 +1,4 @@
1
+ /** Body de `POST /private/devices/last-seen` (loan-credit-business). Consulta en lote. */
2
+ export declare class LoanDeviceLastSeenRequest {
3
+ creditIds: string[];
4
+ }
@@ -9,14 +9,20 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.CancelCardRequest = void 0;
12
+ exports.LoanDeviceLastSeenRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
13
14
  const class_validator_1 = require("class-validator");
14
- const CardCancelReasonEnum_1 = require("../../enums/CardCancelReasonEnum");
15
- /** Body de la cancelación (anulación) de una tarjeta física. */
16
- class CancelCardRequest {
15
+ const LoanDeviceBatchLimits_1 = require("../../constants/LoanDeviceBatchLimits");
16
+ /** Body de `POST /private/devices/last-seen` (loan-credit-business). Consulta en lote. */
17
+ class LoanDeviceLastSeenRequest {
17
18
  }
18
- exports.CancelCardRequest = CancelCardRequest;
19
+ exports.LoanDeviceLastSeenRequest = LoanDeviceLastSeenRequest;
19
20
  __decorate([
20
- (0, class_validator_1.IsEnum)(CardCancelReasonEnum_1.CardCancelReasonEnum),
21
- __metadata("design:type", String)
22
- ], CancelCardRequest.prototype, "reason", void 0);
21
+ (0, class_transformer_1.Expose)(),
22
+ (0, class_validator_1.IsArray)(),
23
+ (0, class_validator_1.ArrayNotEmpty)(),
24
+ (0, class_validator_1.ArrayMaxSize)(LoanDeviceBatchLimits_1.LOAN_DEVICE_MAX_BATCH),
25
+ (0, class_validator_1.ArrayUnique)(),
26
+ (0, class_validator_1.IsUUID)(undefined, { each: true }),
27
+ __metadata("design:type", Array)
28
+ ], LoanDeviceLastSeenRequest.prototype, "creditIds", void 0);
@@ -0,0 +1,7 @@
1
+ import { LoanDeviceManualLockItem } from '../LoanDeviceManualLockItem';
2
+ /** Body de `POST /private/devices/manual-lock` (loan-credit-business). Bloquea en lote. */
3
+ export declare class LoanDeviceManualLockRequest {
4
+ items: LoanDeviceManualLockItem[];
5
+ /** Referencia con la que el caller correlaciona este batch; vuelve en cada resultado. */
6
+ operationReference: string;
7
+ }