@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.
- package/_test_/unit/retailIntegration/eventPayloadBounds.test.ts +2 -2
- package/_test_/unit/retailIntegration/eventPayloads.test.ts +43 -2
- package/bin/retailIntegration/dtos/ProductEventPayload.d.ts +2 -0
- package/bin/retailIntegration/dtos/ProductEventPayload.js +8 -1
- package/bin/retailIntegration/enums/RetailProductTierEnum.d.ts +1 -1
- package/bin/retailIntegration/enums/RetailProductTierEnum.js +1 -1
- package/package.json +1 -1
- package/src/retailIntegration/dtos/ProductEventPayload.ts +9 -4
- package/src/retailIntegration/enums/RetailProductTierEnum.ts +1 -1
|
@@ -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:
|
|
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
|
-
['
|
|
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,
|
|
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,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,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
|
-
|
|
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
|
-
|
|
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
|
}
|