@fiado/type-kit 3.500.0 → 3.502.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 (64) hide show
  1. package/_test_/unit/loanCredit/inStorePaymentDtos.test.ts +19 -0
  2. package/_test_/unit/retailPromotions/constants.test.ts +1 -1
  3. package/_test_/unit/retailPromotions/evaluatedSalePromotion.test.ts +2 -0
  4. package/_test_/unit/retailPromotions/resolveSalePromotionKind.test.ts +2 -0
  5. package/_test_/unit/retailPromotions/salePromotionConditions.test.ts +4 -0
  6. package/_test_/unit/retailPromotions/stackablePromotions.test.ts +238 -0
  7. package/bin/loanCredit/dtos/responses/LoanPaymentListItem.d.ts +2 -0
  8. package/bin/retailPromotions/constants/retailPromotionsErrorHttpStatus.js +1 -0
  9. package/bin/retailPromotions/dtos/LinePromotionAmount.d.ts +6 -0
  10. package/bin/retailPromotions/dtos/LinePromotionAmount.js +36 -0
  11. package/bin/retailPromotions/dtos/LinePromotionDiscount.d.ts +4 -0
  12. package/bin/retailPromotions/dtos/SalePromotion.d.ts +2 -0
  13. package/bin/retailPromotions/dtos/SalePromotionRef.d.ts +5 -0
  14. package/bin/retailPromotions/dtos/SalePromotionRef.js +30 -0
  15. package/bin/retailPromotions/dtos/requests/CreateSalePromotionRequest.d.ts +2 -0
  16. package/bin/retailPromotions/dtos/requests/CreateSalePromotionRequest.js +6 -0
  17. package/bin/retailPromotions/dtos/requests/HoldPromotionInput.d.ts +8 -0
  18. package/bin/retailPromotions/dtos/requests/HoldPromotionInput.js +46 -0
  19. package/bin/retailPromotions/dtos/requests/HoldSalePromotionRequest.d.ts +9 -3
  20. package/bin/retailPromotions/dtos/requests/HoldSalePromotionRequest.js +11 -0
  21. package/bin/retailPromotions/dtos/requests/UpdateSalePromotionRequest.d.ts +2 -0
  22. package/bin/retailPromotions/dtos/requests/UpdateSalePromotionRequest.js +6 -0
  23. package/bin/retailPromotions/dtos/responses/WizardSalePromotionResponses.d.ts +20 -0
  24. package/bin/retailPromotions/enums/RetailPromotionsErrorCodeEnum.d.ts +3 -1
  25. package/bin/retailPromotions/enums/RetailPromotionsErrorCodeEnum.js +2 -0
  26. package/bin/retailPromotions/index.d.ts +4 -0
  27. package/bin/retailPromotions/index.js +5 -0
  28. package/bin/retailPromotions/validators/IsHoldModeExclusiveConstraint.d.ts +6 -0
  29. package/bin/retailPromotions/validators/IsHoldModeExclusiveConstraint.js +24 -0
  30. package/bin/retailWizard/dtos/Sale.d.ts +3 -0
  31. package/bin/retailWizard/dtos/WizardLinePromotionFields.d.ts +4 -0
  32. package/bin/retailWizard/dtos/WizardSession.d.ts +3 -0
  33. package/bin/retailWizard/dtos/requests/ApplyLinePromotionRequest.d.ts +5 -0
  34. package/bin/retailWizard/dtos/requests/ApplyLinePromotionRequest.js +16 -0
  35. package/bin/retailWizard/dtos/requests/ApplySalePromotionRequest.d.ts +3 -0
  36. package/bin/retailWizard/dtos/requests/ApplySalePromotionRequest.js +9 -0
  37. package/bin/retailWizard/dtos/responses/PrivateWizardSessionResponse.d.ts +3 -0
  38. package/bin/retailWizard/events/RetailPromotionInboundMessage.d.ts +8 -0
  39. package/bin/retailWizard/events/RetailPromotionInboundMessage.js +22 -0
  40. package/bin/retailWizard/index.d.ts +2 -0
  41. package/bin/retailWizard/index.js +5 -0
  42. package/package.json +1 -1
  43. package/src/loanCredit/dtos/responses/LoanPaymentListItem.ts +2 -0
  44. package/src/retailPromotions/constants/retailPromotionsErrorHttpStatus.ts +1 -0
  45. package/src/retailPromotions/dtos/LinePromotionAmount.ts +20 -0
  46. package/src/retailPromotions/dtos/LinePromotionDiscount.ts +5 -0
  47. package/src/retailPromotions/dtos/SalePromotion.ts +2 -0
  48. package/src/retailPromotions/dtos/SalePromotionRef.ts +15 -0
  49. package/src/retailPromotions/dtos/requests/CreateSalePromotionRequest.ts +6 -0
  50. package/src/retailPromotions/dtos/requests/HoldPromotionInput.ts +30 -0
  51. package/src/retailPromotions/dtos/requests/HoldSalePromotionRequest.ts +28 -4
  52. package/src/retailPromotions/dtos/requests/UpdateSalePromotionRequest.ts +6 -0
  53. package/src/retailPromotions/dtos/responses/WizardSalePromotionResponses.ts +21 -0
  54. package/src/retailPromotions/enums/RetailPromotionsErrorCodeEnum.ts +2 -0
  55. package/src/retailPromotions/index.ts +6 -0
  56. package/src/retailPromotions/validators/IsHoldModeExclusiveConstraint.ts +18 -0
  57. package/src/retailWizard/dtos/Sale.ts +3 -0
  58. package/src/retailWizard/dtos/WizardLinePromotionFields.ts +4 -0
  59. package/src/retailWizard/dtos/WizardSession.ts +3 -0
  60. package/src/retailWizard/dtos/requests/ApplyLinePromotionRequest.ts +18 -2
  61. package/src/retailWizard/dtos/requests/ApplySalePromotionRequest.ts +11 -2
  62. package/src/retailWizard/dtos/responses/PrivateWizardSessionResponse.ts +3 -0
  63. package/src/retailWizard/events/RetailPromotionInboundMessage.ts +22 -0
  64. package/src/retailWizard/index.ts +2 -0
@@ -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';
@@ -48,6 +48,10 @@ __exportStar(require("./dtos/SalePromotion"), exports);
48
48
  __exportStar(require("./dtos/SalePromotionLogEntry"), exports);
49
49
  __exportStar(require("./dtos/DiscountCode"), exports);
50
50
  __exportStar(require("./dtos/LinePromotionDiscount"), exports);
51
+ __exportStar(require("./dtos/LinePromotionAmount"), exports);
52
+ __exportStar(require("./dtos/SalePromotionRef"), exports);
53
+ // Validadores
54
+ __exportStar(require("./validators/IsHoldModeExclusiveConstraint"), exports);
51
55
  // Request DTOs
52
56
  __exportStar(require("./dtos/requests/DiscountValueInput"), exports);
53
57
  __exportStar(require("./dtos/requests/SalePromotionLeversInput"), exports);
@@ -63,6 +67,7 @@ __exportStar(require("./dtos/requests/ChangeDiscountCodeStatusRequest"), exports
63
67
  __exportStar(require("./dtos/requests/ListStoreSalePromotionsQuery"), exports);
64
68
  __exportStar(require("./dtos/requests/EvaluateSalePromotionsRequest"), exports);
65
69
  __exportStar(require("./dtos/requests/HoldGiftPromotionInput"), exports);
70
+ __exportStar(require("./dtos/requests/HoldPromotionInput"), exports);
66
71
  __exportStar(require("./dtos/requests/HoldSalePromotionRequest"), exports);
67
72
  __exportStar(require("./dtos/requests/GetSaleCouponQuery"), exports);
68
73
  __exportStar(require("./dtos/requests/SkuSalePromotionsQuery"), exports);
@@ -0,0 +1,6 @@
1
+ import { type ValidationArguments, type ValidatorConstraintInterface } from 'class-validator';
2
+ /** Rechaza mandar `promotions` junto con `gift`, `promotionId` o `saleGiftSkus` (forma vieja). */
3
+ export declare class IsHoldModeExclusiveConstraint implements ValidatorConstraintInterface {
4
+ validate(_value: unknown, args: ValidationArguments): boolean;
5
+ defaultMessage(): string;
6
+ }
@@ -0,0 +1,24 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.IsHoldModeExclusiveConstraint = void 0;
10
+ const class_validator_1 = require("class-validator");
11
+ /** Rechaza mandar `promotions` junto con `gift`, `promotionId` o `saleGiftSkus` (forma vieja). */
12
+ let IsHoldModeExclusiveConstraint = class IsHoldModeExclusiveConstraint {
13
+ validate(_value, args) {
14
+ const o = args.object;
15
+ return o.gift == null && o.promotionId == null && o.saleGiftSkus == null;
16
+ }
17
+ defaultMessage() {
18
+ return 'promotions no se combina con gift, promotionId ni saleGiftSkus';
19
+ }
20
+ };
21
+ exports.IsHoldModeExclusiveConstraint = IsHoldModeExclusiveConstraint;
22
+ exports.IsHoldModeExclusiveConstraint = IsHoldModeExclusiveConstraint = __decorate([
23
+ (0, class_validator_1.ValidatorConstraint)({ name: 'isHoldModeExclusive', async: false })
24
+ ], IsHoldModeExclusiveConstraint);
@@ -5,6 +5,7 @@ import type { ExternalProviderEnum } from '../enums/ExternalProviderEnum';
5
5
  import type { CentralSyncStatusEnum } from '../enums/CentralSyncStatusEnum';
6
6
  import type { SalePaymentDetail } from './SalePaymentDetail';
7
7
  import type { SaleLine } from './SaleLine';
8
+ import type { SalePromotionRef } from '../../retailPromotions/dtos/SalePromotionRef';
8
9
  /**
9
10
  * Venta (modelo-datos §3). pk `SALE#<saleId>` · sk `META` · 4 GSIs (`retailerId-soldAt-index`,
10
11
  * `storeId-soldAt-index`, `seller-soldAt-index`, `customerId-soldAt-index`). Unicidad de folio vía
@@ -31,6 +32,8 @@ export interface Sale {
31
32
  /** Promo de venta congelada al cerrar; `null` = ninguna. */
32
33
  salePromotionId?: string | null;
33
34
  salePromotionVersion?: number | null;
35
+ /** Todas las promos de venta congeladas al cerrar. */
36
+ salePromotions?: SalePromotionRef[] | null;
34
37
  /** IMEI consumido del silo también en contado (local-first); null en EXTERNAL_REFERRAL (D15). */
35
38
  imei: string | null;
36
39
  /** Lo cobrado en caja al cerrar: enganche + lo no financiado; 0 en EXTERNAL_REFERRAL. Contrato de `SaleCompletedV1`. */
@@ -1,3 +1,4 @@
1
+ import type { LinePromotionAmount } from '../../retailPromotions/dtos/LinePromotionAmount';
1
2
  import type { WizardLineRoleEnum } from '../enums/WizardLineRoleEnum';
2
3
  /** Campos de Promociones en la línea de sesión y de venta; solo los escribe su endpoint M2M. */
3
4
  export interface WizardLinePromotionFields {
@@ -12,4 +13,7 @@ export interface WizardLinePromotionFields {
12
13
  discountCents?: number;
13
14
  /** Precio antes del descuento; en un regalo, el valor de lista con la línea a $0. */
14
15
  originalPriceCents?: number;
16
+ /** Descuento de cada promo en la línea; sin el campo, la de `promotionId` lleva todo menos el código. */
17
+ promotionDiscounts?: LinePromotionAmount[];
18
+ codeDiscountCents?: number;
15
19
  }
@@ -1,3 +1,4 @@
1
+ import type { SalePromotionRef } from '../../retailPromotions/dtos/SalePromotionRef';
1
2
  import type { WizardStateEnum } from '../enums/WizardStateEnum';
2
3
  import type { WizardStepEnum } from '../enums/WizardStepEnum';
3
4
  import type { FiadoPhoneStatusEnum } from '../enums/FiadoPhoneStatusEnum';
@@ -122,6 +123,8 @@ export interface WizardSession {
122
123
  /** Promo de venta que fijó Promociones; `null` = ninguna. */
123
124
  salePromotionId?: string | null;
124
125
  salePromotionVersion?: number | null;
126
+ /** Todas las promos de venta fijadas; `salePromotionId` queda como la principal. */
127
+ salePromotions?: SalePromotionRef[] | null;
125
128
  /** Enganche cobrado que queda por reembolsar tras cancelar. */
126
129
  refundPendingCents?: number;
127
130
  paymentMethod: PaymentMethodEnum | null;
@@ -1,3 +1,4 @@
1
+ import { LinePromotionAmount } from '../../../retailPromotions/dtos/LinePromotionAmount';
1
2
  /**
2
3
  * PUT …/lines/{lineId}/promotion (privateApplyLinePromotion): reemplaza la promo de la línea por valor.
3
4
  * Un campo ausente queda borrado; no toca role ni linkedLineId. `tenantId` va en el query.
@@ -11,4 +12,8 @@ export declare class ApplyLinePromotionRequest {
11
12
  /** Descuento total de la línea; 0 mientras el código espera revalidarse. */
12
13
  discountCents?: number;
13
14
  originalPriceCents?: number;
15
+ /** Descuento de cada promo en la línea; `promotionId` queda como la principal. */
16
+ promotionDiscounts?: LinePromotionAmount[];
17
+ /** Parte de `discountCents` que viene del código. */
18
+ codeDiscountCents?: number;
14
19
  }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.ApplyLinePromotionRequest = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
+ const LinePromotionAmount_1 = require("../../../retailPromotions/dtos/LinePromotionAmount");
15
16
  const hasPromotion = (o) => o.promotionId !== undefined || o.promotionVersion !== undefined;
16
17
  /**
17
18
  * PUT …/lines/{lineId}/promotion (privateApplyLinePromotion): reemplaza la promo de la línea por valor.
@@ -55,3 +56,18 @@ __decorate([
55
56
  (0, class_validator_1.Min)(0),
56
57
  __metadata("design:type", Number)
57
58
  ], ApplyLinePromotionRequest.prototype, "originalPriceCents", void 0);
59
+ __decorate([
60
+ (0, class_transformer_1.Expose)(),
61
+ (0, class_validator_1.IsOptional)(),
62
+ (0, class_validator_1.IsArray)(),
63
+ (0, class_validator_1.ValidateNested)({ each: true }),
64
+ (0, class_transformer_1.Type)(() => LinePromotionAmount_1.LinePromotionAmount),
65
+ __metadata("design:type", Array)
66
+ ], ApplyLinePromotionRequest.prototype, "promotionDiscounts", void 0);
67
+ __decorate([
68
+ (0, class_transformer_1.Expose)(),
69
+ (0, class_validator_1.IsOptional)(),
70
+ (0, class_validator_1.IsInt)(),
71
+ (0, class_validator_1.Min)(0),
72
+ __metadata("design:type", Number)
73
+ ], ApplyLinePromotionRequest.prototype, "codeDiscountCents", void 0);
@@ -1,3 +1,4 @@
1
+ import { SalePromotionRef } from '../../../retailPromotions/dtos/SalePromotionRef';
1
2
  /**
2
3
  * PUT /private/wizard/sessions/{id}/sale-promotion (privateApplySalePromotion, M2M de Promociones).
3
4
  * Ambos en `null` = «Ninguna»; la versión va solo con la promo. `tenantId` va en el query.
@@ -6,4 +7,6 @@
6
7
  export declare class ApplySalePromotionRequest {
7
8
  salePromotionId: string | null;
8
9
  salePromotionVersion: number | null;
10
+ /** Todas las promos de venta fijadas; `salePromotionId` queda como la principal. */
11
+ salePromotions?: SalePromotionRef[] | null;
9
12
  }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.ApplySalePromotionRequest = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
+ const SalePromotionRef_1 = require("../../../retailPromotions/dtos/SalePromotionRef");
15
16
  /**
16
17
  * PUT /private/wizard/sessions/{id}/sale-promotion (privateApplySalePromotion, M2M de Promociones).
17
18
  * Ambos en `null` = «Ninguna»; la versión va solo con la promo. `tenantId` va en el query.
@@ -34,3 +35,11 @@ __decorate([
34
35
  (0, class_validator_1.Min)(1),
35
36
  __metadata("design:type", Number)
36
37
  ], ApplySalePromotionRequest.prototype, "salePromotionVersion", void 0);
38
+ __decorate([
39
+ (0, class_transformer_1.Expose)(),
40
+ (0, class_validator_1.IsOptional)(),
41
+ (0, class_validator_1.IsArray)(),
42
+ (0, class_validator_1.ValidateNested)({ each: true }),
43
+ (0, class_transformer_1.Type)(() => SalePromotionRef_1.SalePromotionRef),
44
+ __metadata("design:type", Array)
45
+ ], ApplySalePromotionRequest.prototype, "salePromotions", void 0);
@@ -3,6 +3,7 @@ import type { WizardStateEnum } from '../../enums/WizardStateEnum';
3
3
  import type { WizardStepEnum } from '../../enums/WizardStepEnum';
4
4
  import type { WizardPayment } from '../WizardPayment';
5
5
  import type { WizardReservedLine } from '../WizardReservedLine';
6
+ import type { SalePromotionRef } from '../../../retailPromotions/dtos/SalePromotionRef';
6
7
  /** GET /private/wizard/sessions/{id} (privateGetWizardSession): lo que Promociones lee de la sesión. */
7
8
  export interface PrivateWizardSessionResponse {
8
9
  sessionId: string;
@@ -18,6 +19,8 @@ export interface PrivateWizardSessionResponse {
18
19
  anchorLineId: string | null;
19
20
  salePromotionId: string | null;
20
21
  salePromotionVersion: number | null;
22
+ /** Todas las promos de venta fijadas; `salePromotionId` queda como la principal. */
23
+ salePromotions?: SalePromotionRef[] | null;
21
24
  /** Líneas vivas con los campos de Promociones y financedCents. */
22
25
  lines: WizardReservedLine[];
23
26
  fiadoDirectoryId?: string | null;
@@ -1,3 +1,5 @@
1
+ import { LinePromotionAmount } from '../../retailPromotions/dtos/LinePromotionAmount';
2
+ import { SalePromotionRef } from '../../retailPromotions/dtos/SalePromotionRef';
1
3
  import { RetailPromotionInboundMessageTypeEnum } from '../enums/RetailPromotionInboundMessageTypeEnum';
2
4
  import { WizardLineRoleEnum } from '../enums/WizardLineRoleEnum';
3
5
  /** Línea de la venta en el mensaje de Promociones. */
@@ -12,6 +14,10 @@ export declare class RetailPromotionInboundLine {
12
14
  /** Solo en la línea ancla. */
13
15
  discountCode?: string;
14
16
  discountCents?: number;
17
+ /** Descuento de cada promo en la línea; `promotionId` queda como la principal. */
18
+ promotionDiscounts?: LinePromotionAmount[];
19
+ /** Parte de `discountCents` que viene del código. */
20
+ codeDiscountCents?: number;
15
21
  /** Si la línea no lo trae, basePriceCents × qty. */
16
22
  originalPriceCents: number;
17
23
  /** Identificadores de todos los componentes de la línea, aplanados. */
@@ -36,5 +42,7 @@ export declare class RetailPromotionInboundMessage {
36
42
  fiadoDirectoryId?: string;
37
43
  salePromotionId?: string | null;
38
44
  salePromotionVersion?: number | null;
45
+ /** Todas las promos de venta de la venta; `salePromotionId` queda como la principal. */
46
+ salePromotions?: SalePromotionRef[] | null;
39
47
  lines: RetailPromotionInboundLine[];
40
48
  }
@@ -12,6 +12,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.RetailPromotionInboundMessage = exports.RetailPromotionInboundLine = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
+ const LinePromotionAmount_1 = require("../../retailPromotions/dtos/LinePromotionAmount");
16
+ const SalePromotionRef_1 = require("../../retailPromotions/dtos/SalePromotionRef");
15
17
  const RetailPromotionInboundMessageTypeEnum_1 = require("../enums/RetailPromotionInboundMessageTypeEnum");
16
18
  const WizardLineRoleEnum_1 = require("../enums/WizardLineRoleEnum");
17
19
  /** Línea de la venta en el mensaje de Promociones. */
@@ -68,6 +70,19 @@ __decorate([
68
70
  (0, class_validator_1.Min)(0),
69
71
  __metadata("design:type", Number)
70
72
  ], RetailPromotionInboundLine.prototype, "discountCents", void 0);
73
+ __decorate([
74
+ (0, class_validator_1.IsOptional)(),
75
+ (0, class_validator_1.IsArray)(),
76
+ (0, class_validator_1.ValidateNested)({ each: true }),
77
+ (0, class_transformer_1.Type)(() => LinePromotionAmount_1.LinePromotionAmount),
78
+ __metadata("design:type", Array)
79
+ ], RetailPromotionInboundLine.prototype, "promotionDiscounts", void 0);
80
+ __decorate([
81
+ (0, class_validator_1.IsOptional)(),
82
+ (0, class_validator_1.IsInt)(),
83
+ (0, class_validator_1.Min)(0),
84
+ __metadata("design:type", Number)
85
+ ], RetailPromotionInboundLine.prototype, "codeDiscountCents", void 0);
71
86
  __decorate([
72
87
  (0, class_validator_1.IsInt)(),
73
88
  (0, class_validator_1.Min)(0),
@@ -153,6 +168,13 @@ __decorate([
153
168
  (0, class_validator_1.Min)(1),
154
169
  __metadata("design:type", Number)
155
170
  ], RetailPromotionInboundMessage.prototype, "salePromotionVersion", void 0);
171
+ __decorate([
172
+ (0, class_validator_1.IsOptional)(),
173
+ (0, class_validator_1.IsArray)(),
174
+ (0, class_validator_1.ValidateNested)({ each: true }),
175
+ (0, class_transformer_1.Type)(() => SalePromotionRef_1.SalePromotionRef),
176
+ __metadata("design:type", Array)
177
+ ], RetailPromotionInboundMessage.prototype, "salePromotions", void 0);
156
178
  __decorate([
157
179
  (0, class_validator_1.IsArray)(),
158
180
  (0, class_validator_1.ArrayMinSize)(1),
@@ -41,6 +41,8 @@ export * from './dtos/WizardBlocked';
41
41
  export * from './dtos/WizardLineProduct';
42
42
  export * from './dtos/WizardLineIdentifiers';
43
43
  export * from './dtos/WizardLinePromotionFields';
44
+ export { LinePromotionAmount } from '../retailPromotions/dtos/LinePromotionAmount';
45
+ export { SalePromotionRef } from '../retailPromotions/dtos/SalePromotionRef';
44
46
  export * from './dtos/WizardFinancingPreview';
45
47
  export * from './dtos/WizardReservedLine';
46
48
  export * from './dtos/WizardGiftLine';
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.SalePromotionRef = exports.LinePromotionAmount = void 0;
17
18
  // Catálogos de valores compartidos entre endpoints
18
19
  __exportStar(require("./catalog/monthlyIncome"), exports);
19
20
  // Enums
@@ -60,6 +61,10 @@ __exportStar(require("./dtos/WizardBlocked"), exports);
60
61
  __exportStar(require("./dtos/WizardLineProduct"), exports);
61
62
  __exportStar(require("./dtos/WizardLineIdentifiers"), exports);
62
63
  __exportStar(require("./dtos/WizardLinePromotionFields"), exports);
64
+ var LinePromotionAmount_1 = require("../retailPromotions/dtos/LinePromotionAmount");
65
+ Object.defineProperty(exports, "LinePromotionAmount", { enumerable: true, get: function () { return LinePromotionAmount_1.LinePromotionAmount; } });
66
+ var SalePromotionRef_1 = require("../retailPromotions/dtos/SalePromotionRef");
67
+ Object.defineProperty(exports, "SalePromotionRef", { enumerable: true, get: function () { return SalePromotionRef_1.SalePromotionRef; } });
63
68
  __exportStar(require("./dtos/WizardFinancingPreview"), exports);
64
69
  __exportStar(require("./dtos/WizardReservedLine"), exports);
65
70
  __exportStar(require("./dtos/WizardGiftLine"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.500.0",
3
+ "version": "3.502.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -12,6 +12,8 @@ export interface LoanPaymentListItem {
12
12
  /** Folio del pago — la referencia de conciliación. */
13
13
  receipt: string;
14
14
  installmentNumber: number;
15
+ /** Todas las cuotas que cubrió el pago, ascendente; ausente en abono, liquidación y filas viejas (usar `installmentNumber`). */
16
+ installmentNumbers?: number[];
15
17
  attemptId: string;
16
18
  /** Ausente en los pagos en tienda: ahí no hubo motor. */
17
19
  mechanism?: MechanismType;
@@ -32,4 +32,5 @@ export const RETAIL_PROMOTIONS_ERROR_HTTP_STATUS: Readonly<Record<C, 400 | 403 |
32
32
  [C.INVALID_NEXT_TOKEN]: 400,
33
33
  [C.CATALOG_SKU_NOT_FOUND]: 404,
34
34
  [C.SPLIT_FINANCING_DISABLED]: 409,
35
+ [C.PROMOTION_NOT_STACKABLE]: 422,
35
36
  };
@@ -0,0 +1,20 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsInt, IsNotEmpty, IsString, Min } from 'class-validator';
3
+
4
+ /** Descuento que una promo le aplica a una línea; la suma de la lista + el código da el total. */
5
+ export class LinePromotionAmount {
6
+ @Expose()
7
+ @IsString()
8
+ @IsNotEmpty()
9
+ promotionId!: string;
10
+
11
+ @Expose()
12
+ @IsInt()
13
+ @Min(1)
14
+ promotionVersion!: number;
15
+
16
+ @Expose()
17
+ @IsInt()
18
+ @Min(0)
19
+ discountCents!: number;
20
+ }
@@ -1,3 +1,5 @@
1
+ import type { LinePromotionAmount } from './LinePromotionAmount';
2
+
1
3
  /** Desglose por línea de la sesión: qué promo o código la tocó y cuánto bajó. */
2
4
  export interface LinePromotionDiscount {
3
5
  lineId: string;
@@ -7,4 +9,7 @@ export interface LinePromotionDiscount {
7
9
  originalPriceCents: number;
8
10
  discountCents: number;
9
11
  finalPriceCents: number;
12
+ /** Descuento de cada promo en la línea; sin el campo, la de `promotionId` lleva todo menos el código. */
13
+ promotionDiscounts?: LinePromotionAmount[];
14
+ codeDiscountCents?: number;
10
15
  }
@@ -22,6 +22,8 @@ export interface SalePromotion {
22
22
  /** `null` = permanente. */
23
23
  validUntil: string | null;
24
24
  oncePerCustomer: boolean;
25
+ /** Si se puede sumar con otras promos en la misma línea. */
26
+ stackable: boolean;
25
27
  status: SalePromotionStatusEnum;
26
28
  /** Derivada; `null` cuando el estado no es `ACTIVE`. */
27
29
  phase: SalePromotionPhaseEnum | null;
@@ -0,0 +1,15 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsInt, IsNotEmpty, IsString, Min } from 'class-validator';
3
+
4
+ /** Promo de venta fijada en la sesión o en la venta, con su versión. */
5
+ export class SalePromotionRef {
6
+ @Expose()
7
+ @IsString()
8
+ @IsNotEmpty()
9
+ promotionId!: string;
10
+
11
+ @Expose()
12
+ @IsInt()
13
+ @Min(1)
14
+ promotionVersion!: number;
15
+ }
@@ -70,4 +70,10 @@ export class CreateSalePromotionRequest {
70
70
  @IsOptional()
71
71
  @IsBoolean()
72
72
  oncePerCustomer?: boolean;
73
+
74
+ /** Si se puede sumar con otras promos en la misma línea. */
75
+ @Expose()
76
+ @IsOptional()
77
+ @IsBoolean()
78
+ stackable?: boolean;
73
79
  }
@@ -0,0 +1,30 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsArray, IsInt, IsNotEmpty, IsOptional, IsString, Min } from 'class-validator';
3
+
4
+ /** Promo apartada en la lista nueva: a qué líneas aplica y qué regalos eligió el cliente. */
5
+ export class HoldPromotionInput {
6
+ @Expose()
7
+ @IsString()
8
+ @IsNotEmpty()
9
+ promotionId!: string;
10
+
11
+ @Expose()
12
+ @IsInt()
13
+ @Min(1)
14
+ promotionVersion!: number;
15
+
16
+ /** Líneas que toca la promo; ausente = las que resuelva el lambda. */
17
+ @Expose()
18
+ @IsOptional()
19
+ @IsArray()
20
+ @IsString({ each: true })
21
+ @IsNotEmpty({ each: true })
22
+ lineIds?: string[];
23
+
24
+ @Expose()
25
+ @IsOptional()
26
+ @IsArray()
27
+ @IsString({ each: true })
28
+ @IsNotEmpty({ each: true })
29
+ giftSkus?: string[];
30
+ }
@@ -1,6 +1,18 @@
1
1
  import { Expose, Type } from 'class-transformer';
2
- import { IsArray, IsInt, IsNotEmpty, IsObject, IsOptional, IsString, ValidateIf, ValidateNested } from 'class-validator';
2
+ import {
3
+ IsArray,
4
+ IsInt,
5
+ IsNotEmpty,
6
+ IsObject,
7
+ IsOptional,
8
+ IsString,
9
+ Validate,
10
+ ValidateIf,
11
+ ValidateNested,
12
+ } from 'class-validator';
13
+ import { IsHoldModeExclusiveConstraint } from '../../validators/IsHoldModeExclusiveConstraint';
3
14
  import { HoldGiftPromotionInput } from './HoldGiftPromotionInput';
15
+ import { HoldPromotionInput } from './HoldPromotionInput';
4
16
 
5
17
  /**
6
18
  * Body de publicHoldSalePromotion (PUT, `sessionId` en el path): hasta una promo de regalo, una de venta
@@ -9,7 +21,7 @@ import { HoldGiftPromotionInput } from './HoldGiftPromotionInput';
9
21
  export class HoldSalePromotionRequest {
10
22
  /**
11
23
  * 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í.
24
+ * @deprecated Usa `promotions`; no se combina con él.
13
25
  */
14
26
  @Expose()
15
27
  @IsOptional()
@@ -20,7 +32,7 @@ export class HoldSalePromotionRequest {
20
32
 
21
33
  /**
22
34
  * Promo de venta; `null` = «Ninguna».
23
- * El lambda rechaza con PROMOTION_KIND_MISMATCH una promo de solo regalo mandada aquí.
35
+ * @deprecated Usa `promotions`; no se combina con él.
24
36
  */
25
37
  @Expose()
26
38
  @IsOptional()
@@ -33,7 +45,10 @@ export class HoldSalePromotionRequest {
33
45
  @IsInt()
34
46
  promotionVersion?: number | null;
35
47
 
36
- /** Regalo incluido en la promo de venta, solo si esa promo además trae otras palancas. */
48
+ /**
49
+ * Regalo incluido en la promo de venta, solo si esa promo además trae otras palancas.
50
+ * @deprecated Usa `giftSkus` en `promotions`.
51
+ */
37
52
  @Expose()
38
53
  @IsOptional()
39
54
  @IsArray()
@@ -45,4 +60,13 @@ export class HoldSalePromotionRequest {
45
60
  @IsString()
46
61
  @IsNotEmpty()
47
62
  discountCode?: string | null;
63
+
64
+ /** Promos apartadas, cada una con sus líneas y regalos; excluyente con la forma vieja. */
65
+ @Expose()
66
+ @IsOptional()
67
+ @IsArray()
68
+ @ValidateNested({ each: true })
69
+ @Type(() => HoldPromotionInput)
70
+ @Validate(IsHoldModeExclusiveConstraint)
71
+ promotions?: HoldPromotionInput[] | null;
48
72
  }
@@ -71,4 +71,10 @@ export class UpdateSalePromotionRequest {
71
71
  @IsOptional()
72
72
  @IsBoolean()
73
73
  oncePerCustomer?: boolean;
74
+
75
+ /** Si se puede sumar con otras promos en la misma línea. */
76
+ @Expose()
77
+ @IsOptional()
78
+ @IsBoolean()
79
+ stackable?: boolean;
74
80
  }
@@ -29,6 +29,10 @@ export interface StoreSalePromotionItem {
29
29
  scope: SalePromotionScope;
30
30
  /** SUREKEEP_ONLY = solo con crédito SureKeep; ANY_FINANCIER = también contado o derivada. */
31
31
  appliesTo: PromotionAppliesToEnum;
32
+ /** Si se puede sumar con otras promos en la misma línea. */
33
+ stackable: boolean;
34
+ /** Ocupa el lugar de la línea ancla (teléfono o kit), aunque no la toque directo. */
35
+ anchorBound: boolean;
32
36
  conditions?: SalePromotionConditions;
33
37
  /** Si viene, todavía no se puede decidir para este cliente (ej. CUSTOMER_NOT_IDENTIFIED). */
34
38
  blockedBy?: RetailPromotionsErrorCodeEnum | null;
@@ -69,6 +73,10 @@ export interface EvaluatedSalePromotion {
69
73
  afterSale: AfterSaleBenefit[];
70
74
  /** SUREKEEP_ONLY = solo con crédito SureKeep; ANY_FINANCIER = también contado o derivada. */
71
75
  appliesTo: PromotionAppliesToEnum;
76
+ /** Si se puede sumar con otras promos en la misma línea. */
77
+ stackable: boolean;
78
+ /** Ocupa el lugar de la línea ancla (teléfono o kit), aunque no la toque directo. */
79
+ anchorBound: boolean;
72
80
  conditions?: SalePromotionConditions;
73
81
  /** Si viene, la promo se muestra pero no se puede elegir; dice por qué (ej. CUSTOMER_NOT_IDENTIFIED). */
74
82
  blockedBy?: RetailPromotionsErrorCodeEnum | null;
@@ -95,6 +103,16 @@ export interface HeldGiftPromotion {
95
103
  skus: string[];
96
104
  }
97
105
 
106
+ /** Promo apartada en la lista nueva, con las líneas que toca y los regalos elegidos. */
107
+ export interface HeldPromotion {
108
+ promotionId: string;
109
+ promotionVersion: number;
110
+ kind: SalePromotionKindEnum;
111
+ stackable: boolean;
112
+ lineIds: string[];
113
+ giftSkus: string[];
114
+ }
115
+
98
116
  /** Lo que quedó apartado y escrito en la sesión: la promo de regalo, la de venta y el código. */
99
117
  export interface HoldSalePromotionResponse {
100
118
  sessionId: string;
@@ -106,6 +124,8 @@ export interface HoldSalePromotionResponse {
106
124
  saleGiftSkus: string[];
107
125
  lines: LinePromotionDiscount[];
108
126
  totalDiscountCents: number;
127
+ /** Todas las promos apartadas; los campos de arriba se conservan por compatibilidad. */
128
+ promotions: HeldPromotion[];
109
129
  }
110
130
 
111
131
  /** `released: false` = no había apartado; soltar es idempotente. */
@@ -142,6 +162,7 @@ export interface SaleAppliedPromotion {
142
162
  version: number;
143
163
  name: string;
144
164
  kind: SalePromotionKindEnum;
165
+ stackable?: boolean;
145
166
  }
146
167
 
147
168
  /** Cupón y «lo que se lleva» de una venta cerrada (publicGetSaleCoupon). */
@@ -45,4 +45,6 @@ export enum RetailPromotionsErrorCodeEnum {
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
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
  }
@@ -34,6 +34,11 @@ export * from './dtos/SalePromotion';
34
34
  export * from './dtos/SalePromotionLogEntry';
35
35
  export * from './dtos/DiscountCode';
36
36
  export * from './dtos/LinePromotionDiscount';
37
+ export * from './dtos/LinePromotionAmount';
38
+ export * from './dtos/SalePromotionRef';
39
+
40
+ // Validadores
41
+ export * from './validators/IsHoldModeExclusiveConstraint';
37
42
 
38
43
  // Request DTOs
39
44
  export * from './dtos/requests/DiscountValueInput';
@@ -50,6 +55,7 @@ export * from './dtos/requests/ChangeDiscountCodeStatusRequest';
50
55
  export * from './dtos/requests/ListStoreSalePromotionsQuery';
51
56
  export * from './dtos/requests/EvaluateSalePromotionsRequest';
52
57
  export * from './dtos/requests/HoldGiftPromotionInput';
58
+ export * from './dtos/requests/HoldPromotionInput';
53
59
  export * from './dtos/requests/HoldSalePromotionRequest';
54
60
  export * from './dtos/requests/GetSaleCouponQuery';
55
61
  export * from './dtos/requests/SkuSalePromotionsQuery';
@@ -0,0 +1,18 @@
1
+ import {
2
+ ValidatorConstraint,
3
+ type ValidationArguments,
4
+ type ValidatorConstraintInterface,
5
+ } from 'class-validator';
6
+
7
+ /** Rechaza mandar `promotions` junto con `gift`, `promotionId` o `saleGiftSkus` (forma vieja). */
8
+ @ValidatorConstraint({ name: 'isHoldModeExclusive', async: false })
9
+ export class IsHoldModeExclusiveConstraint implements ValidatorConstraintInterface {
10
+ validate(_value: unknown, args: ValidationArguments): boolean {
11
+ const o = args.object as { gift?: unknown; promotionId?: unknown; saleGiftSkus?: unknown };
12
+ return o.gift == null && o.promotionId == null && o.saleGiftSkus == null;
13
+ }
14
+
15
+ defaultMessage(): string {
16
+ return 'promotions no se combina con gift, promotionId ni saleGiftSkus';
17
+ }
18
+ }
@@ -5,6 +5,7 @@ import type { ExternalProviderEnum } from '../enums/ExternalProviderEnum';
5
5
  import type { CentralSyncStatusEnum } from '../enums/CentralSyncStatusEnum';
6
6
  import type { SalePaymentDetail } from './SalePaymentDetail';
7
7
  import type { SaleLine } from './SaleLine';
8
+ import type { SalePromotionRef } from '../../retailPromotions/dtos/SalePromotionRef';
8
9
 
9
10
  /**
10
11
  * Venta (modelo-datos §3). pk `SALE#<saleId>` · sk `META` · 4 GSIs (`retailerId-soldAt-index`,
@@ -32,6 +33,8 @@ export interface Sale {
32
33
  /** Promo de venta congelada al cerrar; `null` = ninguna. */
33
34
  salePromotionId?: string | null;
34
35
  salePromotionVersion?: number | null;
36
+ /** Todas las promos de venta congeladas al cerrar. */
37
+ salePromotions?: SalePromotionRef[] | null;
35
38
  /** IMEI consumido del silo también en contado (local-first); null en EXTERNAL_REFERRAL (D15). */
36
39
  imei: string | null;
37
40
  /** Lo cobrado en caja al cerrar: enganche + lo no financiado; 0 en EXTERNAL_REFERRAL. Contrato de `SaleCompletedV1`. */