@fiado/type-kit 3.627.0 → 3.629.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 (212) hide show
  1. package/_test_/unit/collection/collectionCallbackRequests.test.ts +96 -0
  2. package/_test_/unit/gsfConnector/gsfMessages.test.ts +20 -0
  3. package/_test_/unit/loanCollectorAssignment/collectorAssignmentRequests.test.ts +65 -0
  4. package/_test_/unit/loanConfig/parameterWriteRequests.test.ts +62 -0
  5. package/_test_/unit/loanCredit/dtos/loanCreditInputLimits.test.ts +168 -0
  6. package/_test_/unit/loanCredit/signLoanCreditRequest.test.ts +61 -2
  7. package/_test_/unit/loanOfferings/offeringsInputRules.test.ts +254 -0
  8. package/_test_/unit/loanOfferings/promotionRequests.test.ts +1 -1
  9. package/_test_/unit/loanRetailAudit/auditInputLimits.test.ts +114 -0
  10. package/_test_/unit/loanScoring/evaluateSciRequest.test.ts +49 -0
  11. package/bin/collection/constants/CollectionResultLimits.d.ts +16 -0
  12. package/bin/collection/constants/CollectionResultLimits.js +19 -0
  13. package/bin/collection/dtos/ApplyCollectionResultRequest.d.ts +5 -0
  14. package/bin/collection/dtos/ApplyCollectionResultRequest.js +22 -0
  15. package/bin/collection/dtos/ResolvePendingChargesRequest.d.ts +2 -0
  16. package/bin/collection/dtos/ResolvePendingChargesRequest.js +9 -0
  17. package/bin/collection/index.d.ts +2 -0
  18. package/bin/collection/index.js +3 -0
  19. package/bin/collection/validators/IsCentPrecision.d.ts +11 -0
  20. package/bin/collection/validators/IsCentPrecision.js +32 -0
  21. package/bin/gsfConnector/dtos/GsfCreditTerms.d.ts +7 -2
  22. package/bin/gsfConnector/dtos/GsfCreditTerms.js +9 -0
  23. package/bin/loanCollectorAssignment/constants/CollectorAssignmentLimits.d.ts +12 -0
  24. package/bin/loanCollectorAssignment/constants/CollectorAssignmentLimits.js +15 -0
  25. package/bin/loanCollectorAssignment/dtos/requests/AutoAssignRequest.d.ts +1 -0
  26. package/bin/loanCollectorAssignment/dtos/requests/AutoAssignRequest.js +8 -0
  27. package/bin/loanCollectorAssignment/dtos/requests/ListCollectorAssignmentsRequest.d.ts +14 -0
  28. package/bin/loanCollectorAssignment/dtos/requests/ListCollectorAssignmentsRequest.js +62 -0
  29. package/bin/loanCollectorAssignment/dtos/requests/ReassignRequest.d.ts +1 -0
  30. package/bin/loanCollectorAssignment/dtos/requests/ReassignRequest.js +4 -0
  31. package/bin/loanCollectorAssignment/dtos/requests/RedistributeRequest.d.ts +1 -0
  32. package/bin/loanCollectorAssignment/dtos/requests/RedistributeRequest.js +4 -0
  33. package/bin/loanCollectorAssignment/dtos/responses/ListCollectorAssignmentsResponse.d.ts +9 -0
  34. package/bin/loanCollectorAssignment/dtos/responses/ListCollectorAssignmentsResponse.js +2 -0
  35. package/bin/loanCollectorAssignment/index.d.ts +3 -0
  36. package/bin/loanCollectorAssignment/index.js +4 -0
  37. package/bin/loanConfig/constants/ParameterRequestLimits.d.ts +8 -0
  38. package/bin/loanConfig/constants/ParameterRequestLimits.js +11 -0
  39. package/bin/loanConfig/dtos/requests/BulkGetParametersRequest.d.ts +1 -1
  40. package/bin/loanConfig/dtos/requests/BulkGetParametersRequest.js +3 -1
  41. package/bin/loanConfig/dtos/requests/BulkUpdateParametersRequest.d.ts +5 -2
  42. package/bin/loanConfig/dtos/requests/BulkUpdateParametersRequest.js +8 -4
  43. package/bin/loanConfig/dtos/requests/UpdateParameterRequest.d.ts +6 -3
  44. package/bin/loanConfig/dtos/requests/UpdateParameterRequest.js +10 -5
  45. package/bin/loanConfig/index.d.ts +1 -0
  46. package/bin/loanConfig/index.js +1 -0
  47. package/bin/loanCredit/constants/LoanInputLimits.d.ts +24 -0
  48. package/bin/loanCredit/constants/LoanInputLimits.js +27 -0
  49. package/bin/loanCredit/dtos/LoanBeneficiary.d.ts +1 -0
  50. package/bin/loanCredit/dtos/LoanBeneficiary.js +9 -0
  51. package/bin/loanCredit/dtos/LoanContractDetails.d.ts +18 -1
  52. package/bin/loanCredit/dtos/LoanContractDetails.js +2 -1
  53. package/bin/loanCredit/dtos/LoanDeviceNotifyItem.d.ts +5 -0
  54. package/bin/loanCredit/dtos/LoanDeviceNotifyItem.js +12 -3
  55. package/bin/loanCredit/dtos/RestructureTerms.d.ts +1 -1
  56. package/bin/loanCredit/dtos/RestructureTerms.js +2 -0
  57. package/bin/loanCredit/dtos/SignatureContext.d.ts +5 -1
  58. package/bin/loanCredit/dtos/requests/ActivationCheckRequest.d.ts +1 -1
  59. package/bin/loanCredit/dtos/requests/ActivationCheckRequest.js +4 -0
  60. package/bin/loanCredit/dtos/requests/BackofficeApproveRestructureRequest.js +2 -0
  61. package/bin/loanCredit/dtos/requests/BackofficeProposeRestructureRequest.js +2 -0
  62. package/bin/loanCredit/dtos/requests/BackofficeRejectRestructureRequest.js +2 -0
  63. package/bin/loanCredit/dtos/requests/BackofficeWriteOffCreditRequest.js +2 -0
  64. package/bin/loanCredit/dtos/requests/CreateCustomerPaymentRequest.d.ts +5 -0
  65. package/bin/loanCredit/dtos/requests/CreateCustomerPaymentRequest.js +6 -0
  66. package/bin/loanCredit/dtos/requests/CreateSellerPaymentRequest.d.ts +5 -0
  67. package/bin/loanCredit/dtos/requests/CreateSellerPaymentRequest.js +6 -0
  68. package/bin/loanCredit/dtos/requests/OriginateLoanCreditRequest.d.ts +1 -0
  69. package/bin/loanCredit/dtos/requests/OriginateLoanCreditRequest.js +7 -1
  70. package/bin/loanCredit/dtos/requests/SegmentFactsBatchRequest.d.ts +1 -1
  71. package/bin/loanCredit/dtos/requests/SegmentFactsBatchRequest.js +3 -1
  72. package/bin/loanCredit/dtos/requests/SignLoanCreditRequest.d.ts +2 -0
  73. package/bin/loanCredit/dtos/requests/SignLoanCreditRequest.js +3 -0
  74. package/bin/loanCredit/dtos/requests/UpsertLoanBorrowerRequest.d.ts +1 -0
  75. package/bin/loanCredit/dtos/requests/UpsertLoanBorrowerRequest.js +2 -0
  76. package/bin/loanCredit/index.d.ts +2 -0
  77. package/bin/loanCredit/index.js +2 -0
  78. package/bin/loanCredit/validators/IsContractBirthDate.d.ts +11 -0
  79. package/bin/loanCredit/validators/IsContractBirthDate.js +41 -0
  80. package/bin/loanOfferings/constants/offeringsInputLimits.d.ts +35 -0
  81. package/bin/loanOfferings/constants/offeringsInputLimits.js +38 -0
  82. package/bin/loanOfferings/dtos/requests/ChangeCreditPlanStatusRequest.d.ts +2 -0
  83. package/bin/loanOfferings/dtos/requests/ChangeCreditPlanStatusRequest.js +8 -0
  84. package/bin/loanOfferings/dtos/requests/ChangePromotionStatusRequest.js +2 -0
  85. package/bin/loanOfferings/dtos/requests/ComputeAmortizationScheduleRequest.d.ts +4 -1
  86. package/bin/loanOfferings/dtos/requests/ComputeAmortizationScheduleRequest.js +3 -1
  87. package/bin/loanOfferings/dtos/requests/ConsumePromotionRequest.d.ts +1 -0
  88. package/bin/loanOfferings/dtos/requests/ConsumePromotionRequest.js +3 -0
  89. package/bin/loanOfferings/dtos/requests/CreateCreditPlanRequest.d.ts +3 -0
  90. package/bin/loanOfferings/dtos/requests/CreateCreditPlanRequest.js +11 -2
  91. package/bin/loanOfferings/dtos/requests/CreateFinancierRequest.d.ts +5 -0
  92. package/bin/loanOfferings/dtos/requests/CreateFinancierRequest.js +11 -0
  93. package/bin/loanOfferings/dtos/requests/CreatePromotionRequest.d.ts +2 -2
  94. package/bin/loanOfferings/dtos/requests/CreatePromotionRequest.js +9 -0
  95. package/bin/loanOfferings/dtos/requests/CreateSegmentRequest.d.ts +1 -1
  96. package/bin/loanOfferings/dtos/requests/CreateSegmentRequest.js +3 -0
  97. package/bin/loanOfferings/dtos/requests/CreateStorePolicyRequest.d.ts +1 -1
  98. package/bin/loanOfferings/dtos/requests/CreateStorePolicyRequest.js +3 -0
  99. package/bin/loanOfferings/dtos/requests/ReleasePromotionRequest.d.ts +8 -0
  100. package/bin/loanOfferings/dtos/requests/ReleasePromotionRequest.js +30 -0
  101. package/bin/loanOfferings/dtos/requests/ReservePromotionBonusRequest.d.ts +1 -0
  102. package/bin/loanOfferings/dtos/requests/ReservePromotionBonusRequest.js +3 -0
  103. package/bin/loanOfferings/dtos/requests/SettlePromotionBonusRequest.d.ts +1 -0
  104. package/bin/loanOfferings/dtos/requests/SettlePromotionBonusRequest.js +3 -0
  105. package/bin/loanOfferings/dtos/requests/SimulateCreditPlanRequest.d.ts +1 -0
  106. package/bin/loanOfferings/dtos/requests/SimulateCreditPlanRequest.js +3 -0
  107. package/bin/loanOfferings/dtos/requests/UpdateCohortRequest.d.ts +3 -1
  108. package/bin/loanOfferings/dtos/requests/UpdateCohortRequest.js +5 -2
  109. package/bin/loanOfferings/dtos/requests/UpdateCreditPlanRequest.d.ts +8 -0
  110. package/bin/loanOfferings/dtos/requests/UpdateCreditPlanRequest.js +30 -12
  111. package/bin/loanOfferings/dtos/requests/UpdateFinancierRequest.d.ts +6 -0
  112. package/bin/loanOfferings/dtos/requests/UpdateFinancierRequest.js +13 -2
  113. package/bin/loanOfferings/dtos/requests/UpdatePromotionRequest.d.ts +7 -1
  114. package/bin/loanOfferings/dtos/requests/UpdatePromotionRequest.js +25 -5
  115. package/bin/loanOfferings/dtos/requests/UpdateSegmentRequest.d.ts +5 -2
  116. package/bin/loanOfferings/dtos/requests/UpdateSegmentRequest.js +12 -5
  117. package/bin/loanOfferings/dtos/requests/UpdateStorePolicyRequest.d.ts +18 -9
  118. package/bin/loanOfferings/dtos/requests/UpdateStorePolicyRequest.js +12 -4
  119. package/bin/loanOfferings/dtos/responses/ReleasePromotionResponse.d.ts +11 -0
  120. package/bin/loanOfferings/dtos/responses/ReleasePromotionResponse.js +2 -0
  121. package/bin/loanOfferings/index.d.ts +5 -0
  122. package/bin/loanOfferings/index.js +6 -0
  123. package/bin/loanOfferings/validators/IsOptionalNonNull.d.ts +9 -0
  124. package/bin/loanOfferings/validators/IsOptionalNonNull.js +14 -0
  125. package/bin/loanOfferings/validators/MaxJsonBytes.d.ts +5 -0
  126. package/bin/loanOfferings/validators/MaxJsonBytes.js +28 -0
  127. package/bin/loanRetailAudit/constants/auditInputLimits.d.ts +16 -0
  128. package/bin/loanRetailAudit/constants/auditInputLimits.js +19 -0
  129. package/bin/loanRetailAudit/dtos/AuditTrailChange.js +4 -0
  130. package/bin/loanRetailAudit/dtos/AuditTrailContextEntry.js +3 -0
  131. package/bin/loanRetailAudit/dtos/requests/CreatePiiAccessLogRequest.d.ts +7 -1
  132. package/bin/loanRetailAudit/dtos/requests/CreatePiiAccessLogRequest.js +8 -1
  133. package/bin/loanRetailAudit/events/AuditTrailRecordedV1.d.ts +1 -0
  134. package/bin/loanRetailAudit/events/AuditTrailRecordedV1.js +5 -1
  135. package/bin/loanRetailAudit/index.d.ts +2 -0
  136. package/bin/loanRetailAudit/index.js +3 -0
  137. package/bin/loanRetailAudit/validators/IsIsoDateTime.d.ts +13 -0
  138. package/bin/loanRetailAudit/validators/IsIsoDateTime.js +29 -0
  139. package/bin/loanScoring/dtos/ScoringOffer.d.ts +8 -6
  140. package/bin/loanScoring/dtos/requests/EvaluateSciRequest.d.ts +14 -3
  141. package/bin/loanScoring/dtos/requests/EvaluateSciRequest.js +15 -0
  142. package/package.json +1 -1
  143. package/src/collection/constants/CollectionResultLimits.ts +18 -0
  144. package/src/collection/dtos/ApplyCollectionResultRequest.ts +15 -8
  145. package/src/collection/dtos/ResolvePendingChargesRequest.ts +7 -4
  146. package/src/collection/index.ts +4 -0
  147. package/src/collection/validators/IsCentPrecision.ts +33 -0
  148. package/src/gsfConnector/dtos/GsfCreditTerms.ts +15 -3
  149. package/src/loanCollectorAssignment/constants/CollectorAssignmentLimits.ts +16 -0
  150. package/src/loanCollectorAssignment/dtos/requests/AutoAssignRequest.ts +13 -1
  151. package/src/loanCollectorAssignment/dtos/requests/ListCollectorAssignmentsRequest.ts +52 -0
  152. package/src/loanCollectorAssignment/dtos/requests/ReassignRequest.ts +8 -1
  153. package/src/loanCollectorAssignment/dtos/requests/RedistributeRequest.ts +8 -1
  154. package/src/loanCollectorAssignment/dtos/responses/ListCollectorAssignmentsResponse.ts +10 -0
  155. package/src/loanCollectorAssignment/index.ts +5 -0
  156. package/src/loanConfig/constants/ParameterRequestLimits.ts +11 -0
  157. package/src/loanConfig/dtos/requests/BulkGetParametersRequest.ts +4 -2
  158. package/src/loanConfig/dtos/requests/BulkUpdateParametersRequest.ts +26 -6
  159. package/src/loanConfig/dtos/requests/UpdateParameterRequest.ts +15 -7
  160. package/src/loanConfig/index.ts +1 -0
  161. package/src/loanCredit/constants/LoanInputLimits.ts +29 -0
  162. package/src/loanCredit/dtos/LoanBeneficiary.ts +11 -1
  163. package/src/loanCredit/dtos/LoanContractDetails.ts +26 -3
  164. package/src/loanCredit/dtos/LoanDeviceNotifyItem.ts +17 -3
  165. package/src/loanCredit/dtos/RestructureTerms.ts +4 -2
  166. package/src/loanCredit/dtos/SignatureContext.ts +5 -1
  167. package/src/loanCredit/dtos/requests/ActivationCheckRequest.ts +12 -2
  168. package/src/loanCredit/dtos/requests/BackofficeApproveRestructureRequest.ts +3 -1
  169. package/src/loanCredit/dtos/requests/BackofficeProposeRestructureRequest.ts +3 -1
  170. package/src/loanCredit/dtos/requests/BackofficeRejectRestructureRequest.ts +3 -1
  171. package/src/loanCredit/dtos/requests/BackofficeWriteOffCreditRequest.ts +3 -1
  172. package/src/loanCredit/dtos/requests/CreateCustomerPaymentRequest.ts +10 -1
  173. package/src/loanCredit/dtos/requests/CreateSellerPaymentRequest.ts +10 -1
  174. package/src/loanCredit/dtos/requests/OriginateLoanCreditRequest.ts +10 -1
  175. package/src/loanCredit/dtos/requests/SegmentFactsBatchRequest.ts +4 -2
  176. package/src/loanCredit/dtos/requests/SignLoanCreditRequest.ts +6 -1
  177. package/src/loanCredit/dtos/requests/UpsertLoanBorrowerRequest.ts +4 -1
  178. package/src/loanCredit/index.ts +2 -0
  179. package/src/loanCredit/validators/IsContractBirthDate.ts +41 -0
  180. package/src/loanOfferings/constants/offeringsInputLimits.ts +47 -0
  181. package/src/loanOfferings/dtos/requests/ChangeCreditPlanStatusRequest.ts +9 -1
  182. package/src/loanOfferings/dtos/requests/ChangePromotionStatusRequest.ts +3 -1
  183. package/src/loanOfferings/dtos/requests/ComputeAmortizationScheduleRequest.ts +7 -2
  184. package/src/loanOfferings/dtos/requests/ConsumePromotionRequest.ts +5 -1
  185. package/src/loanOfferings/dtos/requests/CreateCreditPlanRequest.ts +24 -2
  186. package/src/loanOfferings/dtos/requests/CreateFinancierRequest.ts +25 -0
  187. package/src/loanOfferings/dtos/requests/CreatePromotionRequest.ts +17 -2
  188. package/src/loanOfferings/dtos/requests/CreateSegmentRequest.ts +4 -1
  189. package/src/loanOfferings/dtos/requests/CreateStorePolicyRequest.ts +6 -1
  190. package/src/loanOfferings/dtos/requests/ReleasePromotionRequest.ts +16 -0
  191. package/src/loanOfferings/dtos/requests/ReservePromotionBonusRequest.ts +5 -1
  192. package/src/loanOfferings/dtos/requests/SettlePromotionBonusRequest.ts +5 -1
  193. package/src/loanOfferings/dtos/requests/SimulateCreditPlanRequest.ts +5 -1
  194. package/src/loanOfferings/dtos/requests/UpdateCohortRequest.ts +6 -3
  195. package/src/loanOfferings/dtos/requests/UpdateCreditPlanRequest.ts +43 -12
  196. package/src/loanOfferings/dtos/requests/UpdateFinancierRequest.ts +26 -2
  197. package/src/loanOfferings/dtos/requests/UpdatePromotionRequest.ts +34 -6
  198. package/src/loanOfferings/dtos/requests/UpdateSegmentRequest.ts +14 -7
  199. package/src/loanOfferings/dtos/requests/UpdateStorePolicyRequest.ts +28 -13
  200. package/src/loanOfferings/dtos/responses/ReleasePromotionResponse.ts +11 -0
  201. package/src/loanOfferings/index.ts +7 -0
  202. package/src/loanOfferings/validators/IsOptionalNonNull.ts +12 -0
  203. package/src/loanOfferings/validators/MaxJsonBytes.ts +28 -0
  204. package/src/loanRetailAudit/constants/auditInputLimits.ts +20 -0
  205. package/src/loanRetailAudit/dtos/AuditTrailChange.ts +5 -1
  206. package/src/loanRetailAudit/dtos/AuditTrailContextEntry.ts +4 -1
  207. package/src/loanRetailAudit/dtos/requests/CreatePiiAccessLogRequest.ts +20 -3
  208. package/src/loanRetailAudit/events/AuditTrailRecordedV1.ts +7 -2
  209. package/src/loanRetailAudit/index.ts +4 -0
  210. package/src/loanRetailAudit/validators/IsIsoDateTime.ts +33 -0
  211. package/src/loanScoring/dtos/ScoringOffer.ts +8 -6
  212. package/src/loanScoring/dtos/requests/EvaluateSciRequest.ts +26 -4
@@ -1,5 +1,6 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { ArrayNotEmpty, IsArray, IsEnum, IsString, ValidateNested } from 'class-validator';
2
+ import { ArrayMaxSize, ArrayNotEmpty, IsArray, IsEnum, IsString, ValidateNested } from 'class-validator';
3
+ import { BULK_GET_PARAMETERS_MAX_ITEMS } from '../../constants/ParameterRequestLimits';
3
4
  import { ParameterTypeEnum } from '../../enums/ParameterTypeEnum';
4
5
 
5
6
  export class ParameterKeyRef {
@@ -12,11 +13,12 @@ export class ParameterKeyRef {
12
13
  key!: string;
13
14
  }
14
15
 
15
- /** Body de POST /private/parameters/bulk-get — hot path para consumers (cachean 5 min). */
16
+ /** Body de POST /private/parameters/bulk-get — hot path para consumers (cachean 5 min). Hasta 100 claves. */
16
17
  export class BulkGetParametersRequest {
17
18
  @Expose()
18
19
  @IsArray()
19
20
  @ArrayNotEmpty()
21
+ @ArrayMaxSize(BULK_GET_PARAMETERS_MAX_ITEMS)
20
22
  @ValidateNested({ each: true })
21
23
  @Type(() => ParameterKeyRef)
22
24
  items!: ParameterKeyRef[];
@@ -1,7 +1,23 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { ArrayNotEmpty, IsArray, IsEnum, IsOptional, IsString, ValidateNested } from 'class-validator';
2
+ import {
3
+ ArrayMaxSize,
4
+ ArrayNotEmpty,
5
+ IsArray,
6
+ IsEnum,
7
+ IsString,
8
+ Matches,
9
+ MaxLength,
10
+ ValidateIf,
11
+ ValidateNested,
12
+ } from 'class-validator';
13
+ import {
14
+ BULK_UPDATE_PARAMETERS_MAX_ITEMS,
15
+ PARAMETER_REASON_NON_BLANK_PATTERN,
16
+ PARAMETER_REASON_MAX_LENGTH,
17
+ } from '../../constants/ParameterRequestLimits';
3
18
  import { ParameterTypeEnum } from '../../enums/ParameterTypeEnum';
4
19
 
20
+ /** Un parámetro del lote. Mismas reglas que `UpdateParameterRequest` para `value` y `reason`. */
5
21
  export class BulkUpdateParameterItem {
6
22
  @Expose()
7
23
  @IsEnum(ParameterTypeEnum)
@@ -11,22 +27,26 @@ export class BulkUpdateParameterItem {
11
27
  @IsString()
12
28
  key!: string;
13
29
 
30
+ /** Obligatorio; `null` deja el parámetro pendiente. */
14
31
  @Expose()
15
- @IsOptional()
16
- @IsString()
32
+ @ValidateIf((item: BulkUpdateParameterItem) => item.value !== null)
33
+ @IsString({ message: 'value es obligatorio: un string, o null para dejar el parámetro pendiente' })
17
34
  value!: string | null;
18
35
 
36
+ /** Obligatorio, no en blanco y de hasta 500 caracteres. */
19
37
  @Expose()
20
- @IsOptional()
21
38
  @IsString()
22
- reason?: string;
39
+ @Matches(PARAMETER_REASON_NON_BLANK_PATTERN, { message: 'reason no puede ir vacío ni en blanco' })
40
+ @MaxLength(PARAMETER_REASON_MAX_LENGTH)
41
+ reason!: string;
23
42
  }
24
43
 
25
- /** Body de POST /parameters/bulk-update — carga inicial / ajuste masivo. */
44
+ /** Body de POST /parameters/bulk-update — carga inicial / ajuste masivo. Hasta 50 parámetros. */
26
45
  export class BulkUpdateParametersRequest {
27
46
  @Expose()
28
47
  @IsArray()
29
48
  @ArrayNotEmpty()
49
+ @ArrayMaxSize(BULK_UPDATE_PARAMETERS_MAX_ITEMS)
30
50
  @ValidateNested({ each: true })
31
51
  @Type(() => BulkUpdateParameterItem)
32
52
  parameters!: BulkUpdateParameterItem[];
@@ -1,18 +1,26 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsOptional, IsString } from 'class-validator';
2
+ import { IsString, Matches, MaxLength, ValidateIf } from 'class-validator';
3
+ import {
4
+ PARAMETER_REASON_NON_BLANK_PATTERN,
5
+ PARAMETER_REASON_MAX_LENGTH,
6
+ } from '../../constants/ParameterRequestLimits';
3
7
 
4
8
  /**
5
- * Body de PUT /parameters/:paramType/:key. `value` puede ser null (parámetro pendiente).
6
- * `reason` opcional en F1; el manager lo exigirá para cambios críticos (modelo-datos §10).
9
+ * Body de PUT /parameters/:paramType/:key.
10
+ *
11
+ * - `value` es obligatorio pero puede ser `null` (parámetro pendiente). Omitirlo da 400: antes borraba
12
+ * el valor y respondía 200 (L-140).
13
+ * - `reason` es obligatorio, no en blanco y de hasta 500 caracteres (decisión D-7, L-139).
7
14
  */
8
15
  export class UpdateParameterRequest {
9
16
  @Expose()
10
- @IsOptional()
11
- @IsString()
17
+ @ValidateIf((request: UpdateParameterRequest) => request.value !== null)
18
+ @IsString({ message: 'value es obligatorio: un string, o null para dejar el parámetro pendiente' })
12
19
  value!: string | null;
13
20
 
14
21
  @Expose()
15
- @IsOptional()
16
22
  @IsString()
17
- reason?: string;
23
+ @Matches(PARAMETER_REASON_NON_BLANK_PATTERN, { message: 'reason no puede ir vacío ni en blanco' })
24
+ @MaxLength(PARAMETER_REASON_MAX_LENGTH)
25
+ reason!: string;
18
26
  }
@@ -3,6 +3,7 @@ export * from './enums/ParameterValueTypeEnum';
3
3
 
4
4
  // Constants
5
5
  export * from './constants/RecentParameterChangesLimits';
6
+ export * from './constants/ParameterRequestLimits';
6
7
 
7
8
  // Entity DTOs
8
9
  export * from './dtos/Parameter';
@@ -0,0 +1,29 @@
1
+ /** Plazo máximo de un crédito en semanas, en el alta y en la reestructura. */
2
+ export const LOAN_MAX_TERM_WEEKS = 104;
3
+
4
+ /**
5
+ * Techo técnico de un monto en centavos: 100 000 millones de centavos (1 000 millones de pesos).
6
+ *
7
+ * No es política de negocio: un equipo cuesta decenas de miles de pesos. Deja cuatro órdenes de
8
+ * margen bajo `Number.MAX_SAFE_INTEGER` para que intereses, IVA y sumas de cuotas no pierdan el centavo.
9
+ */
10
+ export const LOAN_AMOUNT_MAX_CENTS = 100_000_000_000;
11
+
12
+ /** Largo máximo de un texto libre del backoffice (motivo, justificación); igual que la cancelación. */
13
+ export const LOAN_FREE_TEXT_MAX_LENGTH = 500;
14
+
15
+ /**
16
+ * Forma aceptada de un `retailCustomerId`. Laxa a propósito: el formato lo define retail-customer
17
+ * (hoy un ULID), así que solo se rechaza lo que no puede ser un id (espacios, comas, símbolos).
18
+ */
19
+ export const RETAIL_CUSTOMER_ID_PATTERN = /^[0-9A-Za-z_-]{1,64}$/;
20
+ export const RETAIL_CUSTOMER_ID_MESSAGE = 'retailCustomerId admite letras, números, guion y guion bajo (máximo 64)';
21
+
22
+ /** CLABE interbancaria: exactamente 18 dígitos. La aplica el dominio (D9); el DTO del contrato solo acota el largo. */
23
+ export const CLABE_PATTERN = /^\d{18}$/;
24
+ export const CLABE_MESSAGE = 'La CLABE debe tener 18 dígitos';
25
+
26
+ /** Teléfono en E.164: `+`, código de país y número; 16 caracteres como máximo. */
27
+ export const E164_PHONE_PATTERN = /^\+[1-9]\d{7,14}$/;
28
+ export const E164_PHONE_MAX_LENGTH = 16;
29
+ export const E164_PHONE_MESSAGE = 'El teléfono debe ir en formato E.164 (por ejemplo +525512345678)';
@@ -1,22 +1,32 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
2
+ import { IsNotEmpty, IsOptional, IsString, MaxLength } from 'class-validator';
3
+ import { IsMxPhone } from '../../common/validators/IsMxPhone';
4
+
5
+ /** Largo máximo del nombre completo, igual que en el contrato. */
6
+ const FULL_NAME_MAX_LENGTH = 300;
7
+ /** Largo máximo del parentesco. */
8
+ const RELATIONSHIP_MAX_LENGTH = 120;
3
9
 
4
10
  /**
5
11
  * Beneficiario declarado por el acreditado (modelo-datos §5b `LoanBorrower.beneficiary`).
12
+ * Textos con tope y teléfono MX de 10 dígitos, con `+52` opcional (L-031).
6
13
  */
7
14
  export class LoanBeneficiary {
8
15
  @Expose()
9
16
  @IsString()
10
17
  @IsNotEmpty()
18
+ @MaxLength(FULL_NAME_MAX_LENGTH)
11
19
  fullName!: string;
12
20
 
13
21
  @Expose()
14
22
  @IsOptional()
15
23
  @IsString()
24
+ @MaxLength(RELATIONSHIP_MAX_LENGTH)
16
25
  relationship?: string;
17
26
 
18
27
  @Expose()
19
28
  @IsOptional()
20
29
  @IsString()
30
+ @IsMxPhone()
21
31
  phone?: string;
22
32
  }
@@ -6,7 +6,12 @@ const SHORT_TEXT = 120;
6
6
  /** Largo máximo de un texto largo del contrato (nombre, domicilio, razón social). */
7
7
  const LONG_TEXT = 300;
8
8
  /** IMEI: exactamente 15 dígitos. */
9
- import { IMEI_PATTERN } from '../../common/constants/InputPatterns';
9
+ import {
10
+ EMAIL_MAX_LENGTH,
11
+ EMAIL_MESSAGE,
12
+ EMAIL_PATTERN,
13
+ IMEI_PATTERN,
14
+ } from '../../common/constants/InputPatterns';
10
15
 
11
16
  /** Datos del acreditado tal como se imprimen en el contrato (Sección II.1). */
12
17
  export class LoanContractBorrowerDetails {
@@ -16,6 +21,10 @@ export class LoanContractBorrowerDetails {
16
21
  @MaxLength(LONG_TEXT)
17
22
  fullName: string;
18
23
 
24
+ /**
25
+ * Solo con tope de largo. retail-customer guarda el CURP de Metamap sin validar su formato, así que
26
+ * exigir `regexCurp` aquí tumbaría la firma. El formato lo revisa el dominio (loan-credit).
27
+ */
19
28
  @Expose()
20
29
  @IsString()
21
30
  @IsNotEmpty()
@@ -29,12 +38,21 @@ export class LoanContractBorrowerDetails {
29
38
  @MaxLength(LONG_TEXT)
30
39
  address: string;
31
40
 
41
+ /**
42
+ * Solo con tope de largo. El RFC de `people` solo se limpia de espacios y puede llegar en minúsculas
43
+ * o con 10 caracteres; si se rechaza, el wizard descarta todo `contractDetails` y la firma no sale.
44
+ * El formato (`RFC_PATTERN`) lo revisa el dominio.
45
+ */
32
46
  @Expose()
33
47
  @IsOptional()
34
48
  @IsString()
35
49
  @MaxLength(SHORT_TEXT)
36
50
  rfc?: string;
37
51
 
52
+ /**
53
+ * Fecha de nacimiento ya formateada para imprimir (el wizard manda `DD/MM/AAAA`). Solo con tope de
54
+ * largo: el dominio puede revisar la fecha con `isContractBirthDate` y dejarla en blanco si no cumple.
55
+ */
38
56
  @Expose()
39
57
  @IsOptional()
40
58
  @IsString()
@@ -57,7 +75,8 @@ export class LoanContractBorrowerDetails {
57
75
  @Expose()
58
76
  @IsOptional()
59
77
  @IsString()
60
- @MaxLength(LONG_TEXT)
78
+ @MaxLength(EMAIL_MAX_LENGTH)
79
+ @Matches(EMAIL_PATTERN, { message: EMAIL_MESSAGE })
61
80
  email?: string;
62
81
 
63
82
  @Expose()
@@ -131,7 +150,11 @@ export class LoanContractProviderDetails {
131
150
 
132
151
  /** Cuenta Pago Confiado del acreditado, de la que se cobra el crédito (Secciones VI y VIII). */
133
152
  export class LoanContractPcfAccountDetails {
134
- /** Tal como la tiene la cuenta; en dev puede no ser una CLABE de 18 dígitos. */
153
+ /**
154
+ * Tal como la tiene la cuenta, con tope de largo. La CLABE estricta de 18 dígitos (decisión D9) se
155
+ * aplica en el dominio: si no cumple `CLABE_PATTERN`, loan-credit deja la cuenta en blanco en el
156
+ * contrato. No se exige aquí para no rechazar la firma cuando la cuenta de dev no es una CLABE.
157
+ */
135
158
  @Expose()
136
159
  @IsString()
137
160
  @IsNotEmpty()
@@ -1,12 +1,26 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsEnum, IsNotEmpty, IsOptional, IsString, Matches, MaxLength } from 'class-validator';
2
+ import { IsEnum, IsNotEmpty, IsOptional, IsString, Matches, MaxLength, ValidateIf } from 'class-validator';
3
3
  import { DeviceNotifyIntensityEnum } from '../../mdm/enums/DeviceNotifyIntensityEnum';
4
4
  import { MdmNoticeTypeEnum } from '../../mdm/enums/MdmNoticeTypeEnum';
5
5
  import { CREDIT_ID_MESSAGE, CREDIT_ID_PATTERN } from '../constants/CreditIdPattern';
6
6
 
7
+ /** `true` si el valor viaja (ni ausente ni `null`). */
8
+ const present = (value: unknown): boolean => value !== undefined && value !== null;
9
+
10
+ /** El ítem trae un aviso por el camino legacy: `notificationCode`, o `title` junto con `content`. */
11
+ const hasLegacyNotice = (item: LoanDeviceNotifyItem): boolean =>
12
+ present(item.notificationCode) || (present(item.title) && present(item.content));
13
+
14
+ /** Mensaje cuando el ítem no trae ningún aviso. */
15
+ export const LOAN_DEVICE_NOTICE_MISSING_MESSAGE =
16
+ 'El aviso debe traer noticeType, o title y content, o notificationCode';
17
+
7
18
  /**
8
19
  * Ítem de notificación: a qué crédito se le avisa y con qué aviso.
9
20
  * El aviso viaja como `noticeType`; los tres campos de texto son el camino legacy.
21
+ *
22
+ * Cada ítem trae un aviso: `noticeType`, o `title` + `content`, o `notificationCode`. Si no trae
23
+ * ninguno, el error sale en `noticeType` (L-023).
10
24
  */
11
25
  export class LoanDeviceNotifyItem {
12
26
  @Expose()
@@ -22,8 +36,8 @@ export class LoanDeviceNotifyItem {
22
36
  * Cuando viaja, manda: los connectors ignoran `notificationCode`, `title` y `content`.
23
37
  */
24
38
  @Expose()
25
- @IsOptional()
26
- @IsEnum(MdmNoticeTypeEnum)
39
+ @ValidateIf((item: LoanDeviceNotifyItem) => present(item.noticeType) || !hasLegacyNotice(item))
40
+ @IsEnum(MdmNoticeTypeEnum, { message: LOAN_DEVICE_NOTICE_MISSING_MESSAGE })
27
41
  noticeType?: MdmNoticeTypeEnum;
28
42
 
29
43
  /** Código del catálogo de Datacultr. Camino legacy: solo se lee si no viaja `noticeType`. */
@@ -1,12 +1,14 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsInt, IsNumber, IsOptional, Min } from 'class-validator';
2
+ import { IsInt, IsNumber, IsOptional, Max, Min } from 'class-validator';
3
+ import { LOAN_MAX_TERM_WEEKS } from '../constants/LoanInputLimits';
3
4
 
4
5
  /** Términos de una reestructura: los propone el cobrador y el admin los aprueba o ajusta. */
5
6
  export class RestructureTerms {
6
- /** Plazo nuevo en semanas; no puede ser menor a las cuotas restantes. */
7
+ /** Plazo nuevo en semanas; no puede ser menor a las cuotas restantes ni pasar el techo del alta (104). */
7
8
  @Expose()
8
9
  @IsInt()
9
10
  @Min(1)
11
+ @Max(LOAN_MAX_TERM_WEEKS)
10
12
  newTermWeeks!: number;
11
13
 
12
14
  /** TNA nueva en decimal (`2.30` = 230%). */
@@ -16,7 +16,11 @@ const USER_AGENT_TEXT = 512;
16
16
  * ceremonia: la IP y el navegador son del equipo de la tienda. Nunca se loguean.
17
17
  */
18
18
  export class SignatureContext {
19
- /** IP de origen de la llamada, como la ve el API Gateway del wizard. */
19
+ /**
20
+ * IP de origen de la llamada, como la ve el API Gateway del wizard. Solo con tope de largo: sin
21
+ * `sourceIp` el wizard manda `"desconocida"`, y `@IsIP()` tumbaría la firma. El dominio decide qué
22
+ * hacer con un valor que no es IP.
23
+ */
20
24
  @Expose()
21
25
  @IsString()
22
26
  @IsNotEmpty()
@@ -1,5 +1,12 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsBoolean, IsOptional, IsString } from 'class-validator';
2
+ import { IsBoolean, IsOptional, IsString, Matches, MaxLength } from 'class-validator';
3
+ import {
4
+ IMEI_MESSAGE,
5
+ IMEI_PATTERN,
6
+ SKU_MAX_LENGTH,
7
+ SKU_MESSAGE,
8
+ SKU_PATTERN,
9
+ } from '../../../common/constants/InputPatterns';
3
10
 
4
11
  /**
5
12
  * Body de `POST /private/credits/:creditId/activate-check` (loan-credit-business — M2 §5).
@@ -35,11 +42,14 @@ export class ActivationCheckRequest {
35
42
  @Expose()
36
43
  @IsOptional()
37
44
  @IsString()
45
+ @Matches(IMEI_PATTERN, { message: IMEI_MESSAGE })
38
46
  imei?: string;
39
47
 
40
- /** SKU del producto vendido (paso 09). Lo congela el expediente MDM al enrolar. */
48
+ /** SKU del producto vendido (paso 09). Lo congela el expediente MDM al enrolar; mismas reglas que el enroll. */
41
49
  @Expose()
42
50
  @IsOptional()
43
51
  @IsString()
52
+ @MaxLength(SKU_MAX_LENGTH)
53
+ @Matches(SKU_PATTERN, { message: SKU_MESSAGE })
44
54
  productSku?: string;
45
55
  }
@@ -1,5 +1,6 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { IsOptional, IsString, MinLength, ValidateNested } from 'class-validator';
2
+ import { IsOptional, IsString, MaxLength, MinLength, ValidateNested } from 'class-validator';
3
+ import { LOAN_FREE_TEXT_MAX_LENGTH } from '../../constants/LoanInputLimits';
3
4
  import { RestructureTerms } from '../RestructureTerms';
4
5
 
5
6
  /** Body de `POST /backoffice/credits/:creditId/restructures/:restructureId/approve` (loan-credit-business). */
@@ -8,6 +9,7 @@ export class BackofficeApproveRestructureRequest {
8
9
  @Expose()
9
10
  @IsString()
10
11
  @MinLength(1)
12
+ @MaxLength(LOAN_FREE_TEXT_MAX_LENGTH)
11
13
  reason!: string;
12
14
 
13
15
  /** Términos ajustados; ausente se aprueba como se propuso. */
@@ -1,5 +1,6 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { IsDefined, IsString, MinLength, ValidateNested } from 'class-validator';
2
+ import { IsDefined, IsString, MaxLength, MinLength, ValidateNested } from 'class-validator';
3
+ import { LOAN_FREE_TEXT_MAX_LENGTH } from '../../constants/LoanInputLimits';
3
4
  import { RestructureTerms } from '../RestructureTerms';
4
5
 
5
6
  /** Body de `POST /backoffice/credits/:creditId/restructures` (loan-credit-business). */
@@ -8,6 +9,7 @@ export class BackofficeProposeRestructureRequest {
8
9
  @Expose()
9
10
  @IsString()
10
11
  @MinLength(1)
12
+ @MaxLength(LOAN_FREE_TEXT_MAX_LENGTH)
11
13
  justification!: string;
12
14
 
13
15
  @Expose()
@@ -1,5 +1,6 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsString, MinLength } from 'class-validator';
2
+ import { IsString, MaxLength, MinLength } from 'class-validator';
3
+ import { LOAN_FREE_TEXT_MAX_LENGTH } from '../../constants/LoanInputLimits';
3
4
 
4
5
  /** Body de `POST /backoffice/credits/:creditId/restructures/:restructureId/reject` (loan-credit-business). */
5
6
  export class BackofficeRejectRestructureRequest {
@@ -7,5 +8,6 @@ export class BackofficeRejectRestructureRequest {
7
8
  @Expose()
8
9
  @IsString()
9
10
  @MinLength(1)
11
+ @MaxLength(LOAN_FREE_TEXT_MAX_LENGTH)
10
12
  reason!: string;
11
13
  }
@@ -1,5 +1,6 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { IsOptional, IsString, ValidateNested } from 'class-validator';
2
+ import { IsOptional, IsString, MaxLength, ValidateNested } from 'class-validator';
3
+ import { LOAN_FREE_TEXT_MAX_LENGTH } from '../../constants/LoanInputLimits';
3
4
  import { WriteOffConfirmations } from '../WriteOffConfirmations';
4
5
 
5
6
  /** Body de `POST /backoffice/credits/:creditId/write-off`. Los faltantes los responde el lambda con su code. */
@@ -8,6 +9,7 @@ export class BackofficeWriteOffCreditRequest {
8
9
  @Expose()
9
10
  @IsOptional()
10
11
  @IsString()
12
+ @MaxLength(LOAN_FREE_TEXT_MAX_LENGTH)
11
13
  reason?: string;
12
14
 
13
15
  @Expose()
@@ -1,5 +1,5 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsEnum, IsInt, IsOptional, IsUUID, Min } from 'class-validator';
2
+ import { IsBoolean, IsEnum, IsInt, IsOptional, IsUUID, Min } from 'class-validator';
3
3
  import { LoanCustomerPaymentTypeEnum } from '../../enums/LoanCustomerPaymentTypeEnum';
4
4
 
5
5
  /** Body de `POST /private/customers/:directoryId/credits/:creditId/payments` (loan-credit-business). */
@@ -25,4 +25,13 @@ export class CreateCustomerPaymentRequest {
25
25
  @IsInt()
26
26
  @Min(1)
27
27
  installmentCount?: number;
28
+
29
+ /**
30
+ * Confirma un pago igual a otro reciente (mismo crédito, monto y actor en los últimos 10 min) que
31
+ * llegó con otra llave. Sin él, el servidor responde que pida confirmación al cliente (L-057, L-092).
32
+ */
33
+ @Expose()
34
+ @IsOptional()
35
+ @IsBoolean()
36
+ confirmDuplicate?: boolean;
28
37
  }
@@ -1,5 +1,5 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { IsEnum, IsInt, IsOptional, IsUUID, Min, ValidateNested } from 'class-validator';
2
+ import { IsBoolean, IsEnum, IsInt, IsOptional, IsUUID, Min, ValidateNested } from 'class-validator';
3
3
  import { InStorePaymentMethodEnum } from '../../enums/InStorePaymentMethodEnum';
4
4
  import { LoanCustomerPaymentTypeEnum } from '../../enums/LoanCustomerPaymentTypeEnum';
5
5
  import { InStorePaymentDetail } from './InStorePaymentDetail';
@@ -37,4 +37,13 @@ export class CreateSellerPaymentRequest {
37
37
  @Expose()
38
38
  @IsUUID()
39
39
  idempotencyKey!: string;
40
+
41
+ /**
42
+ * Confirma un pago igual a otro reciente (mismo crédito, monto y actor en los últimos 10 min) que
43
+ * llegó con otra llave. Sin él, el servidor responde que pida confirmación al vendedor (L-057, L-092).
44
+ */
45
+ @Expose()
46
+ @IsOptional()
47
+ @IsBoolean()
48
+ confirmDuplicate?: boolean;
40
49
  }
@@ -5,9 +5,13 @@ import {
5
5
  IsNotEmpty,
6
6
  IsOptional,
7
7
  IsString,
8
+ Matches,
8
9
  Max,
10
+ MaxLength,
9
11
  Min,
10
12
  } from 'class-validator';
13
+ import { SKU_MAX_LENGTH, SKU_MESSAGE, SKU_PATTERN } from '../../../common/constants/InputPatterns';
14
+ import { LOAN_AMOUNT_MAX_CENTS, LOAN_MAX_TERM_WEEKS } from '../../constants/LoanInputLimits';
11
15
  import { ProductCategoryEnum } from '../../../retailCatalog/enums/ProductCategoryEnum';
12
16
  import { ProductTierEnum } from '../../../retailCatalog/enums/ProductTierEnum';
13
17
  import { ClientLevelEnum } from '../../../loanScoring/enums/ClientLevelEnum';
@@ -42,17 +46,20 @@ export class OriginateLoanCreditRequest {
42
46
  @Expose()
43
47
  @IsInt()
44
48
  @Min(1)
45
- @Max(104)
49
+ @Max(LOAN_MAX_TERM_WEEKS)
46
50
  termWeeks!: number;
47
51
 
52
+ /** Precio del equipo en centavos; el techo es técnico, no de negocio (L-027). */
48
53
  @Expose()
49
54
  @IsInt()
50
55
  @Min(1)
56
+ @Max(LOAN_AMOUNT_MAX_CENTS)
51
57
  equipmentPriceCents!: number;
52
58
 
53
59
  @Expose()
54
60
  @IsInt()
55
61
  @Min(0)
62
+ @Max(LOAN_AMOUNT_MAX_CENTS)
56
63
  downPaymentCents!: number;
57
64
 
58
65
  /**
@@ -107,6 +114,8 @@ export class OriginateLoanCreditRequest {
107
114
  @Expose()
108
115
  @IsOptional()
109
116
  @IsString()
117
+ @MaxLength(SKU_MAX_LENGTH)
118
+ @Matches(SKU_PATTERN, { message: SKU_MESSAGE })
110
119
  productSku?: string;
111
120
 
112
121
  /** Tipo del equipo: resuelve promociones acotadas por tipo. */
@@ -1,7 +1,8 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { ArrayMaxSize, ArrayMinSize, IsArray, IsNotEmpty, IsString } from 'class-validator';
2
+ import { ArrayMaxSize, ArrayMinSize, IsArray, IsNotEmpty, IsString, Matches } from 'class-validator';
3
+ import { RETAIL_CUSTOMER_ID_MESSAGE, RETAIL_CUSTOMER_ID_PATTERN } from '../../constants/LoanInputLimits';
3
4
 
4
- /** Body de `POST /private/borrowers/segment-facts`: datos para segmentar de hasta 100 clientes retail. */
5
+ /** Body de `POST /private/borrowers/segment-facts`: datos para segmentar de hasta 100 clientes retail; cada id con forma de id (L-067). */
5
6
  export class SegmentFactsBatchRequest {
6
7
  @Expose()
7
8
  @IsArray()
@@ -9,5 +10,6 @@ export class SegmentFactsBatchRequest {
9
10
  @ArrayMaxSize(100)
10
11
  @IsString({ each: true })
11
12
  @IsNotEmpty({ each: true })
13
+ @Matches(RETAIL_CUSTOMER_ID_PATTERN, { each: true, message: RETAIL_CUSTOMER_ID_MESSAGE })
12
14
  retailCustomerIds!: string[];
13
15
  }
@@ -1,5 +1,6 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { IsObject, IsOptional, IsString, Length, ValidateNested } from 'class-validator';
2
+ import { IsObject, IsOptional, IsString, Length, Matches, MaxLength, ValidateNested } from 'class-validator';
3
+ import { E164_PHONE_MAX_LENGTH, E164_PHONE_MESSAGE, E164_PHONE_PATTERN } from '../../constants/LoanInputLimits';
3
4
  import { LoanContractDetails } from '../LoanContractDetails';
4
5
  import { SignatureContext } from '../SignatureContext';
5
6
 
@@ -39,6 +40,8 @@ export class SignLoanCreditRequest {
39
40
  * posee (PII TRANSITORIA del cliente — nombreAcreditado, curp, domicilio, lugar de firma...).
40
41
  * Las aporta el WIZARD (dueño del dato); el motor las mezcla con las financieras (monto,
41
42
  * pagos, tasa) y las pasa a document-generator. NO se persisten ni loggean (silo PII-zero).
43
+ *
44
+ * @deprecated loan-credit ya no lo lee: los datos del contrato viajan en `contractDetails`.
42
45
  */
43
46
  @Expose()
44
47
  @IsOptional()
@@ -64,6 +67,8 @@ export class SignLoanCreditRequest {
64
67
  @Expose()
65
68
  @IsOptional()
66
69
  @IsString()
70
+ @MaxLength(E164_PHONE_MAX_LENGTH)
71
+ @Matches(E164_PHONE_PATTERN, { message: E164_PHONE_MESSAGE })
67
72
  otpDestination?: string;
68
73
 
69
74
  /**
@@ -1,5 +1,6 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { IsNotEmpty, IsOptional, IsString, ValidateNested } from 'class-validator';
2
+ import { IsNotEmpty, IsOptional, IsString, Matches, ValidateNested } from 'class-validator';
3
+ import { RETAIL_CUSTOMER_ID_MESSAGE, RETAIL_CUSTOMER_ID_PATTERN } from '../../constants/LoanInputLimits';
3
4
  import { LoanBeneficiary } from '../LoanBeneficiary';
4
5
 
5
6
  /**
@@ -15,9 +16,11 @@ import { LoanBeneficiary } from '../LoanBeneficiary';
15
16
  * `RETAIL_PULL_FAILED` (422/502 — ver openapi del motor).
16
17
  */
17
18
  export class UpsertLoanBorrowerRequest {
19
+ /** Id del cliente en retail-customer (hoy un ULID); largo y forma acotados (L-031). */
18
20
  @Expose()
19
21
  @IsString()
20
22
  @IsNotEmpty()
23
+ @Matches(RETAIL_CUSTOMER_ID_PATTERN, { message: RETAIL_CUSTOMER_ID_MESSAGE })
21
24
  retailCustomerId!: string;
22
25
 
23
26
  /** Beneficiario / a quién avisar (opcional — el wizard lo captura en su paso propio). */
@@ -117,6 +117,8 @@ export * from './dtos/responses/LoanDeviceReleaseResult';
117
117
  export * from './dtos/responses/LoanDeviceReleaseResponse';
118
118
 
119
119
  export * from './validators/IsFutureIso8601DateTime';
120
+ export * from './validators/IsContractBirthDate';
121
+ export * from './constants/LoanInputLimits';
120
122
 
121
123
  // Candidatos de mensajería — contrato de `POST /private/messaging/candidates`
122
124
  // Re-export del enum canónico del momento (owner: messagesConnector — un solo origen de verdad).
@@ -0,0 +1,41 @@
1
+ import { ValidateBy, ValidationOptions } from 'class-validator';
2
+
3
+ /** `DD/MM/AAAA`: como la imprime el contrato y como la manda hoy el wizard. */
4
+ const DAY_FIRST = /^(\d{2})\/(\d{2})\/(\d{4})$/;
5
+ /** `AAAA-MM-DD`: como la guarda retail-customer. */
6
+ const ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
7
+
8
+ /** `true` si año, mes y día forman una fecha de calendario real (rechaza el 31/02). */
9
+ const isCalendarDate = (year: number, month: number, day: number): boolean => {
10
+ const date = new Date(Date.UTC(year, month - 1, day));
11
+ return date.getUTCFullYear() === year && date.getUTCMonth() === month - 1 && date.getUTCDate() === day;
12
+ };
13
+
14
+ /** `true` si el valor es una fecha `DD/MM/AAAA` o `AAAA-MM-DD` que existe en el calendario. */
15
+ export const isContractBirthDate = (value: unknown): boolean => {
16
+ if (typeof value !== 'string') return false;
17
+ const dayFirst = DAY_FIRST.exec(value);
18
+ if (dayFirst) return isCalendarDate(Number(dayFirst[3]), Number(dayFirst[2]), Number(dayFirst[1]));
19
+ const iso = ISO_DATE.exec(value);
20
+ if (iso) return isCalendarDate(Number(iso[1]), Number(iso[2]), Number(iso[3]));
21
+ return false;
22
+ };
23
+
24
+ /**
25
+ * Fecha de nacimiento del contrato: `DD/MM/AAAA` (la que imprime la plantilla y manda el wizard) o
26
+ * `AAAA-MM-DD`. Sin hora: es una fecha de calendario, no un instante.
27
+ *
28
+ * `LoanContractDetails.birthDate` no lo usa: ahí solo hay tope de largo para no tumbar la firma. Es
29
+ * para el dominio, que con `isContractBirthDate` decide si imprime la fecha o la deja en blanco.
30
+ */
31
+ export const IsContractBirthDate = (validationOptions?: ValidationOptions): PropertyDecorator =>
32
+ ValidateBy(
33
+ {
34
+ name: 'isContractBirthDate',
35
+ validator: {
36
+ validate: (value: unknown): boolean => isContractBirthDate(value),
37
+ defaultMessage: (): string => '$property debe ser una fecha DD/MM/AAAA o AAAA-MM-DD válida',
38
+ },
39
+ },
40
+ validationOptions,
41
+ );