@fiado/type-kit 3.605.0 → 3.606.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.
@@ -42,7 +42,7 @@ const price = { basePrice: '4299.00', listPrice: null, effectiveFrom: '2026-08-1
42
42
  const product = {
43
43
  sku: 'SAM-A17-128-NEG', externalId: '9001', brand: 'Samsung', model: 'A17', color: 'Negro', capacity: '128 GB', description: null,
44
44
  category: 'PHONE', trackingMode: 'IMEI', tier: null, currencyId: 'MXN', price,
45
- eligibleFinanciers: [], mdmProvider: null, status: 'ACTIVE',
45
+ eligibleFinanciers: ['SUREKEEP'], mdmProvider: null, status: 'ACTIVE',
46
46
  };
47
47
  const piece = { sku: 'SAM-A17-128-NEG', identifier: '356938035643809', storeId: '12', status: 'SOLD', reason: null };
48
48
  const movement = { movementType: 'SALE', storeId: '12', targetStoreId: null, pieces: [piece], stock: [] };
@@ -105,7 +105,7 @@ describe('ProductEventPayload: topes', () => {
105
105
  const atMax = {
106
106
  ...product, externalId: text(ID), brand: text(SHORT), model: text(SHORT), color: text(SHORT), capacity: text(SHORT), description: text(LONG),
107
107
  price: { ...price, basePrice: '999999999999.99', listPrice: '999999999999.99' },
108
- eligibleFinanciers: Array.from({ length: RETAIL_ELIGIBLE_FINANCIERS_MAX }, () => 'SUREKEEP'),
108
+ eligibleFinanciers: ['SUREKEEP', 'PAYJOY', 'CREDIYA', 'LESPAGO', 'INNOVA'],
109
109
  };
110
110
  expect(await errorsOf(ProductEventPayload, atMax)).toEqual([]);
111
111
  });
@@ -6,6 +6,8 @@ import { RetailUserEventPayload } from '../../../src/retailIntegration/dtos/Reta
6
6
  import { ProductEventPayload } from '../../../src/retailIntegration/dtos/ProductEventPayload';
7
7
  import { InventoryEventPayload } from '../../../src/retailIntegration/dtos/InventoryEventPayload';
8
8
  import { RETAIL_EVENT_PIECES_MAX } from '../../../src/retailIntegration/constants/retailIntegrationLimits';
9
+ import { RetailProductTierEnum } from '../../../src/retailIntegration/enums';
10
+ import { ProductTierEnum } from '../../../src/retailCatalog/enums/ProductTierEnum';
9
11
 
10
12
  function paths(errors: ValidationError[], prefix = ''): string[] {
11
13
  return errors.flatMap((e) => {
@@ -78,7 +80,7 @@ const product = {
78
80
  sku: 'SAM-A17-128-NEG', externalId: '9001', brand: 'Samsung', model: 'A17', color: 'Negro', capacity: '128 GB', description: null,
79
81
  category: 'PHONE', trackingMode: 'IMEI', tier: null, currencyId: 'MXN',
80
82
  price: { basePrice: '4299.00', listPrice: null, effectiveFrom: '2026-08-17T20:32:05Z' },
81
- eligibleFinanciers: [], mdmProvider: null, status: 'ACTIVE',
83
+ eligibleFinanciers: ['SUREKEEP'], mdmProvider: null, status: 'ACTIVE',
82
84
  };
83
85
 
84
86
  const piece = { sku: 'SAM-A17-128-NEG', identifier: '356938035643809', storeId: '12', status: 'SOLD', reason: null };
@@ -93,6 +95,41 @@ describe('ProductEventPayload', () => {
93
95
  expect(await errorsOf(ProductEventPayload, { ...product, mdmProvider })).toEqual([]);
94
96
  });
95
97
 
98
+ it.each([
99
+ ['ausente', undefined],
100
+ ['null', null],
101
+ ['de la gama', 'PREMIUM'],
102
+ ])('acepta tier %s', async (_case, tier) => {
103
+ expect(await errorsOf(ProductEventPayload, { ...product, tier })).toEqual([]);
104
+ });
105
+
106
+ it.each([
107
+ ['ausente', undefined],
108
+ ['null', null],
109
+ ['con financieras', ['SUREKEEP', 'PAYJOY']],
110
+ ])('acepta eligibleFinanciers %s', async (_case, eligibleFinanciers) => {
111
+ expect(await errorsOf(ProductEventPayload, { ...product, eligibleFinanciers })).toEqual([]);
112
+ });
113
+
114
+ it('al transformar, tier ausente queda null y eligibleFinanciers ausente o null queda con todas', () => {
115
+ const { tier: _tier, eligibleFinanciers: _financiers, ...withoutKeys } = product;
116
+ const all = ['SUREKEEP', 'PAYJOY', 'CREDIYA', 'LESPAGO', 'INNOVA'];
117
+ const fromAbsent = plainToInstance(ProductEventPayload, withoutKeys);
118
+ expect(fromAbsent.tier).toBeNull();
119
+ expect(fromAbsent.eligibleFinanciers).toEqual(all);
120
+ expect(plainToInstance(ProductEventPayload, { ...product, eligibleFinanciers: null }).eligibleFinanciers).toEqual(all);
121
+ });
122
+
123
+ it('al transformar, conserva tier y eligibleFinanciers cuando vienen', () => {
124
+ const dto = plainToInstance(ProductEventPayload, { ...product, tier: 'MID', eligibleFinanciers: ['PAYJOY'] });
125
+ expect(dto.tier).toBe('MID');
126
+ expect(dto.eligibleFinanciers).toEqual(['PAYJOY']);
127
+ });
128
+
129
+ it('la gama de la integración trae los mismos valores que la de catálogo', () => {
130
+ expect(Object.values(RetailProductTierEnum)).toEqual(Object.values(ProductTierEnum));
131
+ });
132
+
96
133
  it('rechaza un mdmProvider fuera del enum', async () => {
97
134
  expect(await errorsOf(ProductEventPayload, { ...product, mdmProvider: 'KNOX' })).toContain('mdmProvider');
98
135
  });
@@ -102,7 +139,11 @@ describe('ProductEventPayload', () => {
102
139
  ['price.basePrice', { price: { ...product.price, basePrice: '4299' } }],
103
140
  ['price.effectiveFrom', { price: { ...product.price, effectiveFrom: '2026-08-17T20:32:05' } }],
104
141
  ['eligibleFinanciers', { eligibleFinanciers: ['NADIE'] }],
105
- ['tier', { tier: undefined }],
142
+ ['eligibleFinanciers', { eligibleFinanciers: [] }],
143
+ ['eligibleFinanciers', { eligibleFinanciers: ['SUREKEEP', 'SUREKEEP'] }],
144
+ ['eligibleFinanciers', { eligibleFinanciers: 'SUREKEEP' }],
145
+ ['tier', { tier: 'ULTRA' }],
146
+ ['tier', { tier: 'low' }],
106
147
  ['price.listPrice', { price: { basePrice: '4299.00', effectiveFrom: '2026-08-17T20:32:05Z' } }],
107
148
  ])('rechaza %s', async (path, over) => {
108
149
  expect(await errorsOf(ProductEventPayload, { ...product, ...over })).toContain(path);
@@ -16,9 +16,11 @@ export declare class ProductEventPayload implements RetailSystemProduct {
16
16
  description: string | null;
17
17
  category: RetailProductCategory;
18
18
  trackingMode: RetailTrackingMode;
19
+ /** Opcional en el evento: ausente se vuelve `null`. */
19
20
  tier: RetailProductTier | null;
20
21
  currencyId: RetailCurrency;
21
22
  price: ProductEventPricePayload;
23
+ /** Opcional en el evento: ausente o `null` se vuelve la lista de todas las financieras. */
22
24
  eligibleFinanciers: RetailFinancier[];
23
25
  mdmProvider: RetailMdmProvider | null;
24
26
  status: RetailProductStatus;
@@ -89,7 +89,9 @@ __decorate([
89
89
  __metadata("design:type", String)
90
90
  ], ProductEventPayload.prototype, "trackingMode", void 0);
91
91
  __decorate([
92
- (0, class_validator_1.ValidateIf)(payloadValidators_1.isNullOrValidated),
92
+ (0, class_transformer_1.Expose)(),
93
+ (0, class_transformer_1.Transform)(({ value }) => value ?? null),
94
+ (0, class_validator_1.IsOptional)(),
93
95
  (0, class_validator_1.IsIn)(Object.values(enums_1.RetailProductTierEnum)),
94
96
  __metadata("design:type", String)
95
97
  ], ProductEventPayload.prototype, "tier", void 0);
@@ -105,7 +107,12 @@ __decorate([
105
107
  __metadata("design:type", ProductEventPricePayload)
106
108
  ], ProductEventPayload.prototype, "price", void 0);
107
109
  __decorate([
110
+ (0, class_transformer_1.Expose)(),
111
+ (0, class_transformer_1.Transform)(({ value }) => value ?? Object.values(enums_1.RetailFinancierEnum)),
112
+ (0, class_validator_1.IsOptional)(),
108
113
  (0, class_validator_1.IsArray)(),
114
+ (0, class_validator_1.ArrayNotEmpty)(),
115
+ (0, class_validator_1.ArrayUnique)(),
109
116
  (0, class_validator_1.ArrayMaxSize)(retailIntegrationLimits_1.RETAIL_ELIGIBLE_FINANCIERS_MAX),
110
117
  (0, class_validator_1.IsIn)(Object.values(enums_1.RetailFinancierEnum), { each: true }),
111
118
  __metadata("design:type", Array)
@@ -1,4 +1,4 @@
1
- /** Gama de un producto. */
1
+ /** Gama de un producto; mismos valores que `ProductTierEnum` de retailCatalog. */
2
2
  export declare enum RetailProductTierEnum {
3
3
  LOW = "LOW",
4
4
  MID = "MID",
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RetailProductTierEnum = void 0;
4
- /** Gama de un producto. */
4
+ /** Gama de un producto; mismos valores que `ProductTierEnum` de retailCatalog. */
5
5
  var RetailProductTierEnum;
6
6
  (function (RetailProductTierEnum) {
7
7
  RetailProductTierEnum["LOW"] = "LOW";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.605.0",
3
+ "version": "3.606.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -1,5 +1,5 @@
1
- import { Type } from 'class-transformer';
2
- import { ArrayMaxSize, IsArray, IsDefined, IsIn, IsObject, IsString, Matches, MaxLength, Validate, ValidateIf, ValidateNested } from 'class-validator';
1
+ import { Expose, Transform, Type } from 'class-transformer';
2
+ import { ArrayMaxSize, ArrayNotEmpty, ArrayUnique, IsArray, IsDefined, IsIn, IsObject, IsOptional, IsString, Matches, MaxLength, Validate, ValidateIf, ValidateNested } from 'class-validator';
3
3
  import {
4
4
  RETAIL_ELIGIBLE_FINANCIERS_MAX,
5
5
  RETAIL_EVENT_DECIMAL_PATTERN,
@@ -49,10 +49,15 @@ export class ProductEventPayload implements RetailSystemProduct {
49
49
  @ValidateIf(isNullOrValidated) @IsString() @MaxLength(RETAIL_LONG_TEXT_MAX_LENGTH) description!: string | null;
50
50
  @IsIn(Object.values(RetailProductCategoryEnum)) category!: RetailProductCategory;
51
51
  @IsIn(Object.values(RetailTrackingModeEnum)) trackingMode!: RetailTrackingMode;
52
- @ValidateIf(isNullOrValidated) @IsIn(Object.values(RetailProductTierEnum)) tier!: RetailProductTier | null;
52
+ /** Opcional en el evento: ausente se vuelve `null`. */
53
+ @Expose() @Transform(({ value }) => value ?? null)
54
+ @IsOptional() @IsIn(Object.values(RetailProductTierEnum)) tier!: RetailProductTier | null;
53
55
  @IsIn(Object.values(RetailCurrencyEnum)) currencyId!: RetailCurrency;
54
56
  @IsDefined() @IsObject() @ValidateNested() @Type(() => ProductEventPricePayload) price!: ProductEventPricePayload;
55
- @IsArray() @ArrayMaxSize(RETAIL_ELIGIBLE_FINANCIERS_MAX) @IsIn(Object.values(RetailFinancierEnum), { each: true }) eligibleFinanciers!: RetailFinancier[];
57
+ /** Opcional en el evento: ausente o `null` se vuelve la lista de todas las financieras. */
58
+ @Expose() @Transform(({ value }) => value ?? Object.values(RetailFinancierEnum))
59
+ @IsOptional() @IsArray() @ArrayNotEmpty() @ArrayUnique() @ArrayMaxSize(RETAIL_ELIGIBLE_FINANCIERS_MAX) @IsIn(Object.values(RetailFinancierEnum), { each: true })
60
+ eligibleFinanciers!: RetailFinancier[];
56
61
  @ValidateIf(isNullOrValidated) @IsIn(Object.values(RetailMdmProviderEnum)) mdmProvider!: RetailMdmProvider | null;
57
62
  @IsIn(Object.values(RetailProductStatusEnum)) status!: RetailProductStatus;
58
63
  }
@@ -1,4 +1,4 @@
1
- /** Gama de un producto. */
1
+ /** Gama de un producto; mismos valores que `ProductTierEnum` de retailCatalog. */
2
2
  export enum RetailProductTierEnum {
3
3
  LOW = 'LOW',
4
4
  MID = 'MID',