@fiado/type-kit 3.500.0 → 3.501.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/retailPromotions/constants.test.ts +1 -1
- package/_test_/unit/retailPromotions/evaluatedSalePromotion.test.ts +2 -0
- package/_test_/unit/retailPromotions/resolveSalePromotionKind.test.ts +2 -0
- package/_test_/unit/retailPromotions/salePromotionConditions.test.ts +4 -0
- package/_test_/unit/retailPromotions/stackablePromotions.test.ts +238 -0
- package/bin/retailPromotions/constants/retailPromotionsErrorHttpStatus.js +1 -0
- package/bin/retailPromotions/dtos/LinePromotionAmount.d.ts +6 -0
- package/bin/retailPromotions/dtos/LinePromotionAmount.js +36 -0
- package/bin/retailPromotions/dtos/LinePromotionDiscount.d.ts +4 -0
- package/bin/retailPromotions/dtos/SalePromotion.d.ts +2 -0
- package/bin/retailPromotions/dtos/SalePromotionRef.d.ts +5 -0
- package/bin/retailPromotions/dtos/SalePromotionRef.js +30 -0
- package/bin/retailPromotions/dtos/requests/CreateSalePromotionRequest.d.ts +2 -0
- package/bin/retailPromotions/dtos/requests/CreateSalePromotionRequest.js +6 -0
- package/bin/retailPromotions/dtos/requests/HoldPromotionInput.d.ts +8 -0
- package/bin/retailPromotions/dtos/requests/HoldPromotionInput.js +46 -0
- package/bin/retailPromotions/dtos/requests/HoldSalePromotionRequest.d.ts +9 -3
- package/bin/retailPromotions/dtos/requests/HoldSalePromotionRequest.js +11 -0
- package/bin/retailPromotions/dtos/requests/UpdateSalePromotionRequest.d.ts +2 -0
- package/bin/retailPromotions/dtos/requests/UpdateSalePromotionRequest.js +6 -0
- package/bin/retailPromotions/dtos/responses/WizardSalePromotionResponses.d.ts +20 -0
- package/bin/retailPromotions/enums/RetailPromotionsErrorCodeEnum.d.ts +3 -1
- package/bin/retailPromotions/enums/RetailPromotionsErrorCodeEnum.js +2 -0
- package/bin/retailPromotions/index.d.ts +4 -0
- package/bin/retailPromotions/index.js +5 -0
- package/bin/retailPromotions/validators/IsHoldModeExclusiveConstraint.d.ts +6 -0
- package/bin/retailPromotions/validators/IsHoldModeExclusiveConstraint.js +24 -0
- package/bin/retailWizard/dtos/Sale.d.ts +3 -0
- package/bin/retailWizard/dtos/WizardLinePromotionFields.d.ts +4 -0
- package/bin/retailWizard/dtos/WizardSession.d.ts +3 -0
- package/bin/retailWizard/dtos/requests/ApplyLinePromotionRequest.d.ts +5 -0
- package/bin/retailWizard/dtos/requests/ApplyLinePromotionRequest.js +16 -0
- package/bin/retailWizard/dtos/requests/ApplySalePromotionRequest.d.ts +3 -0
- package/bin/retailWizard/dtos/requests/ApplySalePromotionRequest.js +9 -0
- package/bin/retailWizard/dtos/responses/PrivateWizardSessionResponse.d.ts +3 -0
- package/bin/retailWizard/events/RetailPromotionInboundMessage.d.ts +8 -0
- package/bin/retailWizard/events/RetailPromotionInboundMessage.js +22 -0
- package/bin/retailWizard/index.d.ts +2 -0
- package/bin/retailWizard/index.js +5 -0
- package/package.json +1 -1
- package/src/retailPromotions/constants/retailPromotionsErrorHttpStatus.ts +1 -0
- package/src/retailPromotions/dtos/LinePromotionAmount.ts +20 -0
- package/src/retailPromotions/dtos/LinePromotionDiscount.ts +5 -0
- package/src/retailPromotions/dtos/SalePromotion.ts +2 -0
- package/src/retailPromotions/dtos/SalePromotionRef.ts +15 -0
- package/src/retailPromotions/dtos/requests/CreateSalePromotionRequest.ts +6 -0
- package/src/retailPromotions/dtos/requests/HoldPromotionInput.ts +30 -0
- package/src/retailPromotions/dtos/requests/HoldSalePromotionRequest.ts +28 -4
- package/src/retailPromotions/dtos/requests/UpdateSalePromotionRequest.ts +6 -0
- package/src/retailPromotions/dtos/responses/WizardSalePromotionResponses.ts +21 -0
- package/src/retailPromotions/enums/RetailPromotionsErrorCodeEnum.ts +2 -0
- package/src/retailPromotions/index.ts +6 -0
- package/src/retailPromotions/validators/IsHoldModeExclusiveConstraint.ts +18 -0
- package/src/retailWizard/dtos/Sale.ts +3 -0
- package/src/retailWizard/dtos/WizardLinePromotionFields.ts +4 -0
- package/src/retailWizard/dtos/WizardSession.ts +3 -0
- package/src/retailWizard/dtos/requests/ApplyLinePromotionRequest.ts +18 -2
- package/src/retailWizard/dtos/requests/ApplySalePromotionRequest.ts +11 -2
- package/src/retailWizard/dtos/responses/PrivateWizardSessionResponse.ts +3 -0
- package/src/retailWizard/events/RetailPromotionInboundMessage.ts +22 -0
- package/src/retailWizard/index.ts +2 -0
|
@@ -43,7 +43,7 @@ describe('catálogo de errores', () => {
|
|
|
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(
|
|
46
|
+
expect(Object.keys(RetailPromotionsErrorCodeEnum)).toHaveLength(31);
|
|
47
47
|
expect(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS.SPLIT_FINANCING_DISABLED).toBe(409);
|
|
48
48
|
});
|
|
49
49
|
|
|
@@ -16,6 +16,8 @@ const storeItem: StoreSalePromotionItem = {
|
|
|
16
16
|
levers: { gift: null, deviceDiscount: null, accessoryDiscount: null, coupon: null, walletBonus: null, extendedWarranty: null, airtime: null },
|
|
17
17
|
scope: { storeIds: null, productCategories: null, tiers: null, skus: null },
|
|
18
18
|
appliesTo: PromotionAppliesToEnum.ANY_FINANCIER,
|
|
19
|
+
stackable: false,
|
|
20
|
+
anchorBound: false,
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
const evaluated: EvaluatedSalePromotion = {
|
|
@@ -31,6 +33,8 @@ const evaluated: EvaluatedSalePromotion = {
|
|
|
31
33
|
giftChooseCount: null,
|
|
32
34
|
afterSale: [],
|
|
33
35
|
appliesTo: PromotionAppliesToEnum.SUREKEEP_ONLY,
|
|
36
|
+
stackable: false,
|
|
37
|
+
anchorBound: false,
|
|
34
38
|
};
|
|
35
39
|
|
|
36
40
|
describe('SalePromotionConditions', () => {
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance, type ClassConstructor } from 'class-transformer';
|
|
3
|
+
import { validateSync, type ValidationError } from 'class-validator';
|
|
4
|
+
import {
|
|
5
|
+
CreateSalePromotionRequest,
|
|
6
|
+
HoldPromotionInput,
|
|
7
|
+
HoldSalePromotionRequest,
|
|
8
|
+
LinePromotionAmount,
|
|
9
|
+
RETAIL_PROMOTIONS_ERROR_HTTP_STATUS,
|
|
10
|
+
RetailPromotionsErrorCodeEnum,
|
|
11
|
+
SalePromotionKindEnum,
|
|
12
|
+
SalePromotionRef,
|
|
13
|
+
UpdateSalePromotionRequest,
|
|
14
|
+
type HeldPromotion,
|
|
15
|
+
type HoldSalePromotionResponse,
|
|
16
|
+
type LinePromotionDiscount,
|
|
17
|
+
} from '../../../src/retailPromotions/index';
|
|
18
|
+
import {
|
|
19
|
+
ApplyLinePromotionRequest,
|
|
20
|
+
ApplySalePromotionRequest,
|
|
21
|
+
RetailPromotionInboundMessage,
|
|
22
|
+
RetailPromotionInboundMessageTypeEnum,
|
|
23
|
+
LinePromotionAmount as WizardLinePromotionAmount,
|
|
24
|
+
SalePromotionRef as WizardSalePromotionRef,
|
|
25
|
+
type WizardLinePromotionFields,
|
|
26
|
+
} from '../../../src/retailWizard';
|
|
27
|
+
|
|
28
|
+
function paths(errors: ValidationError[], prefix = ''): string[] {
|
|
29
|
+
return errors.flatMap((e) => {
|
|
30
|
+
const p = prefix ? `${prefix}.${e.property}` : e.property;
|
|
31
|
+
return e.children && e.children.length > 0 ? paths(e.children, p) : [p];
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function errorsOf<T extends object>(cls: ClassConstructor<T>, payload: object): string[] {
|
|
36
|
+
return paths(validateSync(plainToInstance(cls, payload) as object));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const amount = { promotionId: 'P1', promotionVersion: 1, discountCents: 5000 };
|
|
40
|
+
|
|
41
|
+
describe('stackable en el CRUD de promos', () => {
|
|
42
|
+
const create = { name: 'Promo', customerText: 'Texto', levers: {} };
|
|
43
|
+
|
|
44
|
+
it('acepta stackable booleano o ausente', () => {
|
|
45
|
+
expect(errorsOf(CreateSalePromotionRequest, { ...create, stackable: true })).not.toContain('stackable');
|
|
46
|
+
expect(errorsOf(CreateSalePromotionRequest, create)).not.toContain('stackable');
|
|
47
|
+
expect(errorsOf(UpdateSalePromotionRequest, { stackable: false })).toEqual([]);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it('rechaza stackable que no es booleano', () => {
|
|
51
|
+
expect(errorsOf(CreateSalePromotionRequest, { ...create, stackable: 'si' })).toContain('stackable');
|
|
52
|
+
expect(errorsOf(UpdateSalePromotionRequest, { stackable: 1 })).toContain('stackable');
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe('HoldSalePromotionRequest.promotions', () => {
|
|
57
|
+
const promotions = [
|
|
58
|
+
{ promotionId: 'P1', promotionVersion: 2, lineIds: ['L1'], giftSkus: ['SKU-1'] },
|
|
59
|
+
{ promotionId: 'P2', promotionVersion: 1 },
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
it('acepta la lista nueva sola, con o sin código', () => {
|
|
63
|
+
expect(errorsOf(HoldSalePromotionRequest, { promotions })).toEqual([]);
|
|
64
|
+
expect(errorsOf(HoldSalePromotionRequest, { promotions, discountCode: 'BUENFIN' })).toEqual([]);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('sigue aceptando la forma vieja sola', () => {
|
|
68
|
+
expect(
|
|
69
|
+
errorsOf(HoldSalePromotionRequest, {
|
|
70
|
+
gift: { promotionId: 'G1', promotionVersion: 1, skus: ['SKU-1'] },
|
|
71
|
+
promotionId: 'P1',
|
|
72
|
+
promotionVersion: 1,
|
|
73
|
+
saleGiftSkus: ['SKU-2'],
|
|
74
|
+
}),
|
|
75
|
+
).toEqual([]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it.each([
|
|
79
|
+
['gift', { gift: { promotionId: 'G1', promotionVersion: 1, skus: ['SKU-1'] } }],
|
|
80
|
+
['promotionId', { promotionId: 'P1', promotionVersion: 1 }],
|
|
81
|
+
['saleGiftSkus', { saleGiftSkus: ['SKU-2'] }],
|
|
82
|
+
])('rechaza mezclar promotions con %s', (_field, legacy) => {
|
|
83
|
+
expect(errorsOf(HoldSalePromotionRequest, { promotions, ...legacy })).toContain('promotions');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('valida cada elemento anidado', () => {
|
|
87
|
+
const found = errorsOf(HoldSalePromotionRequest, {
|
|
88
|
+
promotions: [{ promotionId: '', promotionVersion: 0, lineIds: [''], giftSkus: 'SKU' }],
|
|
89
|
+
});
|
|
90
|
+
expect(found).toEqual(
|
|
91
|
+
expect.arrayContaining([
|
|
92
|
+
'promotions.0.promotionId',
|
|
93
|
+
'promotions.0.promotionVersion',
|
|
94
|
+
'promotions.0.lineIds',
|
|
95
|
+
'promotions.0.giftSkus',
|
|
96
|
+
]),
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('HoldPromotionInput se valida solo', () => {
|
|
101
|
+
expect(errorsOf(HoldPromotionInput, { promotionId: 'P1', promotionVersion: 1 })).toEqual([]);
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('promotionDiscounts por línea', () => {
|
|
106
|
+
it('ApplyLinePromotionRequest acepta la lista y el descuento del código', () => {
|
|
107
|
+
expect(
|
|
108
|
+
errorsOf(ApplyLinePromotionRequest, {
|
|
109
|
+
promotionId: 'P1',
|
|
110
|
+
promotionVersion: 1,
|
|
111
|
+
discountCents: 7000,
|
|
112
|
+
codeDiscountCents: 2000,
|
|
113
|
+
promotionDiscounts: [amount],
|
|
114
|
+
}),
|
|
115
|
+
).toEqual([]);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('ApplyLinePromotionRequest valida la lista anidada y el código negativo', () => {
|
|
119
|
+
const found = errorsOf(ApplyLinePromotionRequest, {
|
|
120
|
+
codeDiscountCents: -1,
|
|
121
|
+
promotionDiscounts: [{ promotionId: '', promotionVersion: 0, discountCents: -5 }],
|
|
122
|
+
});
|
|
123
|
+
expect(found).toEqual(
|
|
124
|
+
expect.arrayContaining([
|
|
125
|
+
'codeDiscountCents',
|
|
126
|
+
'promotionDiscounts.0.promotionId',
|
|
127
|
+
'promotionDiscounts.0.promotionVersion',
|
|
128
|
+
'promotionDiscounts.0.discountCents',
|
|
129
|
+
]),
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('LinePromotionAmount es la misma clase en ambos módulos', () => {
|
|
134
|
+
expect(WizardLinePromotionAmount).toBe(LinePromotionAmount);
|
|
135
|
+
expect(errorsOf(LinePromotionAmount, amount)).toEqual([]);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('las interfaces aceptan la lista por promo', () => {
|
|
139
|
+
const fields: WizardLinePromotionFields = { promotionDiscounts: [amount], codeDiscountCents: 0 };
|
|
140
|
+
const discount: LinePromotionDiscount = {
|
|
141
|
+
lineId: 'L1',
|
|
142
|
+
promotionId: 'P1',
|
|
143
|
+
promotionVersion: 1,
|
|
144
|
+
discountCode: null,
|
|
145
|
+
originalPriceCents: 10000,
|
|
146
|
+
discountCents: 5000,
|
|
147
|
+
finalPriceCents: 5000,
|
|
148
|
+
promotionDiscounts: [amount],
|
|
149
|
+
codeDiscountCents: 0,
|
|
150
|
+
};
|
|
151
|
+
expect(fields.promotionDiscounts).toEqual(discount.promotionDiscounts);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('salePromotions por venta', () => {
|
|
156
|
+
const ref = { promotionId: 'P1', promotionVersion: 1 };
|
|
157
|
+
|
|
158
|
+
it('ApplySalePromotionRequest acepta la lista y la valida anidada', () => {
|
|
159
|
+
const base = { salePromotionId: null, salePromotionVersion: null };
|
|
160
|
+
expect(errorsOf(ApplySalePromotionRequest, { ...base, salePromotions: [ref] })).toEqual([]);
|
|
161
|
+
expect(errorsOf(ApplySalePromotionRequest, { ...base, salePromotions: null })).toEqual([]);
|
|
162
|
+
expect(
|
|
163
|
+
errorsOf(ApplySalePromotionRequest, { ...base, salePromotions: [{ promotionId: '', promotionVersion: 0 }] }),
|
|
164
|
+
).toEqual(expect.arrayContaining(['salePromotions.0.promotionId', 'salePromotions.0.promotionVersion']));
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('SalePromotionRef es la misma clase en ambos módulos', () => {
|
|
168
|
+
expect(WizardSalePromotionRef).toBe(SalePromotionRef);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('RetailPromotionInboundMessage valida salePromotions y promotionDiscounts de la línea', () => {
|
|
172
|
+
const message = {
|
|
173
|
+
type: RetailPromotionInboundMessageTypeEnum.SALE_CONFIRMED,
|
|
174
|
+
tenantId: 'T',
|
|
175
|
+
retailerId: 'R',
|
|
176
|
+
storeId: 'S',
|
|
177
|
+
saleId: 'V',
|
|
178
|
+
sessionId: 'W',
|
|
179
|
+
customerId: 'C',
|
|
180
|
+
soldAt: '2026-10-06T00:00:00.000Z',
|
|
181
|
+
occurredAt: '2026-10-06T00:00:00.000Z',
|
|
182
|
+
salePromotions: [ref],
|
|
183
|
+
lines: [
|
|
184
|
+
{
|
|
185
|
+
lineId: 'L1',
|
|
186
|
+
sku: 'SKU',
|
|
187
|
+
qty: 1,
|
|
188
|
+
originalPriceCents: 10000,
|
|
189
|
+
identifiers: [],
|
|
190
|
+
promotionDiscounts: [amount],
|
|
191
|
+
codeDiscountCents: 0,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
};
|
|
195
|
+
expect(errorsOf(RetailPromotionInboundMessage, message)).toEqual([]);
|
|
196
|
+
const bad = {
|
|
197
|
+
...message,
|
|
198
|
+
salePromotions: [{ promotionId: 'P1' }],
|
|
199
|
+
lines: [{ ...message.lines[0], promotionDiscounts: [{ ...amount, discountCents: 'x' }], codeDiscountCents: -1 }],
|
|
200
|
+
};
|
|
201
|
+
expect(errorsOf(RetailPromotionInboundMessage, bad)).toEqual(
|
|
202
|
+
expect.arrayContaining([
|
|
203
|
+
'salePromotions.0.promotionVersion',
|
|
204
|
+
'lines.0.promotionDiscounts.0.discountCents',
|
|
205
|
+
'lines.0.codeDiscountCents',
|
|
206
|
+
]),
|
|
207
|
+
);
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe('respuesta del apartado y error nuevo', () => {
|
|
212
|
+
it('HoldSalePromotionResponse trae promotions sin quitar los campos viejos', () => {
|
|
213
|
+
const held: HeldPromotion = {
|
|
214
|
+
promotionId: 'P1',
|
|
215
|
+
promotionVersion: 1,
|
|
216
|
+
kind: SalePromotionKindEnum.SALE,
|
|
217
|
+
stackable: true,
|
|
218
|
+
lineIds: ['L1'],
|
|
219
|
+
giftSkus: [],
|
|
220
|
+
};
|
|
221
|
+
const response: HoldSalePromotionResponse = {
|
|
222
|
+
sessionId: 'W',
|
|
223
|
+
gift: null,
|
|
224
|
+
promotionId: null,
|
|
225
|
+
promotionVersion: null,
|
|
226
|
+
discountCode: null,
|
|
227
|
+
saleGiftSkus: [],
|
|
228
|
+
lines: [],
|
|
229
|
+
totalDiscountCents: 0,
|
|
230
|
+
promotions: [held],
|
|
231
|
+
};
|
|
232
|
+
expect(response.promotions).toHaveLength(1);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('PROMOTION_NOT_STACKABLE responde 422', () => {
|
|
236
|
+
expect(RETAIL_PROMOTIONS_ERROR_HTTP_STATUS[RetailPromotionsErrorCodeEnum.PROMOTION_NOT_STACKABLE]).toBe(422);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
@@ -34,4 +34,5 @@ exports.RETAIL_PROMOTIONS_ERROR_HTTP_STATUS = {
|
|
|
34
34
|
[RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.INVALID_NEXT_TOKEN]: 400,
|
|
35
35
|
[RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.CATALOG_SKU_NOT_FOUND]: 404,
|
|
36
36
|
[RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.SPLIT_FINANCING_DISABLED]: 409,
|
|
37
|
+
[RetailPromotionsErrorCodeEnum_1.RetailPromotionsErrorCodeEnum.PROMOTION_NOT_STACKABLE]: 422,
|
|
37
38
|
};
|
|
@@ -0,0 +1,36 @@
|
|
|
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.LinePromotionAmount = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/** Descuento que una promo le aplica a una línea; la suma de la lista + el código da el total. */
|
|
16
|
+
class LinePromotionAmount {
|
|
17
|
+
}
|
|
18
|
+
exports.LinePromotionAmount = LinePromotionAmount;
|
|
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
|
+
], LinePromotionAmount.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
|
+
], LinePromotionAmount.prototype, "promotionVersion", void 0);
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, class_transformer_1.Expose)(),
|
|
33
|
+
(0, class_validator_1.IsInt)(),
|
|
34
|
+
(0, class_validator_1.Min)(0),
|
|
35
|
+
__metadata("design:type", Number)
|
|
36
|
+
], LinePromotionAmount.prototype, "discountCents", void 0);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { LinePromotionAmount } from './LinePromotionAmount';
|
|
1
2
|
/** Desglose por línea de la sesión: qué promo o código la tocó y cuánto bajó. */
|
|
2
3
|
export interface LinePromotionDiscount {
|
|
3
4
|
lineId: string;
|
|
@@ -7,4 +8,7 @@ export interface LinePromotionDiscount {
|
|
|
7
8
|
originalPriceCents: number;
|
|
8
9
|
discountCents: number;
|
|
9
10
|
finalPriceCents: number;
|
|
11
|
+
/** Descuento de cada promo en la línea; sin el campo, la de `promotionId` lleva todo menos el código. */
|
|
12
|
+
promotionDiscounts?: LinePromotionAmount[];
|
|
13
|
+
codeDiscountCents?: number;
|
|
10
14
|
}
|
|
@@ -21,6 +21,8 @@ export interface SalePromotion {
|
|
|
21
21
|
/** `null` = permanente. */
|
|
22
22
|
validUntil: string | null;
|
|
23
23
|
oncePerCustomer: boolean;
|
|
24
|
+
/** Si se puede sumar con otras promos en la misma línea. */
|
|
25
|
+
stackable: boolean;
|
|
24
26
|
status: SalePromotionStatusEnum;
|
|
25
27
|
/** Derivada; `null` cuando el estado no es `ACTIVE`. */
|
|
26
28
|
phase: SalePromotionPhaseEnum | null;
|
|
@@ -0,0 +1,30 @@
|
|
|
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.SalePromotionRef = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/** Promo de venta fijada en la sesión o en la venta, con su versión. */
|
|
16
|
+
class SalePromotionRef {
|
|
17
|
+
}
|
|
18
|
+
exports.SalePromotionRef = SalePromotionRef;
|
|
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
|
+
], SalePromotionRef.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
|
+
], SalePromotionRef.prototype, "promotionVersion", void 0);
|
|
@@ -81,3 +81,9 @@ __decorate([
|
|
|
81
81
|
(0, class_validator_1.IsBoolean)(),
|
|
82
82
|
__metadata("design:type", Boolean)
|
|
83
83
|
], CreateSalePromotionRequest.prototype, "oncePerCustomer", void 0);
|
|
84
|
+
__decorate([
|
|
85
|
+
(0, class_transformer_1.Expose)(),
|
|
86
|
+
(0, class_validator_1.IsOptional)(),
|
|
87
|
+
(0, class_validator_1.IsBoolean)(),
|
|
88
|
+
__metadata("design:type", Boolean)
|
|
89
|
+
], CreateSalePromotionRequest.prototype, "stackable", void 0);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Promo apartada en la lista nueva: a qué líneas aplica y qué regalos eligió el cliente. */
|
|
2
|
+
export declare class HoldPromotionInput {
|
|
3
|
+
promotionId: string;
|
|
4
|
+
promotionVersion: number;
|
|
5
|
+
/** Líneas que toca la promo; ausente = las que resuelva el lambda. */
|
|
6
|
+
lineIds?: string[];
|
|
7
|
+
giftSkus?: string[];
|
|
8
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
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.HoldPromotionInput = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/** Promo apartada en la lista nueva: a qué líneas aplica y qué regalos eligió el cliente. */
|
|
16
|
+
class HoldPromotionInput {
|
|
17
|
+
}
|
|
18
|
+
exports.HoldPromotionInput = HoldPromotionInput;
|
|
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
|
+
], HoldPromotionInput.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
|
+
], HoldPromotionInput.prototype, "promotionVersion", void 0);
|
|
31
|
+
__decorate([
|
|
32
|
+
(0, class_transformer_1.Expose)(),
|
|
33
|
+
(0, class_validator_1.IsOptional)(),
|
|
34
|
+
(0, class_validator_1.IsArray)(),
|
|
35
|
+
(0, class_validator_1.IsString)({ each: true }),
|
|
36
|
+
(0, class_validator_1.IsNotEmpty)({ each: true }),
|
|
37
|
+
__metadata("design:type", Array)
|
|
38
|
+
], HoldPromotionInput.prototype, "lineIds", void 0);
|
|
39
|
+
__decorate([
|
|
40
|
+
(0, class_transformer_1.Expose)(),
|
|
41
|
+
(0, class_validator_1.IsOptional)(),
|
|
42
|
+
(0, class_validator_1.IsArray)(),
|
|
43
|
+
(0, class_validator_1.IsString)({ each: true }),
|
|
44
|
+
(0, class_validator_1.IsNotEmpty)({ each: true }),
|
|
45
|
+
__metadata("design:type", Array)
|
|
46
|
+
], HoldPromotionInput.prototype, "giftSkus", void 0);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HoldGiftPromotionInput } from './HoldGiftPromotionInput';
|
|
2
|
+
import { HoldPromotionInput } from './HoldPromotionInput';
|
|
2
3
|
/**
|
|
3
4
|
* Body de publicHoldSalePromotion (PUT, `sessionId` en el path): hasta una promo de regalo, una de venta
|
|
4
5
|
* y un código. `null` en cada una = sin ella; un PUT distinto reemplaza el apartado anterior.
|
|
@@ -6,16 +7,21 @@ import { HoldGiftPromotionInput } from './HoldGiftPromotionInput';
|
|
|
6
7
|
export declare class HoldSalePromotionRequest {
|
|
7
8
|
/**
|
|
8
9
|
* Promo de regalo del teléfono (su única palanca es el regalo).
|
|
9
|
-
*
|
|
10
|
+
* @deprecated Usa `promotions`; no se combina con él.
|
|
10
11
|
*/
|
|
11
12
|
gift?: HoldGiftPromotionInput | null;
|
|
12
13
|
/**
|
|
13
14
|
* Promo de venta; `null` = «Ninguna».
|
|
14
|
-
*
|
|
15
|
+
* @deprecated Usa `promotions`; no se combina con él.
|
|
15
16
|
*/
|
|
16
17
|
promotionId?: string | null;
|
|
17
18
|
promotionVersion?: number | null;
|
|
18
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Regalo incluido en la promo de venta, solo si esa promo además trae otras palancas.
|
|
21
|
+
* @deprecated Usa `giftSkus` en `promotions`.
|
|
22
|
+
*/
|
|
19
23
|
saleGiftSkus?: string[] | null;
|
|
20
24
|
discountCode?: string | null;
|
|
25
|
+
/** Promos apartadas, cada una con sus líneas y regalos; excluyente con la forma vieja. */
|
|
26
|
+
promotions?: HoldPromotionInput[] | null;
|
|
21
27
|
}
|
|
@@ -12,7 +12,9 @@ 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 IsHoldModeExclusiveConstraint_1 = require("../../validators/IsHoldModeExclusiveConstraint");
|
|
15
16
|
const HoldGiftPromotionInput_1 = require("./HoldGiftPromotionInput");
|
|
17
|
+
const HoldPromotionInput_1 = require("./HoldPromotionInput");
|
|
16
18
|
/**
|
|
17
19
|
* Body de publicHoldSalePromotion (PUT, `sessionId` en el path): hasta una promo de regalo, una de venta
|
|
18
20
|
* y un código. `null` en cada una = sin ella; un PUT distinto reemplaza el apartado anterior.
|
|
@@ -55,3 +57,12 @@ __decorate([
|
|
|
55
57
|
(0, class_validator_1.IsNotEmpty)(),
|
|
56
58
|
__metadata("design:type", String)
|
|
57
59
|
], HoldSalePromotionRequest.prototype, "discountCode", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
(0, class_transformer_1.Expose)(),
|
|
62
|
+
(0, class_validator_1.IsOptional)(),
|
|
63
|
+
(0, class_validator_1.IsArray)(),
|
|
64
|
+
(0, class_validator_1.ValidateNested)({ each: true }),
|
|
65
|
+
(0, class_transformer_1.Type)(() => HoldPromotionInput_1.HoldPromotionInput),
|
|
66
|
+
(0, class_validator_1.Validate)(IsHoldModeExclusiveConstraint_1.IsHoldModeExclusiveConstraint),
|
|
67
|
+
__metadata("design:type", Array)
|
|
68
|
+
], HoldSalePromotionRequest.prototype, "promotions", void 0);
|
|
@@ -83,3 +83,9 @@ __decorate([
|
|
|
83
83
|
(0, class_validator_1.IsBoolean)(),
|
|
84
84
|
__metadata("design:type", Boolean)
|
|
85
85
|
], UpdateSalePromotionRequest.prototype, "oncePerCustomer", void 0);
|
|
86
|
+
__decorate([
|
|
87
|
+
(0, class_transformer_1.Expose)(),
|
|
88
|
+
(0, class_validator_1.IsOptional)(),
|
|
89
|
+
(0, class_validator_1.IsBoolean)(),
|
|
90
|
+
__metadata("design:type", Boolean)
|
|
91
|
+
], UpdateSalePromotionRequest.prototype, "stackable", void 0);
|
|
@@ -27,6 +27,10 @@ export interface StoreSalePromotionItem {
|
|
|
27
27
|
scope: SalePromotionScope;
|
|
28
28
|
/** SUREKEEP_ONLY = solo con crédito SureKeep; ANY_FINANCIER = también contado o derivada. */
|
|
29
29
|
appliesTo: PromotionAppliesToEnum;
|
|
30
|
+
/** Si se puede sumar con otras promos en la misma línea. */
|
|
31
|
+
stackable: boolean;
|
|
32
|
+
/** Ocupa el lugar de la línea ancla (teléfono o kit), aunque no la toque directo. */
|
|
33
|
+
anchorBound: boolean;
|
|
30
34
|
conditions?: SalePromotionConditions;
|
|
31
35
|
/** Si viene, todavía no se puede decidir para este cliente (ej. CUSTOMER_NOT_IDENTIFIED). */
|
|
32
36
|
blockedBy?: RetailPromotionsErrorCodeEnum | null;
|
|
@@ -63,6 +67,10 @@ export interface EvaluatedSalePromotion {
|
|
|
63
67
|
afterSale: AfterSaleBenefit[];
|
|
64
68
|
/** SUREKEEP_ONLY = solo con crédito SureKeep; ANY_FINANCIER = también contado o derivada. */
|
|
65
69
|
appliesTo: PromotionAppliesToEnum;
|
|
70
|
+
/** Si se puede sumar con otras promos en la misma línea. */
|
|
71
|
+
stackable: boolean;
|
|
72
|
+
/** Ocupa el lugar de la línea ancla (teléfono o kit), aunque no la toque directo. */
|
|
73
|
+
anchorBound: boolean;
|
|
66
74
|
conditions?: SalePromotionConditions;
|
|
67
75
|
/** Si viene, la promo se muestra pero no se puede elegir; dice por qué (ej. CUSTOMER_NOT_IDENTIFIED). */
|
|
68
76
|
blockedBy?: RetailPromotionsErrorCodeEnum | null;
|
|
@@ -85,6 +93,15 @@ export interface HeldGiftPromotion {
|
|
|
85
93
|
promotionVersion: number;
|
|
86
94
|
skus: string[];
|
|
87
95
|
}
|
|
96
|
+
/** Promo apartada en la lista nueva, con las líneas que toca y los regalos elegidos. */
|
|
97
|
+
export interface HeldPromotion {
|
|
98
|
+
promotionId: string;
|
|
99
|
+
promotionVersion: number;
|
|
100
|
+
kind: SalePromotionKindEnum;
|
|
101
|
+
stackable: boolean;
|
|
102
|
+
lineIds: string[];
|
|
103
|
+
giftSkus: string[];
|
|
104
|
+
}
|
|
88
105
|
/** Lo que quedó apartado y escrito en la sesión: la promo de regalo, la de venta y el código. */
|
|
89
106
|
export interface HoldSalePromotionResponse {
|
|
90
107
|
sessionId: string;
|
|
@@ -96,6 +113,8 @@ export interface HoldSalePromotionResponse {
|
|
|
96
113
|
saleGiftSkus: string[];
|
|
97
114
|
lines: LinePromotionDiscount[];
|
|
98
115
|
totalDiscountCents: number;
|
|
116
|
+
/** Todas las promos apartadas; los campos de arriba se conservan por compatibilidad. */
|
|
117
|
+
promotions: HeldPromotion[];
|
|
99
118
|
}
|
|
100
119
|
/** `released: false` = no había apartado; soltar es idempotente. */
|
|
101
120
|
export interface ReleaseSalePromotionResponse {
|
|
@@ -127,6 +146,7 @@ export interface SaleAppliedPromotion {
|
|
|
127
146
|
version: number;
|
|
128
147
|
name: string;
|
|
129
148
|
kind: SalePromotionKindEnum;
|
|
149
|
+
stackable?: boolean;
|
|
130
150
|
}
|
|
131
151
|
/** Cupón y «lo que se lleva» de una venta cerrada (publicGetSaleCoupon). */
|
|
132
152
|
export interface GetSaleCouponResponse {
|
|
@@ -44,5 +44,7 @@ export declare enum RetailPromotionsErrorCodeEnum {
|
|
|
44
44
|
/** El SKU no existe en el catálogo. */
|
|
45
45
|
CATALOG_SKU_NOT_FOUND = "CATALOG_SKU_NOT_FOUND",
|
|
46
46
|
/** Con el reparto apagado no se aplican palancas de precio ni código; los regalos sí. */
|
|
47
|
-
SPLIT_FINANCING_DISABLED = "SPLIT_FINANCING_DISABLED"
|
|
47
|
+
SPLIT_FINANCING_DISABLED = "SPLIT_FINANCING_DISABLED",
|
|
48
|
+
/** La promo no acumulable choca con otra en la misma línea. */
|
|
49
|
+
PROMOTION_NOT_STACKABLE = "PROMOTION_NOT_STACKABLE"
|
|
48
50
|
}
|
|
@@ -49,4 +49,6 @@ var RetailPromotionsErrorCodeEnum;
|
|
|
49
49
|
RetailPromotionsErrorCodeEnum["CATALOG_SKU_NOT_FOUND"] = "CATALOG_SKU_NOT_FOUND";
|
|
50
50
|
/** Con el reparto apagado no se aplican palancas de precio ni código; los regalos sí. */
|
|
51
51
|
RetailPromotionsErrorCodeEnum["SPLIT_FINANCING_DISABLED"] = "SPLIT_FINANCING_DISABLED";
|
|
52
|
+
/** La promo no acumulable choca con otra en la misma línea. */
|
|
53
|
+
RetailPromotionsErrorCodeEnum["PROMOTION_NOT_STACKABLE"] = "PROMOTION_NOT_STACKABLE";
|
|
52
54
|
})(RetailPromotionsErrorCodeEnum || (exports.RetailPromotionsErrorCodeEnum = RetailPromotionsErrorCodeEnum = {}));
|
|
@@ -29,6 +29,9 @@ export * from './dtos/SalePromotion';
|
|
|
29
29
|
export * from './dtos/SalePromotionLogEntry';
|
|
30
30
|
export * from './dtos/DiscountCode';
|
|
31
31
|
export * from './dtos/LinePromotionDiscount';
|
|
32
|
+
export * from './dtos/LinePromotionAmount';
|
|
33
|
+
export * from './dtos/SalePromotionRef';
|
|
34
|
+
export * from './validators/IsHoldModeExclusiveConstraint';
|
|
32
35
|
export * from './dtos/requests/DiscountValueInput';
|
|
33
36
|
export * from './dtos/requests/SalePromotionLeversInput';
|
|
34
37
|
export * from './dtos/requests/SalePromotionScopeInput';
|
|
@@ -43,6 +46,7 @@ export * from './dtos/requests/ChangeDiscountCodeStatusRequest';
|
|
|
43
46
|
export * from './dtos/requests/ListStoreSalePromotionsQuery';
|
|
44
47
|
export * from './dtos/requests/EvaluateSalePromotionsRequest';
|
|
45
48
|
export * from './dtos/requests/HoldGiftPromotionInput';
|
|
49
|
+
export * from './dtos/requests/HoldPromotionInput';
|
|
46
50
|
export * from './dtos/requests/HoldSalePromotionRequest';
|
|
47
51
|
export * from './dtos/requests/GetSaleCouponQuery';
|
|
48
52
|
export * from './dtos/requests/SkuSalePromotionsQuery';
|