@fiado/type-kit 3.475.0 → 3.477.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 (34) hide show
  1. package/_test_/unit/retailCatalog/catalogDebt.test.ts +17 -0
  2. package/_test_/unit/retailCatalog/storeCatalogItemSaga.test.ts +18 -0
  3. package/_test_/unit/retailPromotions/constants.test.ts +20 -2
  4. package/_test_/unit/retailPromotions/discountCodeAndWizardRequests.test.ts +32 -3
  5. package/_test_/unit/retailPromotions/evaluatedSalePromotion.test.ts +2 -0
  6. package/_test_/unit/retailPromotions/resolveSalePromotionKind.test.ts +46 -0
  7. package/bin/retailCatalog/dtos/responses/GetInventorySkuResponse.d.ts +2 -0
  8. package/bin/retailCatalog/dtos/responses/StoreCatalogItem.d.ts +4 -0
  9. package/bin/retailPromotions/constants/retailPromotionsErrorHttpStatus.d.ts +2 -2
  10. package/bin/retailPromotions/constants/retailPromotionsErrorHttpStatus.js +9 -1
  11. package/bin/retailPromotions/dtos/requests/HoldGiftPromotionInput.d.ts +6 -0
  12. package/bin/retailPromotions/dtos/requests/HoldGiftPromotionInput.js +38 -0
  13. package/bin/retailPromotions/dtos/requests/HoldSalePromotionRequest.d.ts +14 -4
  14. package/bin/retailPromotions/dtos/requests/HoldSalePromotionRequest.js +12 -3
  15. package/bin/retailPromotions/dtos/responses/WizardSalePromotionResponses.d.ts +13 -2
  16. package/bin/retailPromotions/enums/RetailPromotionsErrorCodeEnum.d.ts +16 -1
  17. package/bin/retailPromotions/enums/RetailPromotionsErrorCodeEnum.js +15 -0
  18. package/bin/retailPromotions/enums/SalePromotionKindEnum.d.ts +8 -0
  19. package/bin/retailPromotions/enums/SalePromotionKindEnum.js +12 -0
  20. package/bin/retailPromotions/helpers/resolveSalePromotionKind.d.ts +4 -0
  21. package/bin/retailPromotions/helpers/resolveSalePromotionKind.js +10 -0
  22. package/bin/retailPromotions/index.d.ts +3 -0
  23. package/bin/retailPromotions/index.js +3 -0
  24. package/package.json +1 -1
  25. package/src/retailCatalog/dtos/responses/GetInventorySkuResponse.ts +2 -0
  26. package/src/retailCatalog/dtos/responses/StoreCatalogItem.ts +4 -0
  27. package/src/retailPromotions/constants/retailPromotionsErrorHttpStatus.ts +10 -2
  28. package/src/retailPromotions/dtos/requests/HoldGiftPromotionInput.ts +22 -0
  29. package/src/retailPromotions/dtos/requests/HoldSalePromotionRequest.ts +22 -6
  30. package/src/retailPromotions/dtos/responses/WizardSalePromotionResponses.ts +14 -2
  31. package/src/retailPromotions/enums/RetailPromotionsErrorCodeEnum.ts +15 -0
  32. package/src/retailPromotions/enums/SalePromotionKindEnum.ts +8 -0
  33. package/src/retailPromotions/helpers/resolveSalePromotionKind.ts +8 -0
  34. package/src/retailPromotions/index.ts +3 -0
@@ -121,3 +121,20 @@ describe('InventoryMovementEntry — reason', () => {
121
121
  expect(base.reason).toBeUndefined();
122
122
  });
123
123
  });
124
+
125
+ describe('InventoryMovementEntry — movementId', () => {
126
+ it('expone el id del MOV# y sigue válido sin él', () => {
127
+ const base: InventoryMovementEntry = {
128
+ storeId: 'ST-1',
129
+ sku: 'PH-A15',
130
+ type: InventoryMovementTypeEnum.ADJUSTMENT,
131
+ qty: 1,
132
+ identifier: null,
133
+ occurredAt: '2026-09-28T10:00:00.000Z',
134
+ createdBy: 'user-1',
135
+ };
136
+ const withId: InventoryMovementEntry = { ...base, movementId: 'MOV#01J9ZK' };
137
+ expect(withId.movementId).toBe('MOV#01J9ZK');
138
+ expect(base.movementId).toBeUndefined();
139
+ });
140
+ });
@@ -0,0 +1,18 @@
1
+ import 'reflect-metadata';
2
+ import * as RetailCatalog from '../../../src/retailCatalog';
3
+
4
+ type SagaFields = Pick<RetailCatalog.StoreCatalogItem, 'sku' | 'listPriceCents' | 'salePriority'>;
5
+
6
+ describe('StoreCatalogItem — campos de la venta saga', () => {
7
+ it('acepta listPriceCents y salePriority', () => {
8
+ const item: SagaFields = { sku: 'SKU-1', listPriceCents: 129900, salePriority: 80 };
9
+ expect(item.listPriceCents).toBe(129900);
10
+ expect(item.salePriority).toBe(80);
11
+ });
12
+
13
+ it('sigue válido sin listPriceCents ni salePriority', () => {
14
+ const item: SagaFields = { sku: 'SKU-1' };
15
+ expect(item.listPriceCents).toBeUndefined();
16
+ expect(item.salePriority).toBeUndefined();
17
+ });
18
+ });
@@ -38,12 +38,17 @@ describe('resolveSalePromotionTransition', () => {
38
38
  describe('catálogo de errores', () => {
39
39
  it('cada code tiene su status del catálogo cerrado', () => {
40
40
  for (const code of Object.values(RetailPromotionsErrorCodeEnum)) {
41
- expect([403, 404, 409, 422]).toContain(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS[code]);
41
+ expect([400, 403, 404, 409, 422, 502]).toContain(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS[code]);
42
42
  }
43
43
  expect(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS.CODE_NOT_FOUND).toBe(404);
44
44
  expect(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS.DISCOUNT_AFTER_QUOTE).toBe(409);
45
45
  expect(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS.CODE_NOT_OWNED).toBe(422);
46
- expect(Object.keys(RetailPromotionsErrorCodeEnum)).toHaveLength(20);
46
+ expect(Object.keys(RetailPromotionsErrorCodeEnum)).toHaveLength(28);
47
+ });
48
+
49
+ it('promo de regalo y de venta mandadas en el campo equivocado son 422', () => {
50
+ expect(RetailPromotionsErrorCodeEnum.PROMOTION_KIND_MISMATCH).toBe('PROMOTION_KIND_MISMATCH');
51
+ expect(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS.PROMOTION_KIND_MISMATCH).toBe(422);
47
52
  });
48
53
 
49
54
  it('promo o cupón de venta inexistentes son 404; sesión sin retailer o tienda es 403', () => {
@@ -53,6 +58,19 @@ describe('catálogo de errores', () => {
53
58
  expect(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS.MISSING_STORE_SCOPE).toBe(403);
54
59
  });
55
60
 
61
+ it.each([
62
+ ['SESSION_STILL_ACTIVE', 409],
63
+ ['WIZARD_SESSION_NOT_FOUND', 404],
64
+ ['UPSTREAM_UNAVAILABLE', 502],
65
+ ['MISSING_TENANT_SCOPE', 403],
66
+ ['PROMOTION_NOT_REVALIDATED', 409],
67
+ ['SALE_PROMOTION_HOLD_CONFLICT', 409],
68
+ ['INVALID_NEXT_TOKEN', 400],
69
+ ] as const)('%s es %i', (code, status) => {
70
+ expect(RetailPromotionsErrorCodeEnum[code]).toBe(code);
71
+ expect(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS[code]).toBe(status);
72
+ });
73
+
56
74
  it('promo y código con rangos, signo o palancas inválidos son 422', () => {
57
75
  expect(RetailPromotionsErrorCodeEnum.INVALID_SALE_PROMOTION).toBe('INVALID_SALE_PROMOTION');
58
76
  expect(RetailPromotionsErrorCodeEnum.INVALID_DISCOUNT_CODE).toBe('INVALID_DISCOUNT_CODE');
@@ -72,16 +72,45 @@ describe('piezas del wizard', () => {
72
72
  it('apartar acepta null como «Ninguna» y valida versión entera y SKUs de regalo', async () => {
73
73
  expect(await errorPaths(HoldSalePromotionRequest, { promotionId: null, discountCode: null })).toHaveLength(0);
74
74
  expect(
75
- await errorPaths(HoldSalePromotionRequest, { promotionId: 'p1', promotionVersion: 2, giftSkus: ['SKU-9'] }),
75
+ await errorPaths(HoldSalePromotionRequest, { promotionId: 'p1', promotionVersion: 2, saleGiftSkus: ['SKU-9'] }),
76
76
  ).toHaveLength(0);
77
77
  expect(
78
- await errorPaths(HoldSalePromotionRequest, { promotionId: 'p1', promotionVersion: '2', giftSkus: [1] }),
79
- ).toEqual(expect.arrayContaining(['promotionVersion', 'giftSkus']));
78
+ await errorPaths(HoldSalePromotionRequest, { promotionId: 'p1', promotionVersion: '2', saleGiftSkus: [1] }),
79
+ ).toEqual(expect.arrayContaining(['promotionVersion', 'saleGiftSkus']));
80
80
  });
81
81
 
82
82
  it('apartar pide versión cuando trae promo', async () => {
83
83
  expect(await errorPaths(HoldSalePromotionRequest, { promotionId: 'p1' })).toContain('promotionVersion');
84
84
  });
85
+
86
+ describe('gift (promo de regalo del teléfono)', () => {
87
+ const gift = { promotionId: 'g1', promotionVersion: 1, skus: ['SKU-1'] };
88
+
89
+ it('acepta la promo de regalo junto a la de venta, o null como sin regalo', async () => {
90
+ expect(
91
+ await errorPaths(HoldSalePromotionRequest, { gift, promotionId: 'p1', promotionVersion: 2 }),
92
+ ).toHaveLength(0);
93
+ expect(await errorPaths(HoldSalePromotionRequest, { gift, promotionId: null })).toHaveLength(0);
94
+ expect(await errorPaths(HoldSalePromotionRequest, { gift: null })).toHaveLength(0);
95
+ });
96
+
97
+ it('exige promotionId, versión desde 1 y al menos un sku no vacío', async () => {
98
+ const paths = await errorPaths(HoldSalePromotionRequest, {
99
+ gift: { promotionId: '', promotionVersion: 0, skus: [] },
100
+ });
101
+ expect(paths).toEqual(
102
+ expect.arrayContaining(['gift.promotionId', 'gift.promotionVersion', 'gift.skus']),
103
+ );
104
+ expect(await errorPaths(HoldSalePromotionRequest, { gift: { ...gift, skus: [''] } })).toContain('gift.skus');
105
+ expect(await errorPaths(HoldSalePromotionRequest, { gift: { ...gift, promotionVersion: 1.5 } })).toContain(
106
+ 'gift.promotionVersion',
107
+ );
108
+ });
109
+
110
+ it('rechaza un gift que no es objeto', async () => {
111
+ expect(await errorPaths(HoldSalePromotionRequest, { gift: 'g1' })).toContain('gift');
112
+ });
113
+ });
85
114
  });
86
115
 
87
116
  describe('GetSaleCouponQuery', () => {
@@ -2,11 +2,13 @@ import 'reflect-metadata';
2
2
  import {
3
3
  EvaluatedSalePromotion,
4
4
  RetailPromotionsErrorCodeEnum,
5
+ SalePromotionKindEnum,
5
6
  } from '../../../src/retailPromotions/index';
6
7
 
7
8
  const basePromotion: EvaluatedSalePromotion = {
8
9
  promotionId: 'promo-1',
9
10
  version: 1,
11
+ kind: SalePromotionKindEnum.SALE,
10
12
  name: 'Regalo',
11
13
  customerText: 'Llévate un regalo',
12
14
  levers: [],
@@ -0,0 +1,46 @@
1
+ import 'reflect-metadata';
2
+ import {
3
+ EvaluatedSalePromotion,
4
+ SalePromotionKindEnum,
5
+ SalePromotionLeverEnum,
6
+ resolveSalePromotionKind,
7
+ } from '../../../src/retailPromotions/index';
8
+
9
+ describe('resolveSalePromotionKind', () => {
10
+ it('devuelve GIFT cuando la única palanca es el regalo', () => {
11
+ expect(resolveSalePromotionKind([SalePromotionLeverEnum.GIFT])).toBe(SalePromotionKindEnum.GIFT);
12
+ });
13
+
14
+ it('devuelve SALE cuando el regalo viene con otras palancas', () => {
15
+ expect(
16
+ resolveSalePromotionKind([SalePromotionLeverEnum.GIFT, SalePromotionLeverEnum.DEVICE_DISCOUNT]),
17
+ ).toBe(SalePromotionKindEnum.SALE);
18
+ });
19
+
20
+ it('devuelve SALE cuando no hay regalo', () => {
21
+ expect(resolveSalePromotionKind([SalePromotionLeverEnum.COUPON])).toBe(SalePromotionKindEnum.SALE);
22
+ });
23
+
24
+ it('devuelve SALE sin palancas', () => {
25
+ expect(resolveSalePromotionKind([])).toBe(SalePromotionKindEnum.SALE);
26
+ });
27
+ });
28
+
29
+ describe('EvaluatedSalePromotion.kind', () => {
30
+ it('lleva el tipo de promo', () => {
31
+ const promotion: EvaluatedSalePromotion = {
32
+ promotionId: 'g1',
33
+ version: 1,
34
+ kind: SalePromotionKindEnum.GIFT,
35
+ name: 'Regalo',
36
+ customerText: 'Llévate un regalo',
37
+ levers: [SalePromotionLeverEnum.GIFT],
38
+ lines: [],
39
+ totalDiscountCents: 0,
40
+ giftOptions: [],
41
+ giftChooseCount: 1,
42
+ afterSale: [],
43
+ };
44
+ expect(promotion.kind).toBe(SalePromotionKindEnum.GIFT);
45
+ });
46
+ });
@@ -14,6 +14,8 @@ export interface InventoryMovementEntry {
14
14
  createdBy: string;
15
15
  /** Motivo guardado en el MOV#; ausente en los tipos que no llevan motivo. */
16
16
  reason?: InventoryMovementReasonEnum;
17
+ /** Id del MOV#, para ligar un ajuste con reversesMovementId. */
18
+ movementId?: string;
17
19
  }
18
20
  /** Pieza de una tienda; status AVAILABLE, SOLD o DAMAGED. */
19
21
  export interface InventoryPieceEntry {
@@ -36,6 +36,10 @@ export interface StoreCatalogItem {
36
36
  itemType?: ItemTypeEnum;
37
37
  /** Nombre visible para kits y servicios, que no tienen marca/modelo. */
38
38
  description?: string;
39
+ /** Precio de lista de respaldo para un regalo: el precio vigente o, si no hay, product.basePriceCents. */
40
+ listPriceCents?: number;
41
+ /** Prioridad de venta de 0 a 100; «Recomendados» ordena por ella. */
42
+ salePriority?: number;
39
43
  }
40
44
  /** Response de privateGetStoreStockCatalog. */
41
45
  export type GetStoreStockCatalogResponse = StoreCatalogItem[];
@@ -1,3 +1,3 @@
1
1
  import { RetailPromotionsErrorCodeEnum as C } from '../enums/RetailPromotionsErrorCodeEnum';
2
- /** Status HTTP de cada code: 403 sesión sin alcance · 404 no existe · 409 conflicto de estado · 422 regla de negocio. */
3
- export declare const RETAIL_PROMOTIONS_ERROR_HTTP_STATUS: Readonly<Record<C, 403 | 404 | 409 | 422>>;
2
+ /** Status HTTP de cada code: 400 request inválido · 403 sesión sin alcance · 404 no existe · 409 conflicto · 422 regla de negocio · 502 externo. */
3
+ export declare const RETAIL_PROMOTIONS_ERROR_HTTP_STATUS: Readonly<Record<C, 400 | 403 | 404 | 409 | 422 | 502>>;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RETAIL_PROMOTIONS_ERROR_HTTP_STATUS = void 0;
4
4
  const RetailPromotionsErrorCodeEnum_1 = require("../enums/RetailPromotionsErrorCodeEnum");
5
- /** Status HTTP de cada code: 403 sesión sin alcance · 404 no existe · 409 conflicto de estado · 422 regla de negocio. */
5
+ /** Status HTTP de cada code: 400 request inválido · 403 sesión sin alcance · 404 no existe · 409 conflicto · 422 regla de negocio · 502 externo. */
6
6
  exports.RETAIL_PROMOTIONS_ERROR_HTTP_STATUS = {
7
7
  [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.INVALID_PROMOTION_TRANSITION]: 409,
8
8
  [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.CODE_TEXT_TAKEN]: 409,
@@ -22,6 +22,14 @@ exports.RETAIL_PROMOTIONS_ERROR_HTTP_STATUS = {
22
22
  [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.INVALID_DISCOUNT_CODE]: 422,
23
23
  [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.SALE_PROMOTION_NOT_FOUND]: 404,
24
24
  [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.SALE_COUPON_NOT_FOUND]: 404,
25
+ [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.PROMOTION_KIND_MISMATCH]: 422,
25
26
  [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.MISSING_RETAILER_SCOPE]: 403,
26
27
  [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.MISSING_STORE_SCOPE]: 403,
28
+ [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.SESSION_STILL_ACTIVE]: 409,
29
+ [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.WIZARD_SESSION_NOT_FOUND]: 404,
30
+ [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.UPSTREAM_UNAVAILABLE]: 502,
31
+ [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.MISSING_TENANT_SCOPE]: 403,
32
+ [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.PROMOTION_NOT_REVALIDATED]: 409,
33
+ [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.SALE_PROMOTION_HOLD_CONFLICT]: 409,
34
+ [RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.INVALID_NEXT_TOKEN]: 400,
27
35
  };
@@ -0,0 +1,6 @@
1
+ /** Promo de regalo del teléfono dentro del apartado, con los regalos que eligió el cliente. */
2
+ export declare class HoldGiftPromotionInput {
3
+ promotionId: string;
4
+ promotionVersion: number;
5
+ skus: string[];
6
+ }
@@ -0,0 +1,38 @@
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.HoldGiftPromotionInput = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ /** Promo de regalo del teléfono dentro del apartado, con los regalos que eligió el cliente. */
16
+ class HoldGiftPromotionInput {
17
+ }
18
+ exports.HoldGiftPromotionInput = HoldGiftPromotionInput;
19
+ __decorate([
20
+ (0, class_transformer_1.Expose)(),
21
+ (0, class_validator_1.IsString)(),
22
+ (0, class_validator_1.IsNotEmpty)(),
23
+ __metadata("design:type", String)
24
+ ], HoldGiftPromotionInput.prototype, "promotionId", void 0);
25
+ __decorate([
26
+ (0, class_transformer_1.Expose)(),
27
+ (0, class_validator_1.IsInt)(),
28
+ (0, class_validator_1.Min)(1),
29
+ __metadata("design:type", Number)
30
+ ], HoldGiftPromotionInput.prototype, "promotionVersion", void 0);
31
+ __decorate([
32
+ (0, class_transformer_1.Expose)(),
33
+ (0, class_validator_1.IsArray)(),
34
+ (0, class_validator_1.ArrayMinSize)(1),
35
+ (0, class_validator_1.IsString)({ each: true }),
36
+ (0, class_validator_1.IsNotEmpty)({ each: true }),
37
+ __metadata("design:type", Array)
38
+ ], HoldGiftPromotionInput.prototype, "skus", void 0);
@@ -1,11 +1,21 @@
1
+ import { HoldGiftPromotionInput } from './HoldGiftPromotionInput';
1
2
  /**
2
- * Body de publicHoldSalePromotion (PUT, `sessionId` en el path). `promotionId: null` = «Ninguna»;
3
- * un PUT distinto reemplaza el apartado anterior.
3
+ * Body de publicHoldSalePromotion (PUT, `sessionId` en el path): hasta una promo de regalo, una de venta
4
+ * y un código. `null` en cada una = sin ella; un PUT distinto reemplaza el apartado anterior.
4
5
  */
5
6
  export declare class HoldSalePromotionRequest {
7
+ /**
8
+ * Promo de regalo del teléfono (su única palanca es el regalo).
9
+ * El lambda rechaza con PROMOTION_KIND_MISMATCH una promo de venta mandada aquí.
10
+ */
11
+ gift?: HoldGiftPromotionInput | null;
12
+ /**
13
+ * Promo de venta; `null` = «Ninguna».
14
+ * El lambda rechaza con PROMOTION_KIND_MISMATCH una promo de solo regalo mandada aquí.
15
+ */
6
16
  promotionId?: string | null;
7
17
  promotionVersion?: number | null;
8
- /** Regalos elegidos por el cliente, si la promo trae regalo. */
9
- giftSkus?: string[] | null;
18
+ /** Regalo incluido en la promo de venta, solo si esa promo además trae otras palancas. */
19
+ saleGiftSkus?: string[] | null;
10
20
  discountCode?: string | null;
11
21
  }
@@ -12,13 +12,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.HoldSalePromotionRequest = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
+ const HoldGiftPromotionInput_1 = require("./HoldGiftPromotionInput");
15
16
  /**
16
- * Body de publicHoldSalePromotion (PUT, `sessionId` en el path). `promotionId: null` = «Ninguna»;
17
- * un PUT distinto reemplaza el apartado anterior.
17
+ * Body de publicHoldSalePromotion (PUT, `sessionId` en el path): hasta una promo de regalo, una de venta
18
+ * y un código. `null` en cada una = sin ella; un PUT distinto reemplaza el apartado anterior.
18
19
  */
19
20
  class HoldSalePromotionRequest {
20
21
  }
21
22
  exports.HoldSalePromotionRequest = HoldSalePromotionRequest;
23
+ __decorate([
24
+ (0, class_transformer_1.Expose)(),
25
+ (0, class_validator_1.IsOptional)(),
26
+ (0, class_validator_1.IsObject)(),
27
+ (0, class_validator_1.ValidateNested)(),
28
+ (0, class_transformer_1.Type)(() => HoldGiftPromotionInput_1.HoldGiftPromotionInput),
29
+ __metadata("design:type", HoldGiftPromotionInput_1.HoldGiftPromotionInput)
30
+ ], HoldSalePromotionRequest.prototype, "gift", void 0);
22
31
  __decorate([
23
32
  (0, class_transformer_1.Expose)(),
24
33
  (0, class_validator_1.IsOptional)(),
@@ -38,7 +47,7 @@ __decorate([
38
47
  (0, class_validator_1.IsArray)(),
39
48
  (0, class_validator_1.IsString)({ each: true }),
40
49
  __metadata("design:type", Array)
41
- ], HoldSalePromotionRequest.prototype, "giftSkus", void 0);
50
+ ], HoldSalePromotionRequest.prototype, "saleGiftSkus", void 0);
42
51
  __decorate([
43
52
  (0, class_transformer_1.Expose)(),
44
53
  (0, class_validator_1.IsOptional)(),
@@ -4,6 +4,7 @@ import { EntitlementKindEnum } from '../../enums/EntitlementKindEnum';
4
4
  import { EntitlementStateEnum } from '../../enums/EntitlementStateEnum';
5
5
  import { RetailPromotionsErrorCodeEnum } from '../../enums/RetailPromotionsErrorCodeEnum';
6
6
  import { SaleCouponAvailabilityEnum } from '../../enums/SaleCouponAvailabilityEnum';
7
+ import { SalePromotionKindEnum } from '../../enums/SalePromotionKindEnum';
7
8
  import { SalePromotionLeverEnum } from '../../enums/SalePromotionLeverEnum';
8
9
  import { DiscountValue } from '../DiscountValue';
9
10
  import { LinePromotionDiscount } from '../LinePromotionDiscount';
@@ -38,6 +39,8 @@ export interface AfterSaleBenefit {
38
39
  export interface EvaluatedSalePromotion {
39
40
  promotionId: string;
40
41
  version: number;
42
+ /** GIFT = solo regalo, se aparta por separado en `gift`; SALE = promo de venta. */
43
+ kind: SalePromotionKindEnum;
41
44
  name: string;
42
45
  customerText: string;
43
46
  levers: SalePromotionLeverEnum[];
@@ -61,13 +64,21 @@ export interface EvaluateSalePromotionsResponse {
61
64
  promotions: EvaluatedSalePromotion[];
62
65
  discountCode: EvaluatedDiscountCode | null;
63
66
  }
64
- /** Lo que quedó apartado y escrito en la sesión. */
67
+ /** Promo de regalo del teléfono que quedó apartada. */
68
+ export interface HeldGiftPromotion {
69
+ promotionId: string;
70
+ promotionVersion: number;
71
+ skus: string[];
72
+ }
73
+ /** Lo que quedó apartado y escrito en la sesión: la promo de regalo, la de venta y el código. */
65
74
  export interface HoldSalePromotionResponse {
66
75
  sessionId: string;
76
+ gift: HeldGiftPromotion | null;
67
77
  promotionId: string | null;
68
78
  promotionVersion: number | null;
69
79
  discountCode: string | null;
70
- giftSkus: string[];
80
+ /** Regalo incluido en la promo de venta; vacío si no trae. */
81
+ saleGiftSkus: string[];
71
82
  lines: LinePromotionDiscount[];
72
83
  totalDiscountCents: number;
73
84
  }
@@ -22,8 +22,23 @@ export declare enum RetailPromotionsErrorCodeEnum {
22
22
  INVALID_DISCOUNT_CODE = "INVALID_DISCOUNT_CODE",
23
23
  SALE_PROMOTION_NOT_FOUND = "SALE_PROMOTION_NOT_FOUND",
24
24
  SALE_COUPON_NOT_FOUND = "SALE_COUPON_NOT_FOUND",
25
+ /** Promo de solo regalo mandada como promo de venta, o promo de venta mandada en `gift`. */
26
+ PROMOTION_KIND_MISMATCH = "PROMOTION_KIND_MISMATCH",
25
27
  /** La sesión no trae retailer: no se puede acotar la consulta. */
26
28
  MISSING_RETAILER_SCOPE = "MISSING_RETAILER_SCOPE",
27
29
  /** La sesión no trae tienda: no se puede acotar la consulta. */
28
- MISSING_STORE_SCOPE = "MISSING_STORE_SCOPE"
30
+ MISSING_STORE_SCOPE = "MISSING_STORE_SCOPE",
31
+ /** La sesión del wizard sigue abierta y no admite la operación. */
32
+ SESSION_STILL_ACTIVE = "SESSION_STILL_ACTIVE",
33
+ WIZARD_SESSION_NOT_FOUND = "WIZARD_SESSION_NOT_FOUND",
34
+ /** Un servicio externo falló o no respondió. */
35
+ UPSTREAM_UNAVAILABLE = "UPSTREAM_UNAVAILABLE",
36
+ /** La sesión no trae tenant: no se puede acotar la consulta. */
37
+ MISSING_TENANT_SCOPE = "MISSING_TENANT_SCOPE",
38
+ /** La promo no se revalidó antes de cobrar. */
39
+ PROMOTION_NOT_REVALIDATED = "PROMOTION_NOT_REVALIDATED",
40
+ /** Otra venta ya retiene la promo. */
41
+ SALE_PROMOTION_HOLD_CONFLICT = "SALE_PROMOTION_HOLD_CONFLICT",
42
+ /** El token de paginación no es válido. */
43
+ INVALID_NEXT_TOKEN = "INVALID_NEXT_TOKEN"
29
44
  }
@@ -26,8 +26,23 @@ var RetailPromotionsErrorCodeEnum;
26
26
  RetailPromotionsErrorCodeEnum["INVALID_DISCOUNT_CODE"] = "INVALID_DISCOUNT_CODE";
27
27
  RetailPromotionsErrorCodeEnum["SALE_PROMOTION_NOT_FOUND"] = "SALE_PROMOTION_NOT_FOUND";
28
28
  RetailPromotionsErrorCodeEnum["SALE_COUPON_NOT_FOUND"] = "SALE_COUPON_NOT_FOUND";
29
+ /** Promo de solo regalo mandada como promo de venta, o promo de venta mandada en `gift`. */
30
+ RetailPromotionsErrorCodeEnum["PROMOTION_KIND_MISMATCH"] = "PROMOTION_KIND_MISMATCH";
29
31
  /** La sesión no trae retailer: no se puede acotar la consulta. */
30
32
  RetailPromotionsErrorCodeEnum["MISSING_RETAILER_SCOPE"] = "MISSING_RETAILER_SCOPE";
31
33
  /** La sesión no trae tienda: no se puede acotar la consulta. */
32
34
  RetailPromotionsErrorCodeEnum["MISSING_STORE_SCOPE"] = "MISSING_STORE_SCOPE";
35
+ /** La sesión del wizard sigue abierta y no admite la operación. */
36
+ RetailPromotionsErrorCodeEnum["SESSION_STILL_ACTIVE"] = "SESSION_STILL_ACTIVE";
37
+ RetailPromotionsErrorCodeEnum["WIZARD_SESSION_NOT_FOUND"] = "WIZARD_SESSION_NOT_FOUND";
38
+ /** Un servicio externo falló o no respondió. */
39
+ RetailPromotionsErrorCodeEnum["UPSTREAM_UNAVAILABLE"] = "UPSTREAM_UNAVAILABLE";
40
+ /** La sesión no trae tenant: no se puede acotar la consulta. */
41
+ RetailPromotionsErrorCodeEnum["MISSING_TENANT_SCOPE"] = "MISSING_TENANT_SCOPE";
42
+ /** La promo no se revalidó antes de cobrar. */
43
+ RetailPromotionsErrorCodeEnum["PROMOTION_NOT_REVALIDATED"] = "PROMOTION_NOT_REVALIDATED";
44
+ /** Otra venta ya retiene la promo. */
45
+ RetailPromotionsErrorCodeEnum["SALE_PROMOTION_HOLD_CONFLICT"] = "SALE_PROMOTION_HOLD_CONFLICT";
46
+ /** El token de paginación no es válido. */
47
+ RetailPromotionsErrorCodeEnum["INVALID_NEXT_TOKEN"] = "INVALID_NEXT_TOKEN";
33
48
  })(RetailPromotionsErrorCodeEnum || (exports.RetailPromotionsErrorCodeEnum = RetailPromotionsErrorCodeEnum = {}));
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tipo de promo en el apartado: GIFT solo trae regalo y va ligada al teléfono; SALE es cualquier otra.
3
+ * @enum {string}
4
+ */
5
+ export declare enum SalePromotionKindEnum {
6
+ GIFT = "GIFT",
7
+ SALE = "SALE"
8
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SalePromotionKindEnum = void 0;
4
+ /**
5
+ * Tipo de promo en el apartado: GIFT solo trae regalo y va ligada al teléfono; SALE es cualquier otra.
6
+ * @enum {string}
7
+ */
8
+ var SalePromotionKindEnum;
9
+ (function (SalePromotionKindEnum) {
10
+ SalePromotionKindEnum["GIFT"] = "GIFT";
11
+ SalePromotionKindEnum["SALE"] = "SALE";
12
+ })(SalePromotionKindEnum || (exports.SalePromotionKindEnum = SalePromotionKindEnum = {}));
@@ -0,0 +1,4 @@
1
+ import { SalePromotionKindEnum } from '../enums/SalePromotionKindEnum';
2
+ import { SalePromotionLeverEnum } from '../enums/SalePromotionLeverEnum';
3
+ /** GIFT si la única palanca de la promo es el regalo; SALE en cualquier otro caso. */
4
+ export declare function resolveSalePromotionKind(levers: readonly SalePromotionLeverEnum[]): SalePromotionKindEnum;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveSalePromotionKind = resolveSalePromotionKind;
4
+ const SalePromotionKindEnum_1 = require("../enums/SalePromotionKindEnum");
5
+ const SalePromotionLeverEnum_1 = require("../enums/SalePromotionLeverEnum");
6
+ /** GIFT si la única palanca de la promo es el regalo; SALE en cualquier otro caso. */
7
+ function resolveSalePromotionKind(levers) {
8
+ const onlyGift = levers.length > 0 && levers.every((lever) => lever === SalePromotionLeverEnum_1.SalePromotionLeverEnum.GIFT);
9
+ return onlyGift ? SalePromotionKindEnum_1.SalePromotionKindEnum.GIFT : SalePromotionKindEnum_1.SalePromotionKindEnum.SALE;
10
+ }
@@ -16,11 +16,13 @@ export * from './enums/EntitlementStateEnum';
16
16
  export * from './enums/EntitlementKindEnum';
17
17
  export * from './enums/SaleCouponAvailabilityEnum';
18
18
  export * from './enums/RetailPromotionsErrorCodeEnum';
19
+ export * from './enums/SalePromotionKindEnum';
19
20
  export * from './constants/retailPromotionsErrorHttpStatus';
20
21
  export * from './constants/salePromotionTransitions';
21
22
  export * from './constants/bonusPreMoney';
22
23
  export * from './helpers/resolveSalePromotionTransition';
23
24
  export * from './helpers/computeBudgetUsedBps';
25
+ export * from './helpers/resolveSalePromotionKind';
24
26
  export * from './dtos/DiscountValue';
25
27
  export * from './dtos/SalePromotionLevers';
26
28
  export * from './dtos/SalePromotion';
@@ -40,6 +42,7 @@ export * from './dtos/requests/ListDiscountCodesQuery';
40
42
  export * from './dtos/requests/ChangeDiscountCodeStatusRequest';
41
43
  export * from './dtos/requests/ListStoreSalePromotionsQuery';
42
44
  export * from './dtos/requests/EvaluateSalePromotionsRequest';
45
+ export * from './dtos/requests/HoldGiftPromotionInput';
43
46
  export * from './dtos/requests/HoldSalePromotionRequest';
44
47
  export * from './dtos/requests/GetSaleCouponQuery';
45
48
  export * from './dtos/responses/SalePromotionCrudResponses';
@@ -33,12 +33,14 @@ __exportStar(require("./enums/EntitlementStateEnum"), exports);
33
33
  __exportStar(require("./enums/EntitlementKindEnum"), exports);
34
34
  __exportStar(require("./enums/SaleCouponAvailabilityEnum"), exports);
35
35
  __exportStar(require("./enums/RetailPromotionsErrorCodeEnum"), exports);
36
+ __exportStar(require("./enums/SalePromotionKindEnum"), exports);
36
37
  // Constantes y helpers puros
37
38
  __exportStar(require("./constants/retailPromotionsErrorHttpStatus"), exports);
38
39
  __exportStar(require("./constants/salePromotionTransitions"), exports);
39
40
  __exportStar(require("./constants/bonusPreMoney"), exports);
40
41
  __exportStar(require("./helpers/resolveSalePromotionTransition"), exports);
41
42
  __exportStar(require("./helpers/computeBudgetUsedBps"), exports);
43
+ __exportStar(require("./helpers/resolveSalePromotionKind"), exports);
42
44
  // Entidades del dominio
43
45
  __exportStar(require("./dtos/DiscountValue"), exports);
44
46
  __exportStar(require("./dtos/SalePromotionLevers"), exports);
@@ -60,6 +62,7 @@ __exportStar(require("./dtos/requests/ListDiscountCodesQuery"), exports);
60
62
  __exportStar(require("./dtos/requests/ChangeDiscountCodeStatusRequest"), exports);
61
63
  __exportStar(require("./dtos/requests/ListStoreSalePromotionsQuery"), exports);
62
64
  __exportStar(require("./dtos/requests/EvaluateSalePromotionsRequest"), exports);
65
+ __exportStar(require("./dtos/requests/HoldGiftPromotionInput"), exports);
63
66
  __exportStar(require("./dtos/requests/HoldSalePromotionRequest"), exports);
64
67
  __exportStar(require("./dtos/requests/GetSaleCouponQuery"), exports);
65
68
  // Response DTOs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.475.0",
3
+ "version": "3.477.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -15,6 +15,8 @@ export interface InventoryMovementEntry {
15
15
  createdBy: string;
16
16
  /** Motivo guardado en el MOV#; ausente en los tipos que no llevan motivo. */
17
17
  reason?: InventoryMovementReasonEnum;
18
+ /** Id del MOV#, para ligar un ajuste con reversesMovementId. */
19
+ movementId?: string;
18
20
  }
19
21
 
20
22
  /** Pieza de una tienda; status AVAILABLE, SOLD o DAMAGED. */
@@ -38,6 +38,10 @@ export interface StoreCatalogItem {
38
38
  itemType?: ItemTypeEnum;
39
39
  /** Nombre visible para kits y servicios, que no tienen marca/modelo. */
40
40
  description?: string;
41
+ /** Precio de lista de respaldo para un regalo: el precio vigente o, si no hay, product.basePriceCents. */
42
+ listPriceCents?: number;
43
+ /** Prioridad de venta de 0 a 100; «Recomendados» ordena por ella. */
44
+ salePriority?: number;
41
45
  }
42
46
 
43
47
  /** Response de privateGetStoreStockCatalog. */
@@ -1,7 +1,7 @@
1
1
  import { RetailPromotionsErrorCodeEnum as C } from '../enums/RetailPromotionsErrorCodeEnum';
2
2
 
3
- /** Status HTTP de cada code: 403 sesión sin alcance · 404 no existe · 409 conflicto de estado · 422 regla de negocio. */
4
- export const RETAIL_PROMOTIONS_ERROR_HTTP_STATUS: Readonly<Record<C, 403 | 404 | 409 | 422>> = {
3
+ /** Status HTTP de cada code: 400 request inválido · 403 sesión sin alcance · 404 no existe · 409 conflicto · 422 regla de negocio · 502 externo. */
4
+ export const RETAIL_PROMOTIONS_ERROR_HTTP_STATUS: Readonly<Record<C, 400 | 403 | 404 | 409 | 422 | 502>> = {
5
5
  [C.INVALID_PROMOTION_TRANSITION]: 409,
6
6
  [C.CODE_TEXT_TAKEN]: 409,
7
7
  [C.PROMOTION_NOT_ACTIVE]: 409,
@@ -20,6 +20,14 @@ export const RETAIL_PROMOTIONS_ERROR_HTTP_STATUS: Readonly<Record<C, 403 | 404 |
20
20
  [C.INVALID_DISCOUNT_CODE]: 422,
21
21
  [C.SALE_PROMOTION_NOT_FOUND]: 404,
22
22
  [C.SALE_COUPON_NOT_FOUND]: 404,
23
+ [C.PROMOTION_KIND_MISMATCH]: 422,
23
24
  [C.MISSING_RETAILER_SCOPE]: 403,
24
25
  [C.MISSING_STORE_SCOPE]: 403,
26
+ [C.SESSION_STILL_ACTIVE]: 409,
27
+ [C.WIZARD_SESSION_NOT_FOUND]: 404,
28
+ [C.UPSTREAM_UNAVAILABLE]: 502,
29
+ [C.MISSING_TENANT_SCOPE]: 403,
30
+ [C.PROMOTION_NOT_REVALIDATED]: 409,
31
+ [C.SALE_PROMOTION_HOLD_CONFLICT]: 409,
32
+ [C.INVALID_NEXT_TOKEN]: 400,
25
33
  };
@@ -0,0 +1,22 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { ArrayMinSize, IsArray, IsInt, IsNotEmpty, IsString, Min } from 'class-validator';
3
+
4
+ /** Promo de regalo del teléfono dentro del apartado, con los regalos que eligió el cliente. */
5
+ export class HoldGiftPromotionInput {
6
+ @Expose()
7
+ @IsString()
8
+ @IsNotEmpty()
9
+ promotionId!: string;
10
+
11
+ @Expose()
12
+ @IsInt()
13
+ @Min(1)
14
+ promotionVersion!: number;
15
+
16
+ @Expose()
17
+ @IsArray()
18
+ @ArrayMinSize(1)
19
+ @IsString({ each: true })
20
+ @IsNotEmpty({ each: true })
21
+ skus!: string[];
22
+ }
@@ -1,11 +1,27 @@
1
- import { Expose } from 'class-transformer';
2
- import { IsArray, IsInt, IsNotEmpty, IsOptional, IsString, ValidateIf } from 'class-validator';
1
+ import { Expose, Type } from 'class-transformer';
2
+ import { IsArray, IsInt, IsNotEmpty, IsObject, IsOptional, IsString, ValidateIf, ValidateNested } from 'class-validator';
3
+ import { HoldGiftPromotionInput } from './HoldGiftPromotionInput';
3
4
 
4
5
  /**
5
- * Body de publicHoldSalePromotion (PUT, `sessionId` en el path). `promotionId: null` = «Ninguna»;
6
- * un PUT distinto reemplaza el apartado anterior.
6
+ * Body de publicHoldSalePromotion (PUT, `sessionId` en el path): hasta una promo de regalo, una de venta
7
+ * y un código. `null` en cada una = sin ella; un PUT distinto reemplaza el apartado anterior.
7
8
  */
8
9
  export class HoldSalePromotionRequest {
10
+ /**
11
+ * Promo de regalo del teléfono (su única palanca es el regalo).
12
+ * El lambda rechaza con PROMOTION_KIND_MISMATCH una promo de venta mandada aquí.
13
+ */
14
+ @Expose()
15
+ @IsOptional()
16
+ @IsObject()
17
+ @ValidateNested()
18
+ @Type(() => HoldGiftPromotionInput)
19
+ gift?: HoldGiftPromotionInput | null;
20
+
21
+ /**
22
+ * Promo de venta; `null` = «Ninguna».
23
+ * El lambda rechaza con PROMOTION_KIND_MISMATCH una promo de solo regalo mandada aquí.
24
+ */
9
25
  @Expose()
10
26
  @IsOptional()
11
27
  @IsString()
@@ -17,12 +33,12 @@ export class HoldSalePromotionRequest {
17
33
  @IsInt()
18
34
  promotionVersion?: number | null;
19
35
 
20
- /** Regalos elegidos por el cliente, si la promo trae regalo. */
36
+ /** Regalo incluido en la promo de venta, solo si esa promo además trae otras palancas. */
21
37
  @Expose()
22
38
  @IsOptional()
23
39
  @IsArray()
24
40
  @IsString({ each: true })
25
- giftSkus?: string[] | null;
41
+ saleGiftSkus?: string[] | null;
26
42
 
27
43
  @Expose()
28
44
  @IsOptional()
@@ -4,6 +4,7 @@ import { EntitlementKindEnum } from '../../enums/EntitlementKindEnum';
4
4
  import { EntitlementStateEnum } from '../../enums/EntitlementStateEnum';
5
5
  import { RetailPromotionsErrorCodeEnum } from '../../enums/RetailPromotionsErrorCodeEnum';
6
6
  import { SaleCouponAvailabilityEnum } from '../../enums/SaleCouponAvailabilityEnum';
7
+ import { SalePromotionKindEnum } from '../../enums/SalePromotionKindEnum';
7
8
  import { SalePromotionLeverEnum } from '../../enums/SalePromotionLeverEnum';
8
9
  import { DiscountValue } from '../DiscountValue';
9
10
  import { LinePromotionDiscount } from '../LinePromotionDiscount';
@@ -43,6 +44,8 @@ export interface AfterSaleBenefit {
43
44
  export interface EvaluatedSalePromotion {
44
45
  promotionId: string;
45
46
  version: number;
47
+ /** GIFT = solo regalo, se aparta por separado en `gift`; SALE = promo de venta. */
48
+ kind: SalePromotionKindEnum;
46
49
  name: string;
47
50
  customerText: string;
48
51
  levers: SalePromotionLeverEnum[];
@@ -69,13 +72,22 @@ export interface EvaluateSalePromotionsResponse {
69
72
  discountCode: EvaluatedDiscountCode | null;
70
73
  }
71
74
 
72
- /** Lo que quedó apartado y escrito en la sesión. */
75
+ /** Promo de regalo del teléfono que quedó apartada. */
76
+ export interface HeldGiftPromotion {
77
+ promotionId: string;
78
+ promotionVersion: number;
79
+ skus: string[];
80
+ }
81
+
82
+ /** Lo que quedó apartado y escrito en la sesión: la promo de regalo, la de venta y el código. */
73
83
  export interface HoldSalePromotionResponse {
74
84
  sessionId: string;
85
+ gift: HeldGiftPromotion | null;
75
86
  promotionId: string | null;
76
87
  promotionVersion: number | null;
77
88
  discountCode: string | null;
78
- giftSkus: string[];
89
+ /** Regalo incluido en la promo de venta; vacío si no trae. */
90
+ saleGiftSkus: string[];
79
91
  lines: LinePromotionDiscount[];
80
92
  totalDiscountCents: number;
81
93
  }
@@ -22,8 +22,23 @@ export enum RetailPromotionsErrorCodeEnum {
22
22
  INVALID_DISCOUNT_CODE = 'INVALID_DISCOUNT_CODE',
23
23
  SALE_PROMOTION_NOT_FOUND = 'SALE_PROMOTION_NOT_FOUND',
24
24
  SALE_COUPON_NOT_FOUND = 'SALE_COUPON_NOT_FOUND',
25
+ /** Promo de solo regalo mandada como promo de venta, o promo de venta mandada en `gift`. */
26
+ PROMOTION_KIND_MISMATCH = 'PROMOTION_KIND_MISMATCH',
25
27
  /** La sesión no trae retailer: no se puede acotar la consulta. */
26
28
  MISSING_RETAILER_SCOPE = 'MISSING_RETAILER_SCOPE',
27
29
  /** La sesión no trae tienda: no se puede acotar la consulta. */
28
30
  MISSING_STORE_SCOPE = 'MISSING_STORE_SCOPE',
31
+ /** La sesión del wizard sigue abierta y no admite la operación. */
32
+ SESSION_STILL_ACTIVE = 'SESSION_STILL_ACTIVE',
33
+ WIZARD_SESSION_NOT_FOUND = 'WIZARD_SESSION_NOT_FOUND',
34
+ /** Un servicio externo falló o no respondió. */
35
+ UPSTREAM_UNAVAILABLE = 'UPSTREAM_UNAVAILABLE',
36
+ /** La sesión no trae tenant: no se puede acotar la consulta. */
37
+ MISSING_TENANT_SCOPE = 'MISSING_TENANT_SCOPE',
38
+ /** La promo no se revalidó antes de cobrar. */
39
+ PROMOTION_NOT_REVALIDATED = 'PROMOTION_NOT_REVALIDATED',
40
+ /** Otra venta ya retiene la promo. */
41
+ SALE_PROMOTION_HOLD_CONFLICT = 'SALE_PROMOTION_HOLD_CONFLICT',
42
+ /** El token de paginación no es válido. */
43
+ INVALID_NEXT_TOKEN = 'INVALID_NEXT_TOKEN',
29
44
  }
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Tipo de promo en el apartado: GIFT solo trae regalo y va ligada al teléfono; SALE es cualquier otra.
3
+ * @enum {string}
4
+ */
5
+ export enum SalePromotionKindEnum {
6
+ GIFT = 'GIFT',
7
+ SALE = 'SALE',
8
+ }
@@ -0,0 +1,8 @@
1
+ import { SalePromotionKindEnum } from '../enums/SalePromotionKindEnum';
2
+ import { SalePromotionLeverEnum } from '../enums/SalePromotionLeverEnum';
3
+
4
+ /** GIFT si la única palanca de la promo es el regalo; SALE en cualquier otro caso. */
5
+ export function resolveSalePromotionKind(levers: readonly SalePromotionLeverEnum[]): SalePromotionKindEnum {
6
+ const onlyGift = levers.length > 0 && levers.every((lever) => lever === SalePromotionLeverEnum.GIFT);
7
+ return onlyGift ? SalePromotionKindEnum.GIFT : SalePromotionKindEnum.SALE;
8
+ }
@@ -17,6 +17,7 @@ export * from './enums/EntitlementStateEnum';
17
17
  export * from './enums/EntitlementKindEnum';
18
18
  export * from './enums/SaleCouponAvailabilityEnum';
19
19
  export * from './enums/RetailPromotionsErrorCodeEnum';
20
+ export * from './enums/SalePromotionKindEnum';
20
21
 
21
22
  // Constantes y helpers puros
22
23
  export * from './constants/retailPromotionsErrorHttpStatus';
@@ -24,6 +25,7 @@ export * from './constants/salePromotionTransitions';
24
25
  export * from './constants/bonusPreMoney';
25
26
  export * from './helpers/resolveSalePromotionTransition';
26
27
  export * from './helpers/computeBudgetUsedBps';
28
+ export * from './helpers/resolveSalePromotionKind';
27
29
 
28
30
  // Entidades del dominio
29
31
  export * from './dtos/DiscountValue';
@@ -47,6 +49,7 @@ export * from './dtos/requests/ListDiscountCodesQuery';
47
49
  export * from './dtos/requests/ChangeDiscountCodeStatusRequest';
48
50
  export * from './dtos/requests/ListStoreSalePromotionsQuery';
49
51
  export * from './dtos/requests/EvaluateSalePromotionsRequest';
52
+ export * from './dtos/requests/HoldGiftPromotionInput';
50
53
  export * from './dtos/requests/HoldSalePromotionRequest';
51
54
  export * from './dtos/requests/GetSaleCouponQuery';
52
55