@fiado/type-kit 3.636.0 → 3.638.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 (35) hide show
  1. package/_test_/unit/emailVerification/dtos/internal/EmailOwnersByEmailRequest.test.ts +29 -0
  2. package/_test_/unit/retailWizard/salePayments.test.ts +43 -35
  3. package/bin/emailVerification/dtos/internal/EmailOwnersByEmailRequest.d.ts +6 -0
  4. package/bin/emailVerification/dtos/internal/EmailOwnersByEmailRequest.js +25 -0
  5. package/bin/emailVerification/index.d.ts +1 -0
  6. package/bin/emailVerification/index.js +1 -0
  7. package/bin/retailCommission/dtos/CommissionApi.d.ts +63 -0
  8. package/bin/retailWizard/dtos/SalePayment.d.ts +4 -1
  9. package/bin/retailWizard/dtos/SalePayment.js +8 -14
  10. package/bin/retailWizard/dtos/StoredSalePayment.d.ts +13 -0
  11. package/bin/retailWizard/dtos/StoredSalePayment.js +59 -0
  12. package/bin/retailWizard/dtos/requests/CreateAccessorySaleRequest.d.ts +1 -1
  13. package/bin/retailWizard/dtos/requests/CreateAccessorySaleRequest.js +2 -2
  14. package/bin/retailWizard/dtos/requests/DownPaymentRequest.d.ts +1 -1
  15. package/bin/retailWizard/dtos/requests/DownPaymentRequest.js +2 -2
  16. package/bin/retailWizard/dtos/requests/RegisterPaymentRequest.d.ts +1 -1
  17. package/bin/retailWizard/dtos/requests/RegisterPaymentRequest.js +2 -2
  18. package/bin/retailWizard/index.d.ts +2 -0
  19. package/bin/retailWizard/index.js +2 -0
  20. package/bin/retailWizard/validators/IsSalePaymentInputList.d.ts +2 -0
  21. package/bin/retailWizard/validators/IsSalePaymentInputList.js +11 -0
  22. package/bin/retailWizard/validators/IsSalePaymentList.d.ts +1 -1
  23. package/bin/retailWizard/validators/IsSalePaymentList.js +3 -3
  24. package/package.json +1 -1
  25. package/src/emailVerification/dtos/internal/EmailOwnersByEmailRequest.ts +11 -0
  26. package/src/emailVerification/index.ts +1 -0
  27. package/src/retailCommission/dtos/CommissionApi.ts +25 -0
  28. package/src/retailWizard/dtos/SalePayment.ts +9 -20
  29. package/src/retailWizard/dtos/StoredSalePayment.ts +46 -0
  30. package/src/retailWizard/dtos/requests/CreateAccessorySaleRequest.ts +3 -3
  31. package/src/retailWizard/dtos/requests/DownPaymentRequest.ts +3 -3
  32. package/src/retailWizard/dtos/requests/RegisterPaymentRequest.ts +3 -3
  33. package/src/retailWizard/index.ts +2 -0
  34. package/src/retailWizard/validators/IsSalePaymentInputList.ts +9 -0
  35. package/src/retailWizard/validators/IsSalePaymentList.ts +3 -3
@@ -0,0 +1,29 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validate } from 'class-validator';
4
+ import { EmailOwnersByEmailRequest } from '../../../../../src/emailVerification/dtos/internal/EmailOwnersByEmailRequest';
5
+ import * as emailVerification from '../../../../../src/emailVerification';
6
+
7
+ describe('EmailOwnersByEmailRequest', () => {
8
+ it('valida happy path (0 errores)', async () => {
9
+ const dto = plainToInstance(EmailOwnersByEmailRequest, { email: 'persona@ejemplo.com' });
10
+ const errors = await validate(dto);
11
+ expect(errors).toEqual([]);
12
+ });
13
+
14
+ it('falla si email no es un correo válido', async () => {
15
+ const dto = plainToInstance(EmailOwnersByEmailRequest, { email: 'no-es-correo' });
16
+ const errors = await validate(dto);
17
+ expect(errors.some(e => e.property === 'email')).toBe(true);
18
+ });
19
+
20
+ it('falla si falta email', async () => {
21
+ const dto = plainToInstance(EmailOwnersByEmailRequest, {});
22
+ const errors = await validate(dto);
23
+ expect(errors.some(e => e.property === 'email')).toBe(true);
24
+ });
25
+
26
+ it('se exporta desde el barrel de emailVerification', () => {
27
+ expect(emailVerification.EmailOwnersByEmailRequest).toBe(EmailOwnersByEmailRequest);
28
+ });
29
+ });
@@ -3,6 +3,7 @@ import { plainToInstance } from 'class-transformer';
3
3
  import { validateSync, type ValidationError } from 'class-validator';
4
4
  import { SalePayment } from '../../../src/retailWizard/dtos/SalePayment';
5
5
  import { WizardPayment } from '../../../src/retailWizard/dtos/WizardPayment';
6
+ import { StoredSalePayment } from '../../../src/retailWizard/dtos/StoredSalePayment';
6
7
  import { RegisterPaymentRequest } from '../../../src/retailWizard/dtos/requests/RegisterPaymentRequest';
7
8
  import { DownPaymentRequest } from '../../../src/retailWizard/dtos/requests/DownPaymentRequest';
8
9
  import { CreateAccessorySaleRequest } from '../../../src/retailWizard/dtos/requests/CreateAccessorySaleRequest';
@@ -28,17 +29,32 @@ const cash = { method: CASH, amountCents: 10000, cashConfirmedInRegister: true }
28
29
  const card = { method: CARD, amountCents: 5000, cardLast4: '4242', authCode: 'A1B2C3' };
29
30
  const wire = { method: WIRE, amountCents: 5000, speiTrackingKey: 'MBAN01002610', senderClabe: '012180001234567897' };
30
31
 
31
- describe('SalePayment', () => {
32
+ describe('SalePayment (forma del request)', () => {
33
+ it('acepta cualquier monto entero y comprobante en texto, sin revisar formato ni medio', () => {
34
+ expect(errorsOf(SalePayment, { method: CARD, amountCents: 0, cardLast4: '1', authCode: ' ' })).toEqual([]);
35
+ expect(errorsOf(SalePayment, { method: CASH, amountCents: -5, speiTrackingKey: 'MBAN-01' })).toEqual([]);
36
+ expect(errorsOf(SalePayment, { method: WIRE, amountCents: 1, senderClabe: null, cashConfirmedInRegister: null })).toEqual([]);
37
+ });
38
+
39
+ it('rechaza lo que no tiene la forma', () => {
40
+ expect(errorsOf(SalePayment, { method: 'FIADO', amountCents: 1 })).toEqual(['method']);
41
+ expect(errorsOf(SalePayment, { method: CASH, amountCents: 1.5 })).toEqual(['amountCents']);
42
+ expect(errorsOf(SalePayment, { method: CARD, amountCents: 1, cardLast4: 4242 })).toEqual(['cardLast4']);
43
+ expect(errorsOf(SalePayment, { method: CASH, amountCents: 1, cashConfirmedInRegister: 'yes' })).toEqual(['cashConfirmedInRegister']);
44
+ });
45
+ });
46
+
47
+ describe('StoredSalePayment (cobro ya registrado)', () => {
32
48
  it('acepta cada medio con comprobante', () => {
33
- expect(errorsOf(SalePayment, cash)).toEqual([]);
34
- expect(errorsOf(SalePayment, card)).toEqual([]);
35
- expect(errorsOf(SalePayment, wire)).toEqual([]);
49
+ expect(errorsOf(StoredSalePayment, cash)).toEqual([]);
50
+ expect(errorsOf(StoredSalePayment, card)).toEqual([]);
51
+ expect(errorsOf(StoredSalePayment, wire)).toEqual([]);
36
52
  });
37
53
 
38
54
  it('acepta tarjeta y SPEI sin comprobante, ausente o en null', () => {
39
- expect(errorsOf(SalePayment, { method: CARD, amountCents: 5000 })).toEqual([]);
40
- expect(errorsOf(SalePayment, { method: WIRE, amountCents: 5000, speiTrackingKey: null, senderClabe: null })).toEqual([]);
41
- expect(errorsOf(SalePayment, { method: CASH, amountCents: 5000, cashConfirmedInRegister: null })).toEqual([]);
55
+ expect(errorsOf(StoredSalePayment, { method: CARD, amountCents: 5000 })).toEqual([]);
56
+ expect(errorsOf(StoredSalePayment, { method: WIRE, amountCents: 5000, speiTrackingKey: null, senderClabe: null })).toEqual([]);
57
+ expect(errorsOf(StoredSalePayment, { method: CASH, amountCents: 5000, cashConfirmedInRegister: null })).toEqual([]);
42
58
  });
43
59
 
44
60
  it.each([
@@ -49,7 +65,7 @@ describe('SalePayment', () => {
49
65
  ['senderClabe', { ...wire, senderClabe: '0121' }],
50
66
  ['cashConfirmedInRegister', { ...cash, cashConfirmedInRegister: 'yes' }],
51
67
  ])('rechaza %s con formato inválido', (field, payload) => {
52
- expect(errorsOf(SalePayment, payload)).toEqual([field]);
68
+ expect(errorsOf(StoredSalePayment, payload)).toEqual([field]);
53
69
  });
54
70
 
55
71
  it.each([
@@ -57,13 +73,13 @@ describe('SalePayment', () => {
57
73
  ['speiTrackingKey', { ...card, speiTrackingKey: 'MBAN01' }],
58
74
  ['cashConfirmedInRegister', { ...wire, cashConfirmedInRegister: true }],
59
75
  ])('rechaza %s en un medio que no le corresponde', (field, payload) => {
60
- expect(errorsOf(SalePayment, payload)).toEqual([field]);
76
+ expect(errorsOf(StoredSalePayment, payload)).toEqual([field]);
61
77
  });
62
78
 
63
79
  it('rechaza un medio fuera del enum y un monto no positivo', () => {
64
- expect(errorsOf(SalePayment, { method: 'FIADO', amountCents: 100 })).toEqual(['method']);
65
- expect(errorsOf(SalePayment, { ...cash, amountCents: 0 })).toEqual(['amountCents']);
66
- expect(errorsOf(SalePayment, { ...cash, amountCents: 10.5 })).toEqual(['amountCents']);
80
+ expect(errorsOf(StoredSalePayment, { method: 'FIADO', amountCents: 100 })).toEqual(['method']);
81
+ expect(errorsOf(StoredSalePayment, { ...cash, amountCents: 0 })).toEqual(['amountCents']);
82
+ expect(errorsOf(StoredSalePayment, { ...cash, amountCents: 10.5 })).toEqual(['amountCents']);
67
83
  });
68
84
  });
69
85
 
@@ -72,10 +88,6 @@ describe('payments en RegisterPaymentRequest', () => {
72
88
  expect(errorsOf(RegisterPaymentRequest, { amountCents: 20000, payments: [cash, card, wire] })).toEqual([]);
73
89
  });
74
90
 
75
- it('acepta tarjeta repetida', () => {
76
- expect(errorsOf(RegisterPaymentRequest, { amountCents: 20000, payments: [cash, card, card] })).toEqual([]);
77
- });
78
-
79
91
  it('sigue aceptando el formato viejo', () => {
80
92
  expect(errorsOf(RegisterPaymentRequest, { method: CASH, amountCents: 20000, detail: { cashConfirmedInRegister: true } })).toEqual([]);
81
93
  });
@@ -84,24 +96,17 @@ describe('payments en RegisterPaymentRequest', () => {
84
96
  expect(errorsOf(RegisterPaymentRequest, { amountCents: 20000 })).toEqual(['method']);
85
97
  });
86
98
 
87
- it('rechaza efectivo o SPEI repetidos', () => {
88
- expect(errorsOf(RegisterPaymentRequest, { amountCents: 20000, payments: [cash, cash] })).toEqual(['payments']);
89
- expect(errorsOf(RegisterPaymentRequest, { amountCents: 10000, payments: [wire, wire] })).toEqual(['payments']);
90
- });
91
-
92
- it(`rechaza más de ${MAX_SALE_PAYMENTS} pagos o una lista vacía`, () => {
93
- expect(errorsOf(RegisterPaymentRequest, { amountCents: 25000, payments: [cash, card, card, wire] })).toEqual(['payments']);
94
- expect(errorsOf(RegisterPaymentRequest, { amountCents: 0, payments: [] })).toEqual(['payments']);
95
- });
96
-
97
- it('rechaza que la suma no cuadre con amountCents', () => {
98
- expect(errorsOf(RegisterPaymentRequest, { amountCents: 20001, payments: [cash, card, wire] })).toEqual(['payments']);
99
+ it('deja pasar las reglas de negocio para que el dominio responda con su code', () => {
100
+ expect(errorsOf(RegisterPaymentRequest, { amountCents: 20000, payments: [cash, cash] })).toEqual([]);
101
+ expect(errorsOf(RegisterPaymentRequest, { amountCents: 25000, payments: [cash, card, card, wire] })).toEqual([]);
102
+ expect(errorsOf(RegisterPaymentRequest, { amountCents: 0, payments: [] })).toEqual([]);
103
+ expect(errorsOf(RegisterPaymentRequest, { amountCents: 20001, payments: [cash, card, wire] })).toEqual([]);
104
+ expect(errorsOf(RegisterPaymentRequest, { amountCents: 15000, payments: [cash, { ...card, cardLast4: '1' }] })).toEqual([]);
99
105
  });
100
106
 
101
- it('reporta el campo del pago inválido', () => {
102
- expect(errorsOf(RegisterPaymentRequest, { amountCents: 15000, payments: [cash, { ...card, cardLast4: '1' }] })).toEqual([
103
- 'payments.1.cardLast4',
104
- ]);
107
+ it('rechaza lo que no tiene la forma y reporta el campo', () => {
108
+ expect(errorsOf(RegisterPaymentRequest, { amountCents: 1, payments: 'CASH' })).toEqual(['payments']);
109
+ expect(errorsOf(RegisterPaymentRequest, { amountCents: 1, payments: [{ ...card, method: 'FIADO' }] })).toEqual(['payments.0.method']);
105
110
  });
106
111
  });
107
112
 
@@ -135,16 +140,18 @@ describe('cobro de $0', () => {
135
140
  });
136
141
 
137
142
  describe('payments en los demás contratos', () => {
138
- it('DownPaymentRequest acepta solo payments y valida la suma', () => {
143
+ it('DownPaymentRequest acepta solo payments y deja la suma al dominio', () => {
139
144
  expect(errorsOf(DownPaymentRequest, { amountCents: 15000, payments: [cash, wire] })).toEqual([]);
140
- expect(errorsOf(DownPaymentRequest, { amountCents: 1, payments: [cash, wire] })).toEqual(['payments']);
145
+ expect(errorsOf(DownPaymentRequest, { amountCents: 1, payments: [cash, wire] })).toEqual([]);
146
+ expect(errorsOf(DownPaymentRequest, { amountCents: 1, payments: [{ ...wire, amountCents: 'x' }] })).toEqual(['payments.0.amountCents']);
141
147
  });
142
148
 
143
149
  it('CreateAccessorySaleRequest acepta solo payments y ya no exige paymentDetail', () => {
144
150
  const lines = [{ sku: 'ACC-1', qty: 1 }];
145
151
  expect(errorsOf(CreateAccessorySaleRequest, { lines, amountCents: 15000, payments: [cash, card] })).toEqual([]);
146
152
  expect(errorsOf(CreateAccessorySaleRequest, { lines, amountCents: 15000 })).toEqual(['paymentMethod']);
147
- expect(errorsOf(CreateAccessorySaleRequest, { lines, amountCents: 20000, payments: [cash, cash] })).toEqual(['payments']);
153
+ expect(errorsOf(CreateAccessorySaleRequest, { lines, amountCents: 20000, payments: [cash, cash] })).toEqual([]);
154
+ expect(errorsOf(CreateAccessorySaleRequest, { lines, amountCents: 1, payments: [{ ...card, authCode: 7 }] })).toEqual(['payments.0.authCode']);
148
155
  });
149
156
 
150
157
  it('WizardPayment guarda payments tipados', () => {
@@ -152,6 +159,7 @@ describe('payments en los demás contratos', () => {
152
159
  expect(errorsOf(WizardPayment, { ...base, payments: [cash, card] })).toEqual([]);
153
160
  expect(errorsOf(WizardPayment, base)).toEqual([]);
154
161
  expect(errorsOf(WizardPayment, { ...base, payments: [cash, cash] })).toEqual(['payments']);
162
+ expect(errorsOf(WizardPayment, { ...base, payments: [{ ...card, cardLast4: '1' }] })).toEqual(['payments.0.cardLast4']);
155
163
  });
156
164
 
157
165
  it('RetailPromotionInboundMessage acepta paymentMethods y rechaza valores fuera del enum', () => {
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Request interno (api-invoker) para buscar qué directorios tienen un correo.
3
+ */
4
+ export declare class EmailOwnersByEmailRequest {
5
+ email: string;
6
+ }
@@ -0,0 +1,25 @@
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.EmailOwnersByEmailRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ /**
16
+ * Request interno (api-invoker) para buscar qué directorios tienen un correo.
17
+ */
18
+ class EmailOwnersByEmailRequest {
19
+ }
20
+ exports.EmailOwnersByEmailRequest = EmailOwnersByEmailRequest;
21
+ __decorate([
22
+ (0, class_transformer_1.Expose)(),
23
+ (0, class_validator_1.IsEmail)(),
24
+ __metadata("design:type", String)
25
+ ], EmailOwnersByEmailRequest.prototype, "email", void 0);
@@ -24,3 +24,4 @@ export * from './dtos/internal/EmailsByDirectoryRequest';
24
24
  export * from './dtos/internal/EmailsByDirectoryResponse';
25
25
  export * from './dtos/internal/EmailStartByDirectoryRequest';
26
26
  export * from './dtos/internal/EmailStartByDirectoryResponse';
27
+ export * from './dtos/internal/EmailOwnersByEmailRequest';
@@ -40,3 +40,4 @@ __exportStar(require("./dtos/internal/EmailsByDirectoryRequest"), exports);
40
40
  __exportStar(require("./dtos/internal/EmailsByDirectoryResponse"), exports);
41
41
  __exportStar(require("./dtos/internal/EmailStartByDirectoryRequest"), exports);
42
42
  __exportStar(require("./dtos/internal/EmailStartByDirectoryResponse"), exports);
43
+ __exportStar(require("./dtos/internal/EmailOwnersByEmailRequest"), exports);
@@ -1,4 +1,5 @@
1
1
  import type { CommissionPlanStatusEnum } from '../enums/CommissionPlanStatusEnum';
2
+ import type { CommissionRuleStatusEnum } from '../enums/CommissionRuleStatusEnum';
2
3
  import type { CommissionPayoutStatusEnum } from '../enums/CommissionPayoutStatusEnum';
3
4
  import type { CommissionAddOn, CommissionCategory, CommissionPlanSnapshot, CommissionQuota } from './CommissionPlan';
4
5
  import type { CommissionAccrual, CommissionAppliedBonus, CommissionSaleInput, CommissionSaleLine } from './CommissionAccrual';
@@ -227,12 +228,74 @@ export interface RuleActionResponse {
227
228
  rule: CommissionRule;
228
229
  snapshotId: string;
229
230
  }
231
+ /** Un campo de la regla que cambió de una versión a la siguiente, con su valor antes y después. */
232
+ export type CommissionRuleChange = {
233
+ field: 'name';
234
+ before: string;
235
+ after: string;
236
+ } | {
237
+ field: 'description';
238
+ before: string | null;
239
+ after: string | null;
240
+ } | {
241
+ field: 'levers';
242
+ before: CommissionRuleLevers;
243
+ after: CommissionRuleLevers;
244
+ } | {
245
+ field: 'scope';
246
+ before: CommissionRuleScope;
247
+ after: CommissionRuleScope;
248
+ } | {
249
+ field: 'condition';
250
+ before: CommissionRuleCondition | null;
251
+ after: CommissionRuleCondition | null;
252
+ } | {
253
+ field: 'effectiveFrom';
254
+ before: string;
255
+ after: string;
256
+ } | {
257
+ field: 'effectiveTo';
258
+ before: string | null;
259
+ after: string | null;
260
+ } | {
261
+ field: 'priority';
262
+ before: number;
263
+ after: number;
264
+ } | {
265
+ field: 'replacesOthers';
266
+ before: boolean;
267
+ after: boolean;
268
+ } | {
269
+ field: 'countBy';
270
+ before: CommissionCountByEnum;
271
+ after: CommissionCountByEnum;
272
+ } | {
273
+ field: 'payTiming';
274
+ before: CommissionPayTimingEnum;
275
+ after: CommissionPayTimingEnum;
276
+ } | {
277
+ field: 'onSaleAdvanceBps';
278
+ before: number | null;
279
+ after: number | null;
280
+ };
230
281
  /** Un evento del historial de una regla. */
231
282
  export interface CommissionRuleEvent {
232
283
  at: string;
233
284
  action: string;
234
285
  performedBy: string;
235
286
  version: number | null;
287
+ /**
288
+ * Solo en ediciones: lo que cambió respecto a la versión anterior; vacío si no cambió ningún campo.
289
+ * Ausente si no hay versión anterior con qué comparar, y en motores anteriores.
290
+ */
291
+ changes?: CommissionRuleChange[];
292
+ /** Junto a `changes`: si la versión editada cuenta piezas o ventas, para leer sus palancas y su condición. */
293
+ countBy?: CommissionCountByEnum;
294
+ /** El estado que tenía la regla y el que le dejó el evento; `null` si no lo cambió o no se sabe. Ausente en motores anteriores. */
295
+ statusChange?: {
296
+ from: CommissionRuleStatusEnum;
297
+ to: CommissionRuleStatusEnum;
298
+ } | null;
236
299
  }
237
300
  /** `GET /backoffice/commissions/rules/{ruleId}/history` — del más nuevo al más viejo. */
238
301
  export interface RuleHistoryResponse {
@@ -1,5 +1,8 @@
1
1
  import { SalePaymentMethodEnum } from '../enums/SalePaymentMethodEnum';
2
- /** Un pago del cobro. El comprobante es opcional: si viene se valida y solo en su medio; si no, `null` o ausente. */
2
+ /**
3
+ * Un pago del cobro tal como llega en un request: solo la forma. Tope, uso único, suma, monto
4
+ * positivo y formato del comprobante los valida el dominio con su code.
5
+ */
3
6
  export declare class SalePayment {
4
7
  method: SalePaymentMethodEnum;
5
8
  amountCents: number;
@@ -12,12 +12,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.SalePayment = void 0;
13
13
  const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
- const retailIntegrationLimits_1 = require("../../retailIntegration/constants/retailIntegrationLimits");
16
15
  const SalePaymentMethodEnum_1 = require("../enums/SalePaymentMethodEnum");
17
- const OnlyForPaymentMethodConstraint_1 = require("../validators/OnlyForPaymentMethodConstraint");
18
- const { CASH, CARD, WIRE } = SalePaymentMethodEnum_1.SalePaymentMethodEnum;
19
16
  const hasValue = (field) => (o) => o[field] != null;
20
- /** Un pago del cobro. El comprobante es opcional: si viene se valida y solo en su medio; si no, `null` o ausente. */
17
+ /**
18
+ * Un pago del cobro tal como llega en un request: solo la forma. Tope, uso único, suma, monto
19
+ * positivo y formato del comprobante los valida el dominio con su code.
20
+ */
21
21
  class SalePayment {
22
22
  }
23
23
  exports.SalePayment = SalePayment;
@@ -29,41 +29,35 @@ __decorate([
29
29
  __decorate([
30
30
  (0, class_transformer_1.Expose)(),
31
31
  (0, class_validator_1.IsInt)(),
32
- (0, class_validator_1.Min)(1),
33
32
  __metadata("design:type", Number)
34
33
  ], SalePayment.prototype, "amountCents", void 0);
35
34
  __decorate([
36
35
  (0, class_transformer_1.Expose)(),
37
36
  (0, class_validator_1.ValidateIf)(hasValue('cashConfirmedInRegister')),
38
37
  (0, class_validator_1.IsBoolean)(),
39
- (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [CASH]),
40
38
  __metadata("design:type", Boolean)
41
39
  ], SalePayment.prototype, "cashConfirmedInRegister", void 0);
42
40
  __decorate([
43
41
  (0, class_transformer_1.Expose)(),
44
42
  (0, class_validator_1.ValidateIf)(hasValue('cardLast4')),
45
- (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_CARD_LAST4_PATTERN),
46
- (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [CARD]),
43
+ (0, class_validator_1.IsString)(),
47
44
  __metadata("design:type", String)
48
45
  ], SalePayment.prototype, "cardLast4", void 0);
49
46
  __decorate([
50
47
  (0, class_transformer_1.Expose)(),
51
48
  (0, class_validator_1.ValidateIf)(hasValue('authCode')),
52
- (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_SALE_ID_TEXT_PATTERN),
53
- (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [CARD]),
49
+ (0, class_validator_1.IsString)(),
54
50
  __metadata("design:type", String)
55
51
  ], SalePayment.prototype, "authCode", void 0);
56
52
  __decorate([
57
53
  (0, class_transformer_1.Expose)(),
58
54
  (0, class_validator_1.ValidateIf)(hasValue('speiTrackingKey')),
59
- (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_SPEI_TRACKING_KEY_PATTERN),
60
- (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [WIRE]),
55
+ (0, class_validator_1.IsString)(),
61
56
  __metadata("design:type", String)
62
57
  ], SalePayment.prototype, "speiTrackingKey", void 0);
63
58
  __decorate([
64
59
  (0, class_transformer_1.Expose)(),
65
60
  (0, class_validator_1.ValidateIf)(hasValue('senderClabe')),
66
- (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_CLABE_PATTERN),
67
- (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [WIRE]),
61
+ (0, class_validator_1.IsString)(),
68
62
  __metadata("design:type", String)
69
63
  ], SalePayment.prototype, "senderClabe", void 0);
@@ -0,0 +1,13 @@
1
+ import { SalePayment } from './SalePayment';
2
+ /**
3
+ * Pago ya registrado (cobro de la sesión): monto positivo y comprobante con formato, solo en su medio.
4
+ * Repite las reglas de forma porque class-validator descarta las del padre en la propiedad que se redeclara.
5
+ */
6
+ export declare class StoredSalePayment extends SalePayment {
7
+ amountCents: number;
8
+ cashConfirmedInRegister?: boolean | null;
9
+ cardLast4?: string | null;
10
+ authCode?: string | null;
11
+ speiTrackingKey?: string | null;
12
+ senderClabe?: string | null;
13
+ }
@@ -0,0 +1,59 @@
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.StoredSalePayment = void 0;
13
+ const class_validator_1 = require("class-validator");
14
+ const retailIntegrationLimits_1 = require("../../retailIntegration/constants/retailIntegrationLimits");
15
+ const SalePaymentMethodEnum_1 = require("../enums/SalePaymentMethodEnum");
16
+ const OnlyForPaymentMethodConstraint_1 = require("../validators/OnlyForPaymentMethodConstraint");
17
+ const SalePayment_1 = require("./SalePayment");
18
+ const { CASH, CARD, WIRE } = SalePaymentMethodEnum_1.SalePaymentMethodEnum;
19
+ /**
20
+ * Pago ya registrado (cobro de la sesión): monto positivo y comprobante con formato, solo en su medio.
21
+ * Repite las reglas de forma porque class-validator descarta las del padre en la propiedad que se redeclara.
22
+ */
23
+ class StoredSalePayment extends SalePayment_1.SalePayment {
24
+ }
25
+ exports.StoredSalePayment = StoredSalePayment;
26
+ __decorate([
27
+ (0, class_validator_1.IsInt)(),
28
+ (0, class_validator_1.Min)(1),
29
+ __metadata("design:type", Number)
30
+ ], StoredSalePayment.prototype, "amountCents", void 0);
31
+ __decorate([
32
+ (0, class_validator_1.IsBoolean)(),
33
+ (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [CASH]),
34
+ __metadata("design:type", Boolean)
35
+ ], StoredSalePayment.prototype, "cashConfirmedInRegister", void 0);
36
+ __decorate([
37
+ (0, class_validator_1.IsString)(),
38
+ (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_CARD_LAST4_PATTERN),
39
+ (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [CARD]),
40
+ __metadata("design:type", String)
41
+ ], StoredSalePayment.prototype, "cardLast4", void 0);
42
+ __decorate([
43
+ (0, class_validator_1.IsString)(),
44
+ (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_SALE_ID_TEXT_PATTERN),
45
+ (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [CARD]),
46
+ __metadata("design:type", String)
47
+ ], StoredSalePayment.prototype, "authCode", void 0);
48
+ __decorate([
49
+ (0, class_validator_1.IsString)(),
50
+ (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_SPEI_TRACKING_KEY_PATTERN),
51
+ (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [WIRE]),
52
+ __metadata("design:type", String)
53
+ ], StoredSalePayment.prototype, "speiTrackingKey", void 0);
54
+ __decorate([
55
+ (0, class_validator_1.IsString)(),
56
+ (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_CLABE_PATTERN),
57
+ (0, class_validator_1.Validate)(OnlyForPaymentMethodConstraint_1.OnlyForPaymentMethodConstraint, [WIRE]),
58
+ __metadata("design:type", String)
59
+ ], StoredSalePayment.prototype, "senderClabe", void 0);
@@ -13,6 +13,6 @@ export declare class CreateAccessorySaleRequest {
13
13
  amountCents: number;
14
14
  /** @deprecated Usa el comprobante de cada elemento de `payments`. */
15
15
  paymentDetail?: SalePaymentDetail;
16
- /** Pagos del cobro (1 a 3); si viene, manda sobre `paymentMethod` y `paymentDetail`. */
16
+ /** Pagos del cobro; si viene, manda sobre `paymentMethod` y `paymentDetail`. */
17
17
  payments?: SalePayment[];
18
18
  }
@@ -15,7 +15,7 @@ const class_validator_1 = require("class-validator");
15
15
  const SalePaymentMethodEnum_1 = require("../../enums/SalePaymentMethodEnum");
16
16
  const SalePaymentDetail_1 = require("../SalePaymentDetail");
17
17
  const AccessorySaleLine_1 = require("../AccessorySaleLine");
18
- const IsSalePaymentList_1 = require("../../validators/IsSalePaymentList");
18
+ const IsSalePaymentInputList_1 = require("../../validators/IsSalePaymentInputList");
19
19
  /**
20
20
  * POST /wizard/accessory-sales — cierra la venta de mostrador, sin cliente.
21
21
  * `amountCents` es lo cobrado en caja: iguala la suma del catálogo y la de `payments`.
@@ -54,6 +54,6 @@ __decorate([
54
54
  __decorate([
55
55
  (0, class_transformer_1.Expose)(),
56
56
  (0, class_validator_1.IsOptional)(),
57
- (0, IsSalePaymentList_1.IsSalePaymentList)(),
57
+ (0, IsSalePaymentInputList_1.IsSalePaymentInputList)(),
58
58
  __metadata("design:type", Array)
59
59
  ], CreateAccessorySaleRequest.prototype, "payments", void 0);
@@ -16,6 +16,6 @@ export declare class DownPaymentRequest {
16
16
  amountCents: number;
17
17
  /** @deprecated Usa el comprobante de cada elemento de `payments`. */
18
18
  detail?: SalePaymentDetail;
19
- /** Pagos del cobro (1 a 3); si viene, manda sobre `method` y `detail`. */
19
+ /** Pagos del cobro; si viene, manda sobre `method` y `detail`. */
20
20
  payments?: SalePayment[];
21
21
  }
@@ -14,7 +14,7 @@ const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
15
  const SalePaymentMethodEnum_1 = require("../../enums/SalePaymentMethodEnum");
16
16
  const SalePaymentDetail_1 = require("../SalePaymentDetail");
17
- const IsSalePaymentList_1 = require("../../validators/IsSalePaymentList");
17
+ const IsSalePaymentInputList_1 = require("../../validators/IsSalePaymentInputList");
18
18
  /**
19
19
  * POST /wizard/sessions/:id/down-payment — cobro del ENGANCHE de la venta a crédito (paso 07,
20
20
  * pista SOFOM). Endpoint propio, separado del cobro de contado (`/payment`): acá la regla dura es
@@ -49,6 +49,6 @@ __decorate([
49
49
  __decorate([
50
50
  (0, class_transformer_1.Expose)(),
51
51
  (0, class_validator_1.IsOptional)(),
52
- (0, IsSalePaymentList_1.IsSalePaymentList)(),
52
+ (0, IsSalePaymentInputList_1.IsSalePaymentInputList)(),
53
53
  __metadata("design:type", Array)
54
54
  ], DownPaymentRequest.prototype, "payments", void 0);
@@ -12,6 +12,6 @@ export declare class RegisterPaymentRequest {
12
12
  amountCents: number;
13
13
  /** @deprecated Usa el comprobante de cada elemento de `payments`. */
14
14
  detail?: SalePaymentDetail;
15
- /** Pagos del cobro (1 a 3); si viene, manda sobre `method` y `detail`. */
15
+ /** Pagos del cobro; si viene, manda sobre `method` y `detail`. */
16
16
  payments?: SalePayment[];
17
17
  }
@@ -14,7 +14,7 @@ const class_transformer_1 = require("class-transformer");
14
14
  const class_validator_1 = require("class-validator");
15
15
  const SalePaymentMethodEnum_1 = require("../../enums/SalePaymentMethodEnum");
16
16
  const SalePaymentDetail_1 = require("../SalePaymentDetail");
17
- const IsSalePaymentList_1 = require("../../validators/IsSalePaymentList");
17
+ const IsSalePaymentInputList_1 = require("../../validators/IsSalePaymentInputList");
18
18
  /**
19
19
  * POST /wizard/sessions/:id/payment — registra el cobro de contado (idempotente por sesión). Regla
20
20
  * dura: `amountCents == cashPrice` de la reserva. `POST /payment/folio` genera el folio server-side
@@ -45,6 +45,6 @@ __decorate([
45
45
  __decorate([
46
46
  (0, class_transformer_1.Expose)(),
47
47
  (0, class_validator_1.IsOptional)(),
48
- (0, IsSalePaymentList_1.IsSalePaymentList)(),
48
+ (0, IsSalePaymentInputList_1.IsSalePaymentInputList)(),
49
49
  __metadata("design:type", Array)
50
50
  ], RegisterPaymentRequest.prototype, "payments", void 0);
@@ -41,6 +41,8 @@ export * from './dtos/WizardWelcome';
41
41
  export * from './dtos/WizardCreditPromotionBonus';
42
42
  export * from './dtos/SalePaymentDetail';
43
43
  export * from './dtos/SalePayment';
44
+ export * from './dtos/StoredSalePayment';
45
+ export * from './validators/IsSalePaymentInputList';
44
46
  export * from './validators/IsSalePaymentList';
45
47
  export * from './validators/OnlyForPaymentMethodConstraint';
46
48
  export * from './validators/PaymentsHaveSingleUseMethodsConstraint';
@@ -61,6 +61,8 @@ __exportStar(require("./dtos/WizardWelcome"), exports);
61
61
  __exportStar(require("./dtos/WizardCreditPromotionBonus"), exports);
62
62
  __exportStar(require("./dtos/SalePaymentDetail"), exports);
63
63
  __exportStar(require("./dtos/SalePayment"), exports);
64
+ __exportStar(require("./dtos/StoredSalePayment"), exports);
65
+ __exportStar(require("./validators/IsSalePaymentInputList"), exports);
64
66
  __exportStar(require("./validators/IsSalePaymentList"), exports);
65
67
  __exportStar(require("./validators/OnlyForPaymentMethodConstraint"), exports);
66
68
  __exportStar(require("./validators/PaymentsHaveSingleUseMethodsConstraint"), exports);
@@ -0,0 +1,2 @@
1
+ /** Forma de `payments` en un request: arreglo de pagos bien tipados. Las reglas de negocio las valida el dominio. */
2
+ export declare function IsSalePaymentInputList(): PropertyDecorator;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IsSalePaymentInputList = IsSalePaymentInputList;
4
+ const class_transformer_1 = require("class-transformer");
5
+ const class_validator_1 = require("class-validator");
6
+ const SalePayment_1 = require("../dtos/SalePayment");
7
+ /** Forma de `payments` en un request: arreglo de pagos bien tipados. Las reglas de negocio las valida el dominio. */
8
+ function IsSalePaymentInputList() {
9
+ const decorators = [(0, class_validator_1.IsArray)(), (0, class_validator_1.ValidateNested)({ each: true }), (0, class_transformer_1.Type)(() => SalePayment_1.SalePayment)];
10
+ return (target, propertyKey) => decorators.forEach((decorate) => decorate(target, propertyKey));
11
+ }
@@ -1,2 +1,2 @@
1
- /** Reglas de `payments`: 1 a 3 pagos válidos, efectivo y SPEI una vez, y la suma igual a `amountCents`. */
1
+ /** Reglas de `payments` ya registrados (cobro de la sesión): 1 a 3 pagos válidos, efectivo y SPEI una vez, y la suma igual a `amountCents`. */
2
2
  export declare function IsSalePaymentList(): PropertyDecorator;
@@ -4,17 +4,17 @@ exports.IsSalePaymentList = IsSalePaymentList;
4
4
  const class_transformer_1 = require("class-transformer");
5
5
  const class_validator_1 = require("class-validator");
6
6
  const retailWizardValidation_1 = require("../constants/retailWizardValidation");
7
- const SalePayment_1 = require("../dtos/SalePayment");
7
+ const StoredSalePayment_1 = require("../dtos/StoredSalePayment");
8
8
  const PaymentsHaveSingleUseMethodsConstraint_1 = require("./PaymentsHaveSingleUseMethodsConstraint");
9
9
  const PaymentsMatchAmountCentsConstraint_1 = require("./PaymentsMatchAmountCentsConstraint");
10
- /** Reglas de `payments`: 1 a 3 pagos válidos, efectivo y SPEI una vez, y la suma igual a `amountCents`. */
10
+ /** Reglas de `payments` ya registrados (cobro de la sesión): 1 a 3 pagos válidos, efectivo y SPEI una vez, y la suma igual a `amountCents`. */
11
11
  function IsSalePaymentList() {
12
12
  const decorators = [
13
13
  (0, class_validator_1.IsArray)(),
14
14
  (0, class_validator_1.ArrayMinSize)(1),
15
15
  (0, class_validator_1.ArrayMaxSize)(retailWizardValidation_1.MAX_SALE_PAYMENTS),
16
16
  (0, class_validator_1.ValidateNested)({ each: true }),
17
- (0, class_transformer_1.Type)(() => SalePayment_1.SalePayment),
17
+ (0, class_transformer_1.Type)(() => StoredSalePayment_1.StoredSalePayment),
18
18
  (0, class_validator_1.Validate)(PaymentsHaveSingleUseMethodsConstraint_1.PaymentsHaveSingleUseMethodsConstraint),
19
19
  (0, class_validator_1.Validate)(PaymentsMatchAmountCentsConstraint_1.PaymentsMatchAmountCentsConstraint),
20
20
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.636.0",
3
+ "version": "3.638.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -0,0 +1,11 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsEmail } from 'class-validator';
3
+
4
+ /**
5
+ * Request interno (api-invoker) para buscar qué directorios tienen un correo.
6
+ */
7
+ export class EmailOwnersByEmailRequest {
8
+ @Expose()
9
+ @IsEmail()
10
+ email!: string;
11
+ }
@@ -24,3 +24,4 @@ export * from './dtos/internal/EmailsByDirectoryRequest';
24
24
  export * from './dtos/internal/EmailsByDirectoryResponse';
25
25
  export * from './dtos/internal/EmailStartByDirectoryRequest';
26
26
  export * from './dtos/internal/EmailStartByDirectoryResponse';
27
+ export * from './dtos/internal/EmailOwnersByEmailRequest';
@@ -1,4 +1,5 @@
1
1
  import type { CommissionPlanStatusEnum } from '../enums/CommissionPlanStatusEnum';
2
+ import type { CommissionRuleStatusEnum } from '../enums/CommissionRuleStatusEnum';
2
3
  import type { CommissionPayoutStatusEnum } from '../enums/CommissionPayoutStatusEnum';
3
4
  import type {
4
5
  CommissionAddOn,
@@ -295,12 +296,36 @@ export interface RuleActionResponse {
295
296
  snapshotId: string;
296
297
  }
297
298
 
299
+ /** Un campo de la regla que cambió de una versión a la siguiente, con su valor antes y después. */
300
+ export type CommissionRuleChange =
301
+ | { field: 'name'; before: string; after: string }
302
+ | { field: 'description'; before: string | null; after: string | null }
303
+ | { field: 'levers'; before: CommissionRuleLevers; after: CommissionRuleLevers }
304
+ | { field: 'scope'; before: CommissionRuleScope; after: CommissionRuleScope }
305
+ | { field: 'condition'; before: CommissionRuleCondition | null; after: CommissionRuleCondition | null }
306
+ | { field: 'effectiveFrom'; before: string; after: string }
307
+ | { field: 'effectiveTo'; before: string | null; after: string | null }
308
+ | { field: 'priority'; before: number; after: number }
309
+ | { field: 'replacesOthers'; before: boolean; after: boolean }
310
+ | { field: 'countBy'; before: CommissionCountByEnum; after: CommissionCountByEnum }
311
+ | { field: 'payTiming'; before: CommissionPayTimingEnum; after: CommissionPayTimingEnum }
312
+ | { field: 'onSaleAdvanceBps'; before: number | null; after: number | null };
313
+
298
314
  /** Un evento del historial de una regla. */
299
315
  export interface CommissionRuleEvent {
300
316
  at: string;
301
317
  action: string;
302
318
  performedBy: string;
303
319
  version: number | null;
320
+ /**
321
+ * Solo en ediciones: lo que cambió respecto a la versión anterior; vacío si no cambió ningún campo.
322
+ * Ausente si no hay versión anterior con qué comparar, y en motores anteriores.
323
+ */
324
+ changes?: CommissionRuleChange[];
325
+ /** Junto a `changes`: si la versión editada cuenta piezas o ventas, para leer sus palancas y su condición. */
326
+ countBy?: CommissionCountByEnum;
327
+ /** El estado que tenía la regla y el que le dejó el evento; `null` si no lo cambió o no se sabe. Ausente en motores anteriores. */
328
+ statusChange?: { from: CommissionRuleStatusEnum; to: CommissionRuleStatusEnum } | null;
304
329
  }
305
330
 
306
331
  /** `GET /backoffice/commissions/rules/{ruleId}/history` — del más nuevo al más viejo. */
@@ -1,18 +1,13 @@
1
1
  import { Expose } from 'class-transformer';
2
- import { IsBoolean, IsEnum, IsInt, Matches, Min, Validate, ValidateIf } from 'class-validator';
3
- import {
4
- RETAIL_CARD_LAST4_PATTERN,
5
- RETAIL_CLABE_PATTERN,
6
- RETAIL_SALE_ID_TEXT_PATTERN,
7
- RETAIL_SPEI_TRACKING_KEY_PATTERN,
8
- } from '../../retailIntegration/constants/retailIntegrationLimits';
2
+ import { IsBoolean, IsEnum, IsInt, IsString, ValidateIf } from 'class-validator';
9
3
  import { SalePaymentMethodEnum } from '../enums/SalePaymentMethodEnum';
10
- import { OnlyForPaymentMethodConstraint } from '../validators/OnlyForPaymentMethodConstraint';
11
4
 
12
- const { CASH, CARD, WIRE } = SalePaymentMethodEnum;
13
5
  const hasValue = (field: keyof SalePayment) => (o: SalePayment) => o[field] != null;
14
6
 
15
- /** Un pago del cobro. El comprobante es opcional: si viene se valida y solo en su medio; si no, `null` o ausente. */
7
+ /**
8
+ * Un pago del cobro tal como llega en un request: solo la forma. Tope, uso único, suma, monto
9
+ * positivo y formato del comprobante los valida el dominio con su code.
10
+ */
16
11
  export class SalePayment {
17
12
  @Expose()
18
13
  @IsEnum(SalePaymentMethodEnum)
@@ -20,36 +15,30 @@ export class SalePayment {
20
15
 
21
16
  @Expose()
22
17
  @IsInt()
23
- @Min(1)
24
18
  amountCents!: number;
25
19
 
26
20
  @Expose()
27
21
  @ValidateIf(hasValue('cashConfirmedInRegister'))
28
22
  @IsBoolean()
29
- @Validate(OnlyForPaymentMethodConstraint, [CASH])
30
23
  cashConfirmedInRegister?: boolean | null;
31
24
 
32
25
  @Expose()
33
26
  @ValidateIf(hasValue('cardLast4'))
34
- @Matches(RETAIL_CARD_LAST4_PATTERN)
35
- @Validate(OnlyForPaymentMethodConstraint, [CARD])
27
+ @IsString()
36
28
  cardLast4?: string | null;
37
29
 
38
30
  @Expose()
39
31
  @ValidateIf(hasValue('authCode'))
40
- @Matches(RETAIL_SALE_ID_TEXT_PATTERN)
41
- @Validate(OnlyForPaymentMethodConstraint, [CARD])
32
+ @IsString()
42
33
  authCode?: string | null;
43
34
 
44
35
  @Expose()
45
36
  @ValidateIf(hasValue('speiTrackingKey'))
46
- @Matches(RETAIL_SPEI_TRACKING_KEY_PATTERN)
47
- @Validate(OnlyForPaymentMethodConstraint, [WIRE])
37
+ @IsString()
48
38
  speiTrackingKey?: string | null;
49
39
 
50
40
  @Expose()
51
41
  @ValidateIf(hasValue('senderClabe'))
52
- @Matches(RETAIL_CLABE_PATTERN)
53
- @Validate(OnlyForPaymentMethodConstraint, [WIRE])
42
+ @IsString()
54
43
  senderClabe?: string | null;
55
44
  }
@@ -0,0 +1,46 @@
1
+ import { IsBoolean, IsInt, IsString, Min, Matches, Validate } from 'class-validator';
2
+ import {
3
+ RETAIL_CARD_LAST4_PATTERN,
4
+ RETAIL_CLABE_PATTERN,
5
+ RETAIL_SALE_ID_TEXT_PATTERN,
6
+ RETAIL_SPEI_TRACKING_KEY_PATTERN,
7
+ } from '../../retailIntegration/constants/retailIntegrationLimits';
8
+ import { SalePaymentMethodEnum } from '../enums/SalePaymentMethodEnum';
9
+ import { OnlyForPaymentMethodConstraint } from '../validators/OnlyForPaymentMethodConstraint';
10
+ import { SalePayment } from './SalePayment';
11
+
12
+ const { CASH, CARD, WIRE } = SalePaymentMethodEnum;
13
+
14
+ /**
15
+ * Pago ya registrado (cobro de la sesión): monto positivo y comprobante con formato, solo en su medio.
16
+ * Repite las reglas de forma porque class-validator descarta las del padre en la propiedad que se redeclara.
17
+ */
18
+ export class StoredSalePayment extends SalePayment {
19
+ @IsInt()
20
+ @Min(1)
21
+ declare amountCents: number;
22
+
23
+ @IsBoolean()
24
+ @Validate(OnlyForPaymentMethodConstraint, [CASH])
25
+ declare cashConfirmedInRegister?: boolean | null;
26
+
27
+ @IsString()
28
+ @Matches(RETAIL_CARD_LAST4_PATTERN)
29
+ @Validate(OnlyForPaymentMethodConstraint, [CARD])
30
+ declare cardLast4?: string | null;
31
+
32
+ @IsString()
33
+ @Matches(RETAIL_SALE_ID_TEXT_PATTERN)
34
+ @Validate(OnlyForPaymentMethodConstraint, [CARD])
35
+ declare authCode?: string | null;
36
+
37
+ @IsString()
38
+ @Matches(RETAIL_SPEI_TRACKING_KEY_PATTERN)
39
+ @Validate(OnlyForPaymentMethodConstraint, [WIRE])
40
+ declare speiTrackingKey?: string | null;
41
+
42
+ @IsString()
43
+ @Matches(RETAIL_CLABE_PATTERN)
44
+ @Validate(OnlyForPaymentMethodConstraint, [WIRE])
45
+ declare senderClabe?: string | null;
46
+ }
@@ -14,7 +14,7 @@ import { SalePaymentMethodEnum } from '../../enums/SalePaymentMethodEnum';
14
14
  import { SalePaymentDetail } from '../SalePaymentDetail';
15
15
  import { AccessorySaleLine } from '../AccessorySaleLine';
16
16
  import { SalePayment } from '../SalePayment';
17
- import { IsSalePaymentList } from '../../validators/IsSalePaymentList';
17
+ import { IsSalePaymentInputList } from '../../validators/IsSalePaymentInputList';
18
18
 
19
19
  /**
20
20
  * POST /wizard/accessory-sales — cierra la venta de mostrador, sin cliente.
@@ -47,9 +47,9 @@ export class CreateAccessorySaleRequest {
47
47
  @Type(() => SalePaymentDetail)
48
48
  paymentDetail?: SalePaymentDetail;
49
49
 
50
- /** Pagos del cobro (1 a 3); si viene, manda sobre `paymentMethod` y `paymentDetail`. */
50
+ /** Pagos del cobro; si viene, manda sobre `paymentMethod` y `paymentDetail`. */
51
51
  @Expose()
52
52
  @IsOptional()
53
- @IsSalePaymentList()
53
+ @IsSalePaymentInputList()
54
54
  payments?: SalePayment[];
55
55
  }
@@ -3,7 +3,7 @@ import { IsEnum, IsInt, IsOptional, Min, ValidateIf, ValidateNested } from 'clas
3
3
  import { SalePaymentMethodEnum } from '../../enums/SalePaymentMethodEnum';
4
4
  import { SalePaymentDetail } from '../SalePaymentDetail';
5
5
  import { SalePayment } from '../SalePayment';
6
- import { IsSalePaymentList } from '../../validators/IsSalePaymentList';
6
+ import { IsSalePaymentInputList } from '../../validators/IsSalePaymentInputList';
7
7
 
8
8
  /**
9
9
  * POST /wizard/sessions/:id/down-payment — cobro del ENGANCHE de la venta a crédito (paso 07,
@@ -33,9 +33,9 @@ export class DownPaymentRequest {
33
33
  @ValidateNested()
34
34
  detail?: SalePaymentDetail;
35
35
 
36
- /** Pagos del cobro (1 a 3); si viene, manda sobre `method` y `detail`. */
36
+ /** Pagos del cobro; si viene, manda sobre `method` y `detail`. */
37
37
  @Expose()
38
38
  @IsOptional()
39
- @IsSalePaymentList()
39
+ @IsSalePaymentInputList()
40
40
  payments?: SalePayment[];
41
41
  }
@@ -3,7 +3,7 @@ import { IsEnum, IsInt, IsOptional, ValidateIf, ValidateNested, Min } from 'clas
3
3
  import { SalePaymentMethodEnum } from '../../enums/SalePaymentMethodEnum';
4
4
  import { SalePaymentDetail } from '../SalePaymentDetail';
5
5
  import { SalePayment } from '../SalePayment';
6
- import { IsSalePaymentList } from '../../validators/IsSalePaymentList';
6
+ import { IsSalePaymentInputList } from '../../validators/IsSalePaymentInputList';
7
7
 
8
8
  /**
9
9
  * POST /wizard/sessions/:id/payment — registra el cobro de contado (idempotente por sesión). Regla
@@ -29,9 +29,9 @@ export class RegisterPaymentRequest {
29
29
  @ValidateNested()
30
30
  detail?: SalePaymentDetail;
31
31
 
32
- /** Pagos del cobro (1 a 3); si viene, manda sobre `method` y `detail`. */
32
+ /** Pagos del cobro; si viene, manda sobre `method` y `detail`. */
33
33
  @Expose()
34
34
  @IsOptional()
35
- @IsSalePaymentList()
35
+ @IsSalePaymentInputList()
36
36
  payments?: SalePayment[];
37
37
  }
@@ -46,6 +46,8 @@ export * from './dtos/WizardWelcome';
46
46
  export * from './dtos/WizardCreditPromotionBonus';
47
47
  export * from './dtos/SalePaymentDetail';
48
48
  export * from './dtos/SalePayment';
49
+ export * from './dtos/StoredSalePayment';
50
+ export * from './validators/IsSalePaymentInputList';
49
51
  export * from './validators/IsSalePaymentList';
50
52
  export * from './validators/OnlyForPaymentMethodConstraint';
51
53
  export * from './validators/PaymentsHaveSingleUseMethodsConstraint';
@@ -0,0 +1,9 @@
1
+ import { Type } from 'class-transformer';
2
+ import { IsArray, ValidateNested } from 'class-validator';
3
+ import { SalePayment } from '../dtos/SalePayment';
4
+
5
+ /** Forma de `payments` en un request: arreglo de pagos bien tipados. Las reglas de negocio las valida el dominio. */
6
+ export function IsSalePaymentInputList(): PropertyDecorator {
7
+ const decorators: PropertyDecorator[] = [IsArray(), ValidateNested({ each: true }), Type(() => SalePayment)];
8
+ return (target, propertyKey) => decorators.forEach((decorate) => decorate(target, propertyKey));
9
+ }
@@ -1,18 +1,18 @@
1
1
  import { Type } from 'class-transformer';
2
2
  import { ArrayMaxSize, ArrayMinSize, IsArray, Validate, ValidateNested } from 'class-validator';
3
3
  import { MAX_SALE_PAYMENTS } from '../constants/retailWizardValidation';
4
- import { SalePayment } from '../dtos/SalePayment';
4
+ import { StoredSalePayment } from '../dtos/StoredSalePayment';
5
5
  import { PaymentsHaveSingleUseMethodsConstraint } from './PaymentsHaveSingleUseMethodsConstraint';
6
6
  import { PaymentsMatchAmountCentsConstraint } from './PaymentsMatchAmountCentsConstraint';
7
7
 
8
- /** Reglas de `payments`: 1 a 3 pagos válidos, efectivo y SPEI una vez, y la suma igual a `amountCents`. */
8
+ /** Reglas de `payments` ya registrados (cobro de la sesión): 1 a 3 pagos válidos, efectivo y SPEI una vez, y la suma igual a `amountCents`. */
9
9
  export function IsSalePaymentList(): PropertyDecorator {
10
10
  const decorators: PropertyDecorator[] = [
11
11
  IsArray(),
12
12
  ArrayMinSize(1),
13
13
  ArrayMaxSize(MAX_SALE_PAYMENTS),
14
14
  ValidateNested({ each: true }),
15
- Type(() => SalePayment),
15
+ Type(() => StoredSalePayment),
16
16
  Validate(PaymentsHaveSingleUseMethodsConstraint),
17
17
  Validate(PaymentsMatchAmountCentsConstraint),
18
18
  ];