@fiado/type-kit 3.570.0 → 3.572.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.
@@ -188,6 +188,11 @@ describe('CustomerReferral y respuestas', () => {
188
188
  expect(errorsOf(CustomerReferral, { ...referral, source: 'WEB' })).toEqual(['source']);
189
189
  });
190
190
 
191
+ it('acepta la marca de cliente existente al capturar, opcional', () => {
192
+ expect(errorsOf(CustomerReferral, { ...referral, existingCustomerAtCapture: true })).toEqual([]);
193
+ expect(errorsOf(CustomerReferral, { ...referral, existingCustomerAtCapture: 'sí' })).toEqual(['existingCustomerAtCapture']);
194
+ });
195
+
191
196
  it('describe las respuestas de las rutas privadas', () => {
192
197
  const created: CreateCustomerReferralsResponse = { referrals: [referral] };
193
198
  const updated: UpdateCustomerReferralResponse = { referral };
@@ -200,6 +205,7 @@ describe('CustomerReferral y respuestas', () => {
200
205
  referrerName: 'Juan Pérez',
201
206
  source: ReferralSourceEnum.SALE,
202
207
  capturedAt: '2026-10-21T10:00:00Z',
208
+ existingCustomerAtCapture: false,
203
209
  },
204
210
  ],
205
211
  };
@@ -6,8 +6,8 @@ import { BonusTypeEnum, UpsertPromotionBonusRequest } from '../../../src/retailC
6
6
  import type { PromotionBonusEntryResponse } from '../../../src/retailCustomer/index';
7
7
 
8
8
  describe('BonusTypeEnum', () => {
9
- it('distingue la bienvenida de las dos promociones', () => {
10
- expect(Object.values(BonusTypeEnum)).toEqual(['WELCOME', 'CREDIT_PROMOTION', 'SALE_PROMOTION']);
9
+ it('distingue la bienvenida, las dos promociones y el premio de referido', () => {
10
+ expect(Object.values(BonusTypeEnum)).toEqual(['WELCOME', 'CREDIT_PROMOTION', 'SALE_PROMOTION', 'REFERRAL']);
11
11
  });
12
12
 
13
13
  it('sale por el index raíz', () => {
@@ -51,6 +51,10 @@ describe('UpsertPromotionBonusRequest', () => {
51
51
  expect(errorsOf({ ...PENDING_SALE, bonusType: 'WELCOME' })).toContain('bonusType');
52
52
  });
53
53
 
54
+ it('acepta el premio de referido con su rol y referido', () => {
55
+ expect(errorsOf({ ...PENDING_SALE, bonusType: 'REFERRAL', role: 'REFERRER', referralId: 'ref-1' })).toEqual([]);
56
+ });
57
+
54
58
  it.each(['promotionId', 'sourceId', 'storeId', 'currency', 'idempotencyKey'])('rechaza %s vacío', (field) => {
55
59
  expect(errorsOf({ ...PENDING_SALE, [field]: ' ' })).toContain(field);
56
60
  });
@@ -124,6 +124,26 @@ describe('ReferralPromotionInput', () => {
124
124
  expect(errorsOf(ReferralPromotionInput, bad)).toEqual(['minAmountCents', 'windowDays', 'maxRewardsPerReferrer']);
125
125
  });
126
126
 
127
+ it('acepta sin límites por referido ni por recomendado (ausente = 1)', () => {
128
+ expect(errorsOf(ReferralPromotionInput, { ...REFERRAL, maxRewardsPerReferral: 3, maxReferredRewards: 2 })).toEqual([]);
129
+ expect(errorsOf(ReferralPromotionInput, { ...REFERRAL, maxRewardsPerReferral: null, maxReferredRewards: null })).toEqual([]);
130
+ });
131
+
132
+ it('rechaza límites por referido y por recomendado en cero, negativos o decimales', () => {
133
+ expect(errorsOf(ReferralPromotionInput, { ...REFERRAL, maxRewardsPerReferral: 0, maxReferredRewards: 0 })).toEqual([
134
+ 'maxRewardsPerReferral',
135
+ 'maxReferredRewards',
136
+ ]);
137
+ expect(errorsOf(ReferralPromotionInput, { ...REFERRAL, maxRewardsPerReferral: -2, maxReferredRewards: -1 })).toEqual([
138
+ 'maxRewardsPerReferral',
139
+ 'maxReferredRewards',
140
+ ]);
141
+ expect(errorsOf(ReferralPromotionInput, { ...REFERRAL, maxRewardsPerReferral: 1.5, maxReferredRewards: 2.5 })).toEqual([
142
+ 'maxRewardsPerReferral',
143
+ 'maxReferredRewards',
144
+ ]);
145
+ });
146
+
127
147
  it('deja al lambda el mínimo de 2 en compra N y racha (INVALID_REFERRAL_TRIGGER)', () => {
128
148
  const nth = { ...REFERRAL, trigger: 'NTH_PURCHASE', purchaseNumber: 1 };
129
149
  expect(errorsOf(ReferralPromotionInput, nth)).toEqual([]);
@@ -162,6 +182,8 @@ describe('promo de referido en el CRUD de promos', () => {
162
182
  minAmountCents: null,
163
183
  windowDays: 60,
164
184
  maxRewardsPerReferrer: null,
185
+ maxRewardsPerReferral: 2,
186
+ maxReferredRewards: 1,
165
187
  referrerReward: {
166
188
  type: ReferralRewardTypeEnum.FIXED_BONUS,
167
189
  amountCents: 100_00,
@@ -18,6 +18,8 @@ export declare class CustomerReferral {
18
18
  saleId: string | null;
19
19
  /** Solo en `OPENING`. */
20
20
  accountOpeningSessionId: string | null;
21
+ /** `true` si el teléfono ya era cliente de alguna cadena del tenant al capturarlo; no genera premios. */
22
+ existingCustomerAtCapture?: boolean;
21
23
  createdBy: string;
22
24
  updatedBy: string;
23
25
  createdAt: string;
@@ -77,6 +77,12 @@ __decorate([
77
77
  (0, class_validator_1.IsString)(),
78
78
  __metadata("design:type", String)
79
79
  ], CustomerReferral.prototype, "accountOpeningSessionId", void 0);
80
+ __decorate([
81
+ (0, class_transformer_1.Expose)(),
82
+ (0, class_validator_1.IsOptional)(),
83
+ (0, class_validator_1.IsBoolean)(),
84
+ __metadata("design:type", Boolean)
85
+ ], CustomerReferral.prototype, "existingCustomerAtCapture", void 0);
80
86
  __decorate([
81
87
  (0, class_transformer_1.Expose)(),
82
88
  (0, class_validator_1.IsString)(),
@@ -18,7 +18,7 @@ const ReferralRoleEnum_1 = require("../../enums/ReferralRoleEnum");
18
18
  const WelcomeBonusStatusEnum_1 = require("../../enums/WelcomeBonusStatusEnum");
19
19
  /** Tope del motivo libre que el caller escribe en el asiento. */
20
20
  const FREE_TEXT_MAX_LENGTH = 256;
21
- const PROMOTION_BONUS_TYPES = [BonusTypeEnum_1.BonusTypeEnum.CREDIT_PROMOTION, BonusTypeEnum_1.BonusTypeEnum.SALE_PROMOTION];
21
+ const PROMOTION_BONUS_TYPES = [BonusTypeEnum_1.BonusTypeEnum.CREDIT_PROMOTION, BonusTypeEnum_1.BonusTypeEnum.SALE_PROMOTION, BonusTypeEnum_1.BonusTypeEnum.REFERRAL];
22
22
  const STATUSES_REQUIRING_REASON = [
23
23
  WelcomeBonusStatusEnum_1.WelcomeBonusStatusEnum.FAILED,
24
24
  WelcomeBonusStatusEnum_1.WelcomeBonusStatusEnum.UNVERIFIED,
@@ -20,6 +20,8 @@ export interface ReferralByPhone {
20
20
  referrerName: string;
21
21
  source: ReferralSourceEnum;
22
22
  capturedAt: string;
23
+ /** `true` si el teléfono ya era cliente al capturarlo; no genera premios. */
24
+ existingCustomerAtCapture?: boolean;
23
25
  }
24
26
  /** Respuesta de `privateGetReferralsByPhone`, del más antiguo al más reciente. */
25
27
  export interface ReferralsByPhoneResponse {
@@ -2,5 +2,6 @@
2
2
  export declare enum BonusTypeEnum {
3
3
  WELCOME = "WELCOME",
4
4
  CREDIT_PROMOTION = "CREDIT_PROMOTION",
5
- SALE_PROMOTION = "SALE_PROMOTION"
5
+ SALE_PROMOTION = "SALE_PROMOTION",
6
+ REFERRAL = "REFERRAL"
6
7
  }
@@ -7,4 +7,5 @@ var BonusTypeEnum;
7
7
  BonusTypeEnum["WELCOME"] = "WELCOME";
8
8
  BonusTypeEnum["CREDIT_PROMOTION"] = "CREDIT_PROMOTION";
9
9
  BonusTypeEnum["SALE_PROMOTION"] = "SALE_PROMOTION";
10
+ BonusTypeEnum["REFERRAL"] = "REFERRAL";
10
11
  })(BonusTypeEnum || (exports.BonusTypeEnum = BonusTypeEnum = {}));
@@ -27,6 +27,10 @@ export interface ReferralPromotionConfig {
27
27
  /** Días desde la captura del referido. */
28
28
  windowDays: number | null;
29
29
  maxRewardsPerReferrer: number | null;
30
+ /** Veces que se paga a quien recomienda por cada referido; ausente o `null` = 1. */
31
+ maxRewardsPerReferral?: number | null;
32
+ /** Veces que se paga o aplica el premio al recomendado; ausente o `null` = 1. */
33
+ maxReferredRewards?: number | null;
30
34
  referrerReward: ReferralReward;
31
35
  /** `null` = el recomendado no gana nada. */
32
36
  referredReward: ReferralReward | null;
@@ -19,6 +19,10 @@ export declare class ReferralPromotionInput {
19
19
  minAmountCents?: number | null;
20
20
  windowDays?: number | null;
21
21
  maxRewardsPerReferrer?: number | null;
22
+ /** Veces que se paga a quien recomienda por cada referido; ausente = 1. */
23
+ maxRewardsPerReferral?: number | null;
24
+ /** Veces que se paga o aplica el premio al recomendado; ausente = 1. */
25
+ maxReferredRewards?: number | null;
22
26
  referrerReward: ReferralRewardInput;
23
27
  referredReward?: ReferralRewardInput | null;
24
28
  }
@@ -103,6 +103,20 @@ __decorate([
103
103
  (0, class_validator_1.Min)(1),
104
104
  __metadata("design:type", Number)
105
105
  ], ReferralPromotionInput.prototype, "maxRewardsPerReferrer", void 0);
106
+ __decorate([
107
+ (0, class_transformer_1.Expose)(),
108
+ (0, class_validator_1.IsOptional)(),
109
+ (0, class_validator_1.IsInt)(),
110
+ (0, class_validator_1.Min)(1),
111
+ __metadata("design:type", Number)
112
+ ], ReferralPromotionInput.prototype, "maxRewardsPerReferral", void 0);
113
+ __decorate([
114
+ (0, class_transformer_1.Expose)(),
115
+ (0, class_validator_1.IsOptional)(),
116
+ (0, class_validator_1.IsInt)(),
117
+ (0, class_validator_1.Min)(1),
118
+ __metadata("design:type", Number)
119
+ ], ReferralPromotionInput.prototype, "maxReferredRewards", void 0);
106
120
  __decorate([
107
121
  (0, class_transformer_1.Expose)(),
108
122
  (0, class_validator_1.IsDefined)(),
@@ -15,6 +15,10 @@ export interface LiveReferralPromotionItem {
15
15
  installmentStreak: number | null;
16
16
  /** Fin de vigencia; `null` = sin fecha de fin. */
17
17
  validUntil: string | null;
18
+ /** Veces que se paga a quien recomienda por cada referido; ausente o `null` = 1. */
19
+ maxRewardsPerReferral?: number | null;
20
+ /** Veces que se paga o aplica el premio al recomendado; ausente o `null` = 1. */
21
+ maxReferredRewards?: number | null;
18
22
  referrerReward: ReferralReward;
19
23
  /** `null` = el recomendado no gana nada. */
20
24
  referredReward: ReferralReward | null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.570.0",
3
+ "version": "3.572.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -1,5 +1,5 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsEnum, IsISO8601, IsOptional, IsString } from 'class-validator';
2
+ import { IsBoolean, IsEnum, IsISO8601, IsOptional, IsString } from 'class-validator';
3
3
  import { ReferralSourceEnum } from '../enums/ReferralSourceEnum';
4
4
 
5
5
  /** Persona que un cliente recomienda (owner: retail-customer-business). Teléfono normalizado a 10 dígitos. */
@@ -59,6 +59,12 @@ export class CustomerReferral {
59
59
  @IsString()
60
60
  accountOpeningSessionId!: string | null;
61
61
 
62
+ /** `true` si el teléfono ya era cliente de alguna cadena del tenant al capturarlo; no genera premios. */
63
+ @Expose()
64
+ @IsOptional()
65
+ @IsBoolean()
66
+ existingCustomerAtCapture?: boolean;
67
+
62
68
  @Expose()
63
69
  @IsString()
64
70
  createdBy!: string;
@@ -8,7 +8,7 @@ import { WelcomeBonusStatusEnum } from '../../enums/WelcomeBonusStatusEnum';
8
8
  /** Tope del motivo libre que el caller escribe en el asiento. */
9
9
  const FREE_TEXT_MAX_LENGTH = 256;
10
10
 
11
- const PROMOTION_BONUS_TYPES = [BonusTypeEnum.CREDIT_PROMOTION, BonusTypeEnum.SALE_PROMOTION];
11
+ const PROMOTION_BONUS_TYPES = [BonusTypeEnum.CREDIT_PROMOTION, BonusTypeEnum.SALE_PROMOTION, BonusTypeEnum.REFERRAL];
12
12
 
13
13
  const STATUSES_REQUIRING_REASON: WelcomeBonusStatusEnum[] = [
14
14
  WelcomeBonusStatusEnum.FAILED,
@@ -24,6 +24,8 @@ export interface ReferralByPhone {
24
24
  referrerName: string;
25
25
  source: ReferralSourceEnum;
26
26
  capturedAt: string;
27
+ /** `true` si el teléfono ya era cliente al capturarlo; no genera premios. */
28
+ existingCustomerAtCapture?: boolean;
27
29
  }
28
30
 
29
31
  /** Respuesta de `privateGetReferralsByPhone`, del más antiguo al más reciente. */
@@ -3,4 +3,5 @@ export enum BonusTypeEnum {
3
3
  WELCOME = 'WELCOME',
4
4
  CREDIT_PROMOTION = 'CREDIT_PROMOTION',
5
5
  SALE_PROMOTION = 'SALE_PROMOTION',
6
+ REFERRAL = 'REFERRAL',
6
7
  }
@@ -29,6 +29,10 @@ export interface ReferralPromotionConfig {
29
29
  /** Días desde la captura del referido. */
30
30
  windowDays: number | null;
31
31
  maxRewardsPerReferrer: number | null;
32
+ /** Veces que se paga a quien recomienda por cada referido; ausente o `null` = 1. */
33
+ maxRewardsPerReferral?: number | null;
34
+ /** Veces que se paga o aplica el premio al recomendado; ausente o `null` = 1. */
35
+ maxReferredRewards?: number | null;
32
36
  referrerReward: ReferralReward;
33
37
  /** `null` = el recomendado no gana nada. */
34
38
  referredReward: ReferralReward | null;
@@ -79,6 +79,20 @@ export class ReferralPromotionInput {
79
79
  @Min(1)
80
80
  maxRewardsPerReferrer?: number | null;
81
81
 
82
+ /** Veces que se paga a quien recomienda por cada referido; ausente = 1. */
83
+ @Expose()
84
+ @IsOptional()
85
+ @IsInt()
86
+ @Min(1)
87
+ maxRewardsPerReferral?: number | null;
88
+
89
+ /** Veces que se paga o aplica el premio al recomendado; ausente = 1. */
90
+ @Expose()
91
+ @IsOptional()
92
+ @IsInt()
93
+ @Min(1)
94
+ maxReferredRewards?: number | null;
95
+
82
96
  @Expose()
83
97
  @IsDefined()
84
98
  @ValidateNested()
@@ -16,6 +16,10 @@ export interface LiveReferralPromotionItem {
16
16
  installmentStreak: number | null;
17
17
  /** Fin de vigencia; `null` = sin fecha de fin. */
18
18
  validUntil: string | null;
19
+ /** Veces que se paga a quien recomienda por cada referido; ausente o `null` = 1. */
20
+ maxRewardsPerReferral?: number | null;
21
+ /** Veces que se paga o aplica el premio al recomendado; ausente o `null` = 1. */
22
+ maxReferredRewards?: number | null;
19
23
  referrerReward: ReferralReward;
20
24
  /** `null` = el recomendado no gana nada. */
21
25
  referredReward: ReferralReward | null;