@fiado/type-kit 3.584.0 → 3.586.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 (84) hide show
  1. package/_test_/unit/collection/disburseRequest.test.ts +10 -0
  2. package/_test_/unit/collection/disbursementType.test.ts +7 -2
  3. package/_test_/unit/platformRbac/dtos/UpdateTenantUserEmailRequest.test.ts +24 -0
  4. package/_test_/unit/platformRbac/enums/__snapshots__/permissionBits.test.ts.snap +2 -1
  5. package/_test_/unit/platformRbac/enums/apiUserPermission.test.ts +3 -2
  6. package/_test_/unit/platformRbac/enums/retailIntegrationPermission.test.ts +13 -0
  7. package/_test_/unit/productCatalog/rewardEnums.test.ts +19 -0
  8. package/_test_/unit/retailIntegration/reconciliationContracts.test.ts +3 -3
  9. package/_test_/unit/retailIntegration/retailMovementsContracts.test.ts +109 -0
  10. package/_test_/unit/retailIntegration/retailSystemResponses.test.ts +120 -0
  11. package/_test_/unit/rewards/enums.test.ts +1 -1
  12. package/_test_/unit/rewards/waitingLimit.test.ts +43 -0
  13. package/bin/collection/enums/DisbursementType.d.ts +3 -1
  14. package/bin/collection/enums/DisbursementType.js +2 -0
  15. package/bin/platformRbac/dtos/CreateTenantUserRequest.d.ts +2 -1
  16. package/bin/platformRbac/dtos/CreateTenantUserRequest.js +2 -1
  17. package/bin/platformRbac/dtos/UpdateTenantUserEmailRequest.d.ts +5 -0
  18. package/bin/platformRbac/dtos/UpdateTenantUserEmailRequest.js +30 -0
  19. package/bin/platformRbac/enums/Permission.d.ts +2 -1
  20. package/bin/platformRbac/enums/Permission.js +3 -0
  21. package/bin/platformRbac/index.d.ts +1 -0
  22. package/bin/platformRbac/index.js +1 -0
  23. package/bin/productCatalog/enums/ProductSubtypeEnum.d.ts +1 -0
  24. package/bin/productCatalog/enums/ProductSubtypeEnum.js +3 -0
  25. package/bin/productCatalog/enums/ProductTypeEnum.d.ts +3 -1
  26. package/bin/productCatalog/enums/ProductTypeEnum.js +2 -0
  27. package/bin/retailIntegration/constants/retailIntegrationLimits.d.ts +11 -0
  28. package/bin/retailIntegration/constants/retailIntegrationLimits.js +12 -1
  29. package/bin/retailIntegration/dtos/CheckRetailInventoryRequest.d.ts +4 -1
  30. package/bin/retailIntegration/dtos/CheckRetailInventoryRequest.js +4 -1
  31. package/bin/retailIntegration/dtos/GetRetailInventoryRequest.d.ts +3 -3
  32. package/bin/retailIntegration/dtos/GetRetailInventoryRequest.js +3 -3
  33. package/bin/retailIntegration/dtos/ListRetailInventoryMovementsRequest.d.ts +6 -0
  34. package/bin/retailIntegration/dtos/ListRetailInventoryMovementsRequest.js +29 -0
  35. package/bin/retailIntegration/dtos/ReconciliationPageMessage.d.ts +6 -0
  36. package/bin/retailIntegration/dtos/ReconciliationPageMessage.js +20 -0
  37. package/bin/retailIntegration/dtos/RetailOutboundResponses.d.ts +10 -2
  38. package/bin/retailIntegration/dtos/RetailSystemResponses.d.ts +41 -0
  39. package/bin/retailIntegration/dtos/RetailSystemResponses.js +136 -0
  40. package/bin/retailIntegration/enums/ReconciliationEntityEnum.d.ts +2 -1
  41. package/bin/retailIntegration/enums/ReconciliationEntityEnum.js +1 -0
  42. package/bin/retailIntegration/enums/ReconciliationTriggerEnum.d.ts +4 -2
  43. package/bin/retailIntegration/enums/ReconciliationTriggerEnum.js +3 -1
  44. package/bin/retailIntegration/index.d.ts +3 -0
  45. package/bin/retailIntegration/index.js +3 -0
  46. package/bin/retailIntegration/models/RetailPageMeta.d.ts +3 -1
  47. package/bin/retailIntegration/models/RetailSystemInventory.d.ts +9 -1
  48. package/bin/retailIntegration/validators/IsMovementsRangeValid.d.ts +6 -0
  49. package/bin/retailIntegration/validators/IsMovementsRangeValid.js +28 -0
  50. package/bin/rewards/dtos/backoffice/BackofficeGrantItemResponse.d.ts +9 -0
  51. package/bin/rewards/enums/GrantItemStatusEnum.d.ts +2 -0
  52. package/bin/rewards/enums/GrantItemStatusEnum.js +2 -0
  53. package/bin/rewards/enums/LimitWaitReasonEnum.d.ts +7 -0
  54. package/bin/rewards/enums/LimitWaitReasonEnum.js +11 -0
  55. package/bin/rewards/enums/RewardItemCodeEnum.d.ts +9 -0
  56. package/bin/rewards/enums/RewardItemCodeEnum.js +13 -0
  57. package/bin/rewards/index.d.ts +2 -0
  58. package/bin/rewards/index.js +2 -0
  59. package/package.json +1 -1
  60. package/src/collection/enums/DisbursementType.ts +2 -0
  61. package/src/platformRbac/dtos/CreateTenantUserRequest.ts +2 -1
  62. package/src/platformRbac/dtos/UpdateTenantUserEmailRequest.ts +12 -0
  63. package/src/platformRbac/enums/Permission.ts +3 -0
  64. package/src/platformRbac/index.ts +1 -0
  65. package/src/productCatalog/enums/ProductSubtypeEnum.ts +4 -0
  66. package/src/productCatalog/enums/ProductTypeEnum.ts +3 -1
  67. package/src/retailIntegration/constants/retailIntegrationLimits.ts +16 -0
  68. package/src/retailIntegration/dtos/CheckRetailInventoryRequest.ts +4 -1
  69. package/src/retailIntegration/dtos/GetRetailInventoryRequest.ts +3 -3
  70. package/src/retailIntegration/dtos/ListRetailInventoryMovementsRequest.ts +14 -0
  71. package/src/retailIntegration/dtos/ReconciliationPageMessage.ts +21 -1
  72. package/src/retailIntegration/dtos/RetailOutboundResponses.ts +11 -2
  73. package/src/retailIntegration/dtos/RetailSystemResponses.ts +75 -0
  74. package/src/retailIntegration/enums/ReconciliationEntityEnum.ts +1 -0
  75. package/src/retailIntegration/enums/ReconciliationTriggerEnum.ts +3 -1
  76. package/src/retailIntegration/index.ts +3 -0
  77. package/src/retailIntegration/models/RetailPageMeta.ts +3 -1
  78. package/src/retailIntegration/models/RetailSystemInventory.ts +10 -1
  79. package/src/retailIntegration/validators/IsMovementsRangeValid.ts +17 -0
  80. package/src/rewards/dtos/backoffice/BackofficeGrantItemResponse.ts +9 -0
  81. package/src/rewards/enums/GrantItemStatusEnum.ts +2 -0
  82. package/src/rewards/enums/LimitWaitReasonEnum.ts +7 -0
  83. package/src/rewards/enums/RewardItemCodeEnum.ts +9 -0
  84. package/src/rewards/index.ts +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.584.0",
3
+ "version": "3.586.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -7,4 +7,6 @@ export enum DisbursementType {
7
7
  MEX_BONUS = 'MEX_BONUS',
8
8
  /** Comisión de vendedor. */
9
9
  MEX_SELLER_COMMISSION = 'MEX_SELLER_COMMISSION',
10
+ /** Abono de recompensas de `rewards-business`. */
11
+ MEX_REWARD = 'MEX_REWARD',
10
12
  }
@@ -14,7 +14,8 @@ const hasAnyGrantField = (o: CreateTenantUserRequest): boolean =>
14
14
  * Consumido por el alta de usuario orquestada de SureKeep F1 (retail-org → RBAC → RetailUser) vía api-invoker.
15
15
  * - Usuario provisionado en estado INVITED (mitiga orphan si el paso siguiente en retail-org falla).
16
16
  * - Idempotente por identidad Cognito.
17
- * - `roleId`/`scope`/`scopeRef`: todos o ninguno; sin rol no hay invitación.
17
+ * - `roleId`/`scope`/`scopeRef`: todos o ninguno; sin rol exige `suppressInvitation: true`
18
+ * y la invitación queda pendiente (`invitationPending`) hasta asignar el primer rol.
18
19
  * - `createdBy` = cognitoSub del admin real (audit + grantedBy del assignment).
19
20
  * - `customFields` = valores de los campos personalizados del tenant; si el correo ya tiene usuario, se fusionan.
20
21
  */
@@ -0,0 +1,12 @@
1
+ import { Expose, Transform } from 'class-transformer';
2
+ import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
3
+
4
+ /** Body M2M que cambia el correo de un usuario del tenant; el correo se guarda en minúsculas. */
5
+ export class UpdateTenantUserEmailRequest {
6
+ @Expose()
7
+ @Transform(({ value }) => (typeof value === 'string' ? value.trim().toLowerCase() : value))
8
+ @IsEmail()
9
+ email!: string;
10
+
11
+ @Expose() @IsString() @IsNotEmpty() actedBy!: string;
12
+ }
@@ -165,6 +165,8 @@ export enum Permission {
165
165
  TENANT_INTEGRATION_DIAGNOSTIC = 'tenant.integration.diagnostic',
166
166
  // Alta, rotación de secreto y edición de IPs de usuarios de API; se exige además de tenant.user.create.
167
167
  TENANT_API_USER_MANAGE = 'tenant.api_user.manage',
168
+ // Activa la integración de un retailer externo (Zentral); scope PLATFORM.
169
+ PLATFORM_RETAIL_INTEGRATION_ACTIVATE = 'platform.retail_integration.activate',
168
170
  }
169
171
 
170
172
  /**
@@ -286,6 +288,7 @@ export const PERMISSION_BIT_ORDER: readonly Permission[] = [
286
288
  Permission.PLATFORM_INTEGRATION_KEY_REVOKE,
287
289
  Permission.TENANT_INTEGRATION_DIAGNOSTIC,
288
290
  Permission.TENANT_API_USER_MANAGE,
291
+ Permission.PLATFORM_RETAIL_INTEGRATION_ACTIVATE,
289
292
  ] as const;
290
293
 
291
294
  function djb2(input: string): number {
@@ -167,6 +167,7 @@ export type { ListTenantUsersResponse } from './dtos/ListTenantUsersResponse';
167
167
  export type { TenantUserListItemResponse } from './dtos/TenantUserListItemResponse';
168
168
  export type { GetTenantUserResponse } from './dtos/GetTenantUserResponse';
169
169
  export * from './dtos/UpdateTenantUserRequest';
170
+ export * from './dtos/UpdateTenantUserEmailRequest';
170
171
  export * from './dtos/DeleteTenantUserRequest';
171
172
  export * from './dtos/DisableTenantUserRequest';
172
173
  export * from './dtos/EnableTenantUserRequest';
@@ -86,6 +86,10 @@ export enum ProductSubtypeEnum {
86
86
  // Comisión de vendedor de SureKeep abonada a la wallet.
87
87
  SUREKEEP_SELLER_COMMISSION_MX = "SELLER_COMMISSION_MX",
88
88
 
89
+ //REWARDS
90
+ // Abono de recompensas de `rewards-business`.
91
+ REWARD_MX = "REWARD_MX",
92
+
89
93
  //STORE
90
94
  STORE_PHONE = "PHONE",
91
95
 
@@ -63,5 +63,7 @@ export enum ProductTypeEnum {
63
63
  * Dispersión SPEI de liquidaciones de beneficios (money-transfer-connector).
64
64
  * Producto del catálogo para la orden STP que sale con `source=BENEFITS_SETTLEMENT`.
65
65
  */
66
- MONEY_TRANSFER_SA = "MONEY_TRANSFER_SA"
66
+ MONEY_TRANSFER_SA = "MONEY_TRANSFER_SA",
67
+ /** Abono de recompensas de `rewards-business`. */
68
+ REWARDS = "REWARDS"
67
69
  }
@@ -50,3 +50,19 @@ export const RETAIL_ELIGIBLE_FINANCIERS_MAX = 50;
50
50
 
51
51
  /** Decimal de los eventos del retailer: hasta 12 enteros y dos decimales, nunca negativo. */
52
52
  export const RETAIL_EVENT_DECIMAL_PATTERN = /^\d{1,12}\.\d{2}$/;
53
+
54
+ /** Tope del `nextToken` opaco que devuelve Zentral. */
55
+ export const RETAIL_NEXT_TOKEN_MAX_LENGTH = 2048;
56
+
57
+ /** Id que asigna Zentral, como `externalSaleId`: no vacío, sin espacios y de a lo más 64. */
58
+ export const RETAIL_EXTERNAL_ID_PATTERN = /^\S{1,64}$/;
59
+
60
+ /** Tope del `code` en el cuerpo de error de Zentral. */
61
+ export const RETAIL_ERROR_CODE_MAX_LENGTH = 64;
62
+
63
+ /** Rango de `lineIndex` en un error de línea de venta. */
64
+ export const RETAIL_LINE_INDEX_MIN = 0;
65
+ export const RETAIL_LINE_INDEX_MAX = 999;
66
+
67
+ /** Rango máximo de `GET /inventory/movements`: 7 días en milisegundos. */
68
+ export const RETAIL_MOVEMENTS_RANGE_MAX_MS = 7 * 24 * 60 * 60 * 1000;
@@ -8,7 +8,10 @@ function csvToArray({ value }: { value: unknown }): unknown {
8
8
  return typeof value === 'string' ? value.split(',').map((item) => item.trim()) : value;
9
9
  }
10
10
 
11
- /** Query de `GET /private/retail/inventory/live-check`; `identifiers` llega como csv. */
11
+ /**
12
+ * Query de `GET /private/retail/inventory/live-check`; `identifiers` llega como csv.
13
+ * @deprecated el live-check se va a quitar; el inventario se toma de movimientos y de la lectura diaria.
14
+ */
12
15
  export class CheckRetailInventoryRequest extends RetailTenantQuery {
13
16
  @IsString() @Matches(/\S/) storeId!: string;
14
17
 
@@ -1,8 +1,8 @@
1
1
  import { IsString, Matches } from 'class-validator';
2
- import { RetailListQuery } from './RetailListQuery';
2
+ import { RetailPagedQuery } from './RetailPagedQuery';
3
3
 
4
- /** Query de `GET /private/retail/inventory`; el inventario es por tienda y no pagina. */
5
- export class GetRetailInventoryRequest extends RetailListQuery {
4
+ /** Query de `GET /private/retail/inventory`; el inventario es por tienda y pagina con `limit`/`nextToken`. */
5
+ export class GetRetailInventoryRequest extends RetailPagedQuery {
6
6
  @IsString()
7
7
  @Matches(/\S/)
8
8
  storeId!: string;
@@ -0,0 +1,14 @@
1
+ import { Validate } from 'class-validator';
2
+ import { IsIsoDateTimeWithZone } from '../validators/IsIsoDateTimeWithZone';
3
+ import { IsMovementsRangeValid } from '../validators/IsMovementsRangeValid';
4
+ import { RetailPagedQuery } from './RetailPagedQuery';
5
+
6
+ /** Query de `GET /private/retail/inventory/movements`: rango `[from, to)` de a lo más 7 días. */
7
+ export class ListRetailInventoryMovementsRequest extends RetailPagedQuery {
8
+ @Validate(IsIsoDateTimeWithZone)
9
+ from!: string;
10
+
11
+ @Validate(IsIsoDateTimeWithZone)
12
+ @Validate(IsMovementsRangeValid)
13
+ to!: string;
14
+ }
@@ -1,6 +1,7 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsEnum, IsInt, IsNotEmpty, IsOptional, IsString, Min } from 'class-validator';
2
+ import { IsEnum, IsInt, IsNotEmpty, IsOptional, IsString, Matches, Min, Validate } from 'class-validator';
3
3
  import { ReconciliationEntityEnum } from '../enums/ReconciliationEntityEnum';
4
+ import { IsIsoDateTimeWithZone } from '../validators/IsIsoDateTimeWithZone';
4
5
 
5
6
  /** Mensaje de la cola de revisión: una página, o una tienda completa en inventario. */
6
7
  export class ReconciliationPageMessage {
@@ -43,4 +44,23 @@ export class ReconciliationPageMessage {
43
44
  @IsInt()
44
45
  @Min(0)
45
46
  requeueCount?: number;
47
+
48
+ /** Cursor de Zentral para la siguiente página del inventario de la tienda. */
49
+ @Expose()
50
+ @IsOptional()
51
+ @IsString()
52
+ @Matches(/\S/)
53
+ nextToken?: string;
54
+
55
+ /** Inicio del rango de movimientos, incluido. */
56
+ @Expose()
57
+ @IsOptional()
58
+ @Validate(IsIsoDateTimeWithZone)
59
+ from?: string;
60
+
61
+ /** Fin del rango de movimientos, excluido. */
62
+ @Expose()
63
+ @IsOptional()
64
+ @Validate(IsIsoDateTimeWithZone)
65
+ to?: string;
46
66
  }
@@ -1,5 +1,5 @@
1
1
  import { RetailInventoryMeta, RetailPageMeta } from '../models/RetailPageMeta';
2
- import { RetailSystemPiece, RetailSystemStock } from '../models/RetailSystemInventory';
2
+ import { RetailSystemInventoryMovement, RetailSystemPiece, RetailSystemStock } from '../models/RetailSystemInventory';
3
3
  import { RetailSystemProduct } from '../models/RetailSystemProduct';
4
4
  import { RetailSystemStore } from '../models/RetailSystemStore';
5
5
  import { RetailSystemUser } from '../models/RetailSystemUser';
@@ -23,6 +23,12 @@ export interface GetRetailInventoryResponse {
23
23
  meta: RetailInventoryMeta;
24
24
  }
25
25
 
26
+ /** `data` de `GET /private/retail/inventory/movements`. */
27
+ export interface ListRetailInventoryMovementsResponse {
28
+ items: RetailSystemInventoryMovement[];
29
+ meta: RetailPageMeta;
30
+ }
31
+
26
32
  /** `data` de `GET /private/retail/users`. */
27
33
  export interface ListRetailUsersResponse {
28
34
  items: RetailSystemUser[];
@@ -39,7 +45,10 @@ export interface CancelRetailSaleResponse {
39
45
  saleId: string;
40
46
  }
41
47
 
42
- /** `data` de `GET /private/retail/inventory/live-check`: los identificadores que el retailer lista en la tienda. */
48
+ /**
49
+ * `data` de `GET /private/retail/inventory/live-check`: los identificadores que el retailer lista en la tienda.
50
+ * @deprecated el live-check se va a quitar; el inventario se toma de movimientos y de la lectura diaria.
51
+ */
43
52
  export interface CheckRetailInventoryResponse {
44
53
  listed: string[];
45
54
  generatedAt: string;
@@ -0,0 +1,75 @@
1
+ import { Type } from 'class-transformer';
2
+ import {
3
+ IsArray,
4
+ IsInt,
5
+ IsObject,
6
+ IsOptional,
7
+ IsString,
8
+ Matches,
9
+ Max,
10
+ MaxLength,
11
+ Min,
12
+ Validate,
13
+ ValidateIf,
14
+ ValidateNested,
15
+ } from 'class-validator';
16
+ import {
17
+ RETAIL_ENTITY_ID_PATTERN,
18
+ RETAIL_ERROR_CODE_MAX_LENGTH,
19
+ RETAIL_ID_TEXT_MAX_LENGTH,
20
+ RETAIL_LINE_INDEX_MAX,
21
+ RETAIL_LINE_INDEX_MIN,
22
+ RETAIL_NEXT_TOKEN_MAX_LENGTH,
23
+ RETAIL_EXTERNAL_ID_PATTERN,
24
+ } from '../constants/retailIntegrationLimits';
25
+ import { IsIsoDateTimeWithZone } from '../validators/IsIsoDateTimeWithZone';
26
+ import { isNullOrValidated } from '../validators/payloadValidators';
27
+ import { ReceiveInventoryEventRequest } from './ReceiveInventoryEventRequest';
28
+
29
+ /** `meta` de una página de Zentral; `nextToken` en `null` cierra la lectura y nunca se omite. */
30
+ export class RetailSystemPageMeta {
31
+ @IsInt() @Min(0) count!: number;
32
+ @ValidateIf(isNullOrValidated) @IsString() @MaxLength(RETAIL_NEXT_TOKEN_MAX_LENGTH) nextToken!: string | null;
33
+ }
34
+
35
+ /** Página de una lista de Zentral; cada consumidor valida sus renglones de `data`. */
36
+ export class RetailSystemPageResponse {
37
+ @IsArray() data!: unknown[];
38
+ @IsObject() @ValidateNested() @Type(() => RetailSystemPageMeta) meta!: RetailSystemPageMeta;
39
+ }
40
+
41
+ /** `data` de una página de `GET /inventory`: piezas y existencias crudas. */
42
+ export class RetailSystemInventoryData {
43
+ @IsArray() pieces!: unknown[];
44
+ @IsArray() stock!: unknown[];
45
+ }
46
+
47
+ /** `meta` de una página de `GET /inventory`; `generatedAt` es igual en toda la lectura. */
48
+ export class RetailSystemInventoryMeta extends RetailSystemPageMeta {
49
+ @IsString() @Matches(RETAIL_ENTITY_ID_PATTERN) storeId!: string;
50
+ @Validate(IsIsoDateTimeWithZone) generatedAt!: string;
51
+ }
52
+
53
+ /** Respuesta de `GET /inventory` de Zentral. */
54
+ export class RetailSystemInventoryResponse {
55
+ @IsObject() @ValidateNested() @Type(() => RetailSystemInventoryData) data!: RetailSystemInventoryData;
56
+ @IsObject() @ValidateNested() @Type(() => RetailSystemInventoryMeta) meta!: RetailSystemInventoryMeta;
57
+ }
58
+
59
+ /** `data` de `POST /sales` de Zentral. */
60
+ export class RetailSystemSaleResponse {
61
+ @IsString() @MaxLength(RETAIL_ID_TEXT_MAX_LENGTH) @Matches(RETAIL_EXTERNAL_ID_PATTERN) externalSaleId!: string;
62
+ }
63
+
64
+ /** Cuerpo de error de Zentral; `lineIndex` solo viene en errores de una línea de venta. */
65
+ export class RetailSystemErrorBody {
66
+ @IsString() @Matches(/\S/) @MaxLength(RETAIL_ERROR_CODE_MAX_LENGTH) code!: string;
67
+ @IsOptional() @IsString() msg?: string;
68
+ @IsOptional() @IsInt() @Min(RETAIL_LINE_INDEX_MIN) @Max(RETAIL_LINE_INDEX_MAX) lineIndex?: number;
69
+ }
70
+
71
+ /** Respuesta de `GET /inventory/movements`: cada elemento es el mismo sobre del webhook de inventario. */
72
+ export class RetailSystemMovementsResponse {
73
+ @IsArray() @ValidateNested({ each: true }) @Type(() => ReceiveInventoryEventRequest) data!: ReceiveInventoryEventRequest[];
74
+ @IsObject() @ValidateNested() @Type(() => RetailSystemPageMeta) meta!: RetailSystemPageMeta;
75
+ }
@@ -4,4 +4,5 @@ export enum ReconciliationEntityEnum {
4
4
  USERS = 'USERS',
5
5
  CATALOG = 'CATALOG',
6
6
  INVENTORY = 'INVENTORY',
7
+ MOVEMENTS = 'MOVEMENTS',
7
8
  }
@@ -1,6 +1,8 @@
1
- /** Quién abrió la corrida: el reloj horario, el botón «Actualizar» o la activación del retailer. */
1
+ /** Quién abrió la corrida: el reloj horario o diario, el botón «Actualizar», la activación o una discrepancia. */
2
2
  export enum ReconciliationTriggerEnum {
3
3
  SCHEDULED = 'SCHEDULED',
4
4
  MANUAL = 'MANUAL',
5
5
  ACTIVATION = 'ACTIVATION',
6
+ DISCREPANCY = 'DISCREPANCY',
7
+ DAILY = 'DAILY',
6
8
  }
@@ -2,6 +2,7 @@ export * from './constants/retailIntegrationLimits';
2
2
  export * from './constants/retailIntegrationErrorHttpStatus';
3
3
  export * from './enums';
4
4
  export * from './validators/IsIsoDateTimeWithZone';
5
+ export * from './validators/IsMovementsRangeValid';
5
6
  export * from './dtos/RetailEventEnvelope';
6
7
  export * from './dtos/ReceiveStoreEventRequest';
7
8
  export * from './dtos/ReceiveRetailUserEventRequest';
@@ -21,11 +22,13 @@ export * from './dtos/RetailPagedQuery';
21
22
  export * from './dtos/ListRetailStoresRequest';
22
23
  export * from './dtos/ListRetailCatalogRequest';
23
24
  export * from './dtos/GetRetailInventoryRequest';
25
+ export * from './dtos/ListRetailInventoryMovementsRequest';
24
26
  export * from './dtos/ListRetailUsersRequest';
25
27
  export * from './dtos/RegisterRetailSaleRequest';
26
28
  export * from './dtos/CancelRetailSaleRequest';
27
29
  export * from './dtos/CheckRetailInventoryRequest';
28
30
  export * from './dtos/RetailOutboundResponses';
31
+ export * from './dtos/RetailSystemResponses';
29
32
  export * from './models/RetailPageMeta';
30
33
  export * from './models/RetailSystemStore';
31
34
  export * from './models/RetailSystemProduct';
@@ -4,8 +4,10 @@ export interface RetailPageMeta {
4
4
  nextToken: string | null;
5
5
  }
6
6
 
7
- /** `meta` del inventario de una tienda. */
7
+ /** `meta` del inventario de una tienda; `count` y `nextToken` llegan cuando la lectura pagina. */
8
8
  export interface RetailInventoryMeta {
9
9
  storeId: string;
10
10
  generatedAt: string;
11
+ count?: number;
12
+ nextToken?: string | null;
11
13
  }
@@ -1,4 +1,5 @@
1
- import { RetailPieceReasonEnum, RetailPieceStatusEnum } from '../enums';
1
+ import type { InventoryEventPayload } from '../dtos/InventoryEventPayload';
2
+ import { InventoryEventTypeEnum, RetailPieceReasonEnum, RetailPieceStatusEnum } from '../enums';
2
3
 
3
4
  export type RetailPieceStatus = `${RetailPieceStatusEnum}`;
4
5
  export type RetailPieceReason = `${RetailPieceReasonEnum}`;
@@ -18,3 +19,11 @@ export interface RetailSystemStock {
18
19
  storeId: string;
19
20
  qty: number;
20
21
  }
22
+
23
+ /** Movimiento de inventario de Zentral: el mismo sobre que llega a `POST /webhooks/inventory`. */
24
+ export interface RetailSystemInventoryMovement {
25
+ eventId: string;
26
+ eventType: `${InventoryEventTypeEnum}`;
27
+ occurredAt: string;
28
+ payload: InventoryEventPayload;
29
+ }
@@ -0,0 +1,17 @@
1
+ import { ValidationArguments, ValidatorConstraint, ValidatorConstraintInterface } from 'class-validator';
2
+ import { RETAIL_MOVEMENTS_RANGE_MAX_MS } from '../constants/retailIntegrationLimits';
3
+
4
+ /** `to`: mayor que `from` y a lo más 7 días después; sin `from` legible lo rechaza su propio validador. */
5
+ @ValidatorConstraint({ name: 'isMovementsRangeValid', async: false })
6
+ export class IsMovementsRangeValid implements ValidatorConstraintInterface {
7
+ validate(value: unknown, args: ValidationArguments): boolean {
8
+ const from = Date.parse(String((args.object as { from?: unknown }).from));
9
+ const to = Date.parse(String(value));
10
+ if (Number.isNaN(from) || Number.isNaN(to)) return true;
11
+ return to > from && to - from <= RETAIL_MOVEMENTS_RANGE_MAX_MS;
12
+ }
13
+
14
+ defaultMessage(): string {
15
+ return 'to debe ser mayor que from y a lo más 7 días después';
16
+ }
17
+ }
@@ -1,8 +1,17 @@
1
1
  import { GrantItemResponse } from '../responses/GrantItemResponse';
2
+ import { LimitWaitReasonEnum } from '../../enums/LimitWaitReasonEnum';
2
3
  import { BackofficeGrantAttemptResponse } from './BackofficeGrantAttemptResponse';
3
4
 
4
5
  export class BackofficeGrantItemResponse extends GrantItemResponse {
5
6
  /** Nombre de la recompensa congelada en la entrega. */
6
7
  name: string;
7
8
  attempts: BackofficeGrantAttemptResponse[];
9
+ /** Motivo de la espera por tope; solo cuando el ítem está en `WAITING_LIMIT`. */
10
+ waitReason?: LimitWaitReasonEnum;
11
+ /** Epoch ms del próximo intento programado. */
12
+ retryNotBefore?: number;
13
+ /** Epoch ms en que el ítem entró en espera. */
14
+ waitingSince?: number;
15
+ /** Cantidad de rechazos por tope acumulados. */
16
+ limitRejections?: number;
8
17
  }
@@ -5,6 +5,8 @@ export enum GrantItemStatusEnum {
5
5
  * ocurrido y el adaptador debe reconciliar antes de reintentar.
6
6
  */
7
7
  PROCESSING = 'PROCESSING',
8
+ /** Espera por tope de nivel de la cuenta destino: no es `PROCESSING` ni `FAILED`; se reintenta solo. */
9
+ WAITING_LIMIT = 'WAITING_LIMIT',
8
10
  GRANTED = 'GRANTED',
9
11
  FAILED = 'FAILED',
10
12
  SKIPPED = 'SKIPPED',
@@ -0,0 +1,7 @@
1
+ /** Motivo por el que un ítem espera: `processorCode` del rechazo por tope de nivel de la cuenta destino. */
2
+ export enum LimitWaitReasonEnum {
3
+ /** Tope mensual de monto del nivel de la cuenta. */
4
+ MONTHLY_AMOUNT_EXCEEDED = 'ACCOUNT_LEVEL_MAX_MONTHLY_AMOUNT_EXCEEDED',
5
+ /** Tope de saldo disponible del nivel de la cuenta. */
6
+ AVAILABLE_BALANCE_EXCEEDED = 'ACCOUNT_LEVEL_MAX_AVAILABLE_BALANCE_EXCEEDED',
7
+ }
@@ -0,0 +1,9 @@
1
+ /** Códigos de resultado de un ítem de entrega que no vienen del proveedor. */
2
+ export enum RewardItemCodeEnum {
3
+ /** El monto del ítem supera el máximo permitido. */
4
+ AMOUNT_ABOVE_MAX = 'AMOUNT_ABOVE_MAX',
5
+ /** Venció la espera por tope (30 días desde `waitingSince`). */
6
+ LIMIT_WAIT_EXPIRED = 'LIMIT_WAIT_EXPIRED',
7
+ /** Resultado desconocido agotado: no se puede asegurar si el abono ocurrió. */
8
+ OUTCOME_UNKNOWN = 'OUTCOME_UNKNOWN',
9
+ }
@@ -2,6 +2,8 @@
2
2
  export * from './enums/RewardsMessageTypeEnum';
3
3
  export * from './enums/GrantStatusEnum';
4
4
  export * from './enums/GrantItemStatusEnum';
5
+ export * from './enums/LimitWaitReasonEnum';
6
+ export * from './enums/RewardItemCodeEnum';
5
7
  export * from './enums/GrantRejectReasonEnum';
6
8
  export * from './enums/GrantFailedReasonEnum';
7
9
  export * from './enums/ItemErrorCategoryEnum';