@fiado/type-kit 3.539.0 → 3.540.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 (43) hide show
  1. package/_test_/unit/retailCustomer/ensureCustomerByPhoneRequest.test.ts +30 -0
  2. package/_test_/unit/retailWizard/accessorySaleRequests.test.ts +108 -0
  3. package/_test_/unit/retailWizard/cancelSaleConditions.test.ts +2 -1
  4. package/_test_/unit/retailWizard/portalCancelSaleRequest.test.ts +34 -0
  5. package/bin/retailCustomer/dtos/requests/EnsureCustomerByPhoneRequest.d.ts +9 -0
  6. package/bin/retailCustomer/dtos/requests/EnsureCustomerByPhoneRequest.js +34 -0
  7. package/bin/retailCustomer/dtos/responses/EnsureCustomerByPhoneResponse.d.ts +5 -0
  8. package/bin/retailCustomer/dtos/responses/EnsureCustomerByPhoneResponse.js +2 -0
  9. package/bin/retailCustomer/index.d.ts +2 -0
  10. package/bin/retailCustomer/index.js +2 -0
  11. package/bin/retailWizard/dtos/AccessorySaleLine.d.ts +7 -0
  12. package/bin/retailWizard/dtos/AccessorySaleLine.js +38 -0
  13. package/bin/retailWizard/dtos/Sale.d.ts +5 -1
  14. package/bin/retailWizard/dtos/requests/CreateAccessorySaleRequest.d.ts +18 -0
  15. package/bin/retailWizard/dtos/requests/CreateAccessorySaleRequest.js +69 -0
  16. package/bin/retailWizard/dtos/requests/PortalCancelSaleRequest.d.ts +12 -0
  17. package/bin/retailWizard/dtos/requests/PortalCancelSaleRequest.js +43 -0
  18. package/bin/retailWizard/dtos/requests/SendAccessoryOtpRequest.d.ts +4 -0
  19. package/bin/retailWizard/dtos/requests/SendAccessoryOtpRequest.js +25 -0
  20. package/bin/retailWizard/dtos/requests/VerifyAccessoryOtpRequest.d.ts +4 -0
  21. package/bin/retailWizard/dtos/requests/VerifyAccessoryOtpRequest.js +24 -0
  22. package/bin/retailWizard/dtos/responses/AccessoryOtpChallenge.d.ts +7 -0
  23. package/bin/retailWizard/dtos/responses/AccessoryOtpChallenge.js +2 -0
  24. package/bin/retailWizard/dtos/responses/VerifyAccessoryOtpResponse.d.ts +7 -0
  25. package/bin/retailWizard/dtos/responses/VerifyAccessoryOtpResponse.js +2 -0
  26. package/bin/retailWizard/enums/SaleChannelEnum.d.ts +5 -0
  27. package/bin/retailWizard/enums/SaleChannelEnum.js +9 -0
  28. package/bin/retailWizard/index.d.ts +8 -0
  29. package/bin/retailWizard/index.js +8 -0
  30. package/package.json +1 -1
  31. package/src/retailCustomer/dtos/requests/EnsureCustomerByPhoneRequest.ts +20 -0
  32. package/src/retailCustomer/dtos/responses/EnsureCustomerByPhoneResponse.ts +6 -0
  33. package/src/retailCustomer/index.ts +2 -0
  34. package/src/retailWizard/dtos/AccessorySaleLine.ts +23 -0
  35. package/src/retailWizard/dtos/Sale.ts +5 -1
  36. package/src/retailWizard/dtos/requests/CreateAccessorySaleRequest.ts +64 -0
  37. package/src/retailWizard/dtos/requests/PortalCancelSaleRequest.ts +29 -0
  38. package/src/retailWizard/dtos/requests/SendAccessoryOtpRequest.ts +11 -0
  39. package/src/retailWizard/dtos/requests/VerifyAccessoryOtpRequest.ts +10 -0
  40. package/src/retailWizard/dtos/responses/AccessoryOtpChallenge.ts +7 -0
  41. package/src/retailWizard/dtos/responses/VerifyAccessoryOtpResponse.ts +7 -0
  42. package/src/retailWizard/enums/SaleChannelEnum.ts +5 -0
  43. package/src/retailWizard/index.ts +8 -0
@@ -0,0 +1,30 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validateSync } from 'class-validator';
4
+ import { EnsureCustomerByPhoneRequest } from '../../../src/retailCustomer/dtos/requests/EnsureCustomerByPhoneRequest';
5
+ import * as RetailCustomer from '../../../src/retailCustomer';
6
+
7
+ function errorsOf(payload: Record<string, unknown>): string[] {
8
+ const dto = plainToInstance(EnsureCustomerByPhoneRequest, payload, { excludeExtraneousValues: true });
9
+ return validateSync(dto).map((e) => e.property);
10
+ }
11
+
12
+ describe('EnsureCustomerByPhoneRequest', () => {
13
+ it('acepta celular de 10 dígitos y tienda', () => {
14
+ expect(errorsOf({ phone: '5512345678', originStoreId: 'store-1' })).toEqual([]);
15
+ });
16
+
17
+ it('rechaza un celular con lada o separadores', () => {
18
+ expect(errorsOf({ phone: '+525512345678', originStoreId: 'store-1' })).toContain('phone');
19
+ expect(errorsOf({ phone: '55-1234-5678', originStoreId: 'store-1' })).toContain('phone');
20
+ });
21
+
22
+ it('exige la tienda de alta', () => {
23
+ expect(errorsOf({ phone: '5512345678' })).toContain('originStoreId');
24
+ expect(errorsOf({ phone: '5512345678', originStoreId: '' })).toContain('originStoreId');
25
+ });
26
+
27
+ it('se exporta en el barrel', () => {
28
+ expect(RetailCustomer.EnsureCustomerByPhoneRequest).toBe(EnsureCustomerByPhoneRequest);
29
+ });
30
+ });
@@ -0,0 +1,108 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validateSync } from 'class-validator';
4
+ import { SendAccessoryOtpRequest } from '../../../src/retailWizard/dtos/requests/SendAccessoryOtpRequest';
5
+ import { VerifyAccessoryOtpRequest } from '../../../src/retailWizard/dtos/requests/VerifyAccessoryOtpRequest';
6
+ import { CreateAccessorySaleRequest } from '../../../src/retailWizard/dtos/requests/CreateAccessorySaleRequest';
7
+ import { SaleChannelEnum } from '../../../src/retailWizard/enums/SaleChannelEnum';
8
+ import { SalePaymentMethodEnum } from '../../../src/retailWizard/enums/SalePaymentMethodEnum';
9
+ import * as RetailWizard from '../../../src/retailWizard';
10
+
11
+ function errorsOf<T extends object>(cls: new () => T, payload: Record<string, unknown>): string[] {
12
+ const dto = plainToInstance(cls, payload, { excludeExtraneousValues: true });
13
+ return validateSync(dto).map((e) => e.property);
14
+ }
15
+
16
+ const validSale = {
17
+ otpChallengeId: 'chl-1',
18
+ lines: [{ sku: 'ACC-1', qty: 2 }],
19
+ paymentMethod: SalePaymentMethodEnum.CASH,
20
+ amountCents: 39800,
21
+ paymentDetail: { cashConfirmedInRegister: true },
22
+ privacyNoticeAccepted: true,
23
+ privacyNoticeVersion: 'AVISO-2026-10',
24
+ };
25
+
26
+ describe('SendAccessoryOtpRequest', () => {
27
+ it('acepta un celular de 10 dígitos', () => {
28
+ expect(errorsOf(SendAccessoryOtpRequest, { phone: '5512345678' })).toEqual([]);
29
+ });
30
+
31
+ it.each(['+525512345678', '55 1234 5678', '551234567', ''])('rechaza %p', (phone) => {
32
+ expect(errorsOf(SendAccessoryOtpRequest, { phone })).toContain('phone');
33
+ });
34
+ });
35
+
36
+ describe('VerifyAccessoryOtpRequest', () => {
37
+ it('acepta el código de 4 dígitos de messages-business', () => {
38
+ expect(errorsOf(VerifyAccessoryOtpRequest, { code: '1234' })).toEqual([]);
39
+ });
40
+
41
+ it('rechaza un código de 3 dígitos', () => {
42
+ expect(errorsOf(VerifyAccessoryOtpRequest, { code: '123' })).toContain('code');
43
+ });
44
+
45
+ it('rechaza un código ausente', () => {
46
+ expect(errorsOf(VerifyAccessoryOtpRequest, {})).toContain('code');
47
+ });
48
+ });
49
+
50
+ describe('CreateAccessorySaleRequest', () => {
51
+ it('acepta una venta válida', () => {
52
+ expect(errorsOf(CreateAccessorySaleRequest, validSale)).toEqual([]);
53
+ });
54
+
55
+ it('acepta piezas con identificadores', () => {
56
+ const payload = { ...validSale, lines: [{ sku: 'ACC-1', qty: 1, identifiers: ['SER-1'] }] };
57
+ expect(errorsOf(CreateAccessorySaleRequest, payload)).toEqual([]);
58
+ });
59
+
60
+ it('rechaza un carrito vacío', () => {
61
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, lines: [] })).toContain('lines');
62
+ });
63
+
64
+ it('rechaza una línea con qty 0', () => {
65
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, lines: [{ sku: 'ACC-1', qty: 0 }] })).toContain('lines');
66
+ });
67
+
68
+ it('rechaza un medio de pago fuera del enum', () => {
69
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, paymentMethod: 'WALLET' })).toContain('paymentMethod');
70
+ });
71
+
72
+ it('rechaza un monto negativo o decimal', () => {
73
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, amountCents: -1 })).toContain('amountCents');
74
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, amountCents: 10.5 })).toContain('amountCents');
75
+ });
76
+
77
+ it('exige el comprobante del cobro', () => {
78
+ const { paymentDetail: _omit, ...rest } = validSale;
79
+ expect(errorsOf(CreateAccessorySaleRequest, rest)).toContain('paymentDetail');
80
+ });
81
+
82
+ it('exige la versión del aviso de privacidad', () => {
83
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, privacyNoticeVersion: '' })).toContain('privacyNoticeVersion');
84
+ });
85
+
86
+ it('privacyNoticeAccepted no booleano → error de formato', () => {
87
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, privacyNoticeAccepted: 'si' })).toContain('privacyNoticeAccepted');
88
+ });
89
+
90
+ it('el medio WIRE (SPEI) es válido', () => {
91
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, paymentMethod: SalePaymentMethodEnum.WIRE })).toEqual([]);
92
+ });
93
+
94
+ it('exige el reto OTP', () => {
95
+ expect(errorsOf(CreateAccessorySaleRequest, { ...validSale, otpChallengeId: '' })).toContain('otpChallengeId');
96
+ });
97
+ });
98
+
99
+ describe('barrel retailWizard', () => {
100
+ it('exporta los contratos del cobro de accesorios', () => {
101
+ expect(RetailWizard.SendAccessoryOtpRequest).toBeDefined();
102
+ expect(RetailWizard.VerifyAccessoryOtpRequest).toBeDefined();
103
+ expect(RetailWizard.CreateAccessorySaleRequest).toBeDefined();
104
+ expect(RetailWizard.AccessorySaleLine).toBeDefined();
105
+ expect(RetailWizard.SaleChannelEnum.ACCESSORY_COUNTER).toBe('ACCESSORY_COUNTER');
106
+ expect(SaleChannelEnum.WIZARD).toBe('WIZARD');
107
+ });
108
+ });
@@ -2,7 +2,7 @@ import 'reflect-metadata';
2
2
  import { plainToInstance, type ClassConstructor } from 'class-transformer';
3
3
  import { validateSync, type ValidationError } from 'class-validator';
4
4
  import { ReturnPieceCondition } from '../../../src/retailCatalog';
5
- import { BackofficeCancelSaleRequest, CancelSaleRequest } from '../../../src/retailWizard';
5
+ import { BackofficeCancelSaleRequest, CancelSaleRequest, PortalCancelSaleRequest } from '../../../src/retailWizard';
6
6
 
7
7
  function paths(errors: ValidationError[], prefix = ''): string[] {
8
8
  return errors.flatMap((e) => {
@@ -23,6 +23,7 @@ const conditions = [
23
23
  describe.each([
24
24
  ['CancelSaleRequest', CancelSaleRequest, { reason: 'Cliente se arrepintió' }],
25
25
  ['BackofficeCancelSaleRequest', BackofficeCancelSaleRequest, { reason: 'Cliente se arrepintió' }],
26
+ ['PortalCancelSaleRequest', PortalCancelSaleRequest, { reason: 'Cliente se arrepintió' }],
26
27
  ] as const)('%s con condición por pieza', (_name, cls, base) => {
27
28
  it('sin returnConditions sigue validando', () => expect(errorsOf(cls, base)).toEqual([]));
28
29
  it('acepta condiciones y las hidrata aun con excludeExtraneousValues', () => {
@@ -0,0 +1,34 @@
1
+ import 'reflect-metadata';
2
+ import { plainToInstance } from 'class-transformer';
3
+ import { validateSync } from 'class-validator';
4
+ import { PortalCancelSaleRequest } from '../../../src/retailWizard';
5
+
6
+ function errorsOf(payload: object): string[] {
7
+ const dto = plainToInstance(PortalCancelSaleRequest, payload, { excludeExtraneousValues: true });
8
+ return validateSync(dto).map((e) => e.property);
9
+ }
10
+
11
+ describe('PortalCancelSaleRequest', () => {
12
+ it('acepta motivo de 10 a 200 caracteres con el equipo confirmado', () => {
13
+ expect(errorsOf({ reason: 'Cliente se arrepintió', equipmentVerified: true })).toEqual([]);
14
+ });
15
+
16
+ it('exige el motivo con la misma longitud que la cancelación del Admin VL', () => {
17
+ expect(errorsOf({})).toContain('reason');
18
+ expect(errorsOf({ reason: 'corto' })).toContain('reason');
19
+ expect(errorsOf({ reason: 'x'.repeat(201) })).toContain('reason');
20
+ });
21
+
22
+ it('rechaza el string "false" como equipmentVerified', () => {
23
+ expect(errorsOf({ reason: 'Cliente se arrepintió', equipmentVerified: 'false' })).toContain('equipmentVerified');
24
+ });
25
+
26
+ it('no expone la excepción de cancelación tardía', () => {
27
+ const dto = plainToInstance(
28
+ PortalCancelSaleRequest,
29
+ { reason: 'Cliente se arrepintió', outOfWindowExceptionId: 'EXC-1' },
30
+ { excludeExtraneousValues: true },
31
+ );
32
+ expect(dto).not.toHaveProperty('outOfWindowExceptionId');
33
+ });
34
+ });
@@ -0,0 +1,9 @@
1
+ /**
2
+ * POST /private/customers/ensure-by-phone — da de alta al cliente solo con su celular verificado,
3
+ * o devuelve el que ya existe con ese número.
4
+ */
5
+ export declare class EnsureCustomerByPhoneRequest {
6
+ phone: string;
7
+ /** Tienda del primer contacto; no cambia si el cliente ya existía. */
8
+ originStoreId: string;
9
+ }
@@ -0,0 +1,34 @@
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.EnsureCustomerByPhoneRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const regex_1 = require("../../../helpers/constans/regex");
16
+ /**
17
+ * POST /private/customers/ensure-by-phone — da de alta al cliente solo con su celular verificado,
18
+ * o devuelve el que ya existe con ese número.
19
+ */
20
+ class EnsureCustomerByPhoneRequest {
21
+ }
22
+ exports.EnsureCustomerByPhoneRequest = EnsureCustomerByPhoneRequest;
23
+ __decorate([
24
+ (0, class_transformer_1.Expose)(),
25
+ (0, class_validator_1.IsString)(),
26
+ (0, class_validator_1.Matches)(regex_1.regexPhoneMx, { message: 'phone debe tener 10 dígitos' }),
27
+ __metadata("design:type", String)
28
+ ], EnsureCustomerByPhoneRequest.prototype, "phone", void 0);
29
+ __decorate([
30
+ (0, class_transformer_1.Expose)(),
31
+ (0, class_validator_1.IsString)(),
32
+ (0, class_validator_1.MinLength)(1),
33
+ __metadata("design:type", String)
34
+ ], EnsureCustomerByPhoneRequest.prototype, "originStoreId", void 0);
@@ -0,0 +1,5 @@
1
+ import { CustomerResponse } from './CustomerResponse';
2
+ /** Cliente resuelto por celular; `created` dice si esta llamada lo dio de alta. */
3
+ export interface EnsureCustomerByPhoneResponse extends CustomerResponse {
4
+ created: boolean;
5
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -19,11 +19,13 @@ export * from './dtos/requests/KycReviewRequest';
19
19
  export * from './dtos/requests/WelcomeAccreditationRequest';
20
20
  export * from './dtos/requests/WelcomeAccreditationResultRequest';
21
21
  export * from './dtos/requests/UpsertPromotionBonusRequest';
22
+ export * from './dtos/requests/EnsureCustomerByPhoneRequest';
22
23
  export * from './dtos/responses/CustomerResponse';
23
24
  export * from './dtos/responses/Customer360Response';
24
25
  export * from './dtos/responses/WelcomeBonusResponse';
25
26
  export * from './dtos/responses/WelcomeAccreditationResponse';
26
27
  export * from './dtos/responses/PromotionBonusEntryResponse';
28
+ export * from './dtos/responses/EnsureCustomerByPhoneResponse';
27
29
  export * from './events/CustomerCreatedV1';
28
30
  export * from './events/CustomerUpdatedV1';
29
31
  export * from './events/CustomerKycVerifiedV1';
@@ -38,12 +38,14 @@ __exportStar(require("./dtos/requests/KycReviewRequest"), exports);
38
38
  __exportStar(require("./dtos/requests/WelcomeAccreditationRequest"), exports);
39
39
  __exportStar(require("./dtos/requests/WelcomeAccreditationResultRequest"), exports);
40
40
  __exportStar(require("./dtos/requests/UpsertPromotionBonusRequest"), exports);
41
+ __exportStar(require("./dtos/requests/EnsureCustomerByPhoneRequest"), exports);
41
42
  // Response DTOs
42
43
  __exportStar(require("./dtos/responses/CustomerResponse"), exports);
43
44
  __exportStar(require("./dtos/responses/Customer360Response"), exports);
44
45
  __exportStar(require("./dtos/responses/WelcomeBonusResponse"), exports);
45
46
  __exportStar(require("./dtos/responses/WelcomeAccreditationResponse"), exports);
46
47
  __exportStar(require("./dtos/responses/PromotionBonusEntryResponse"), exports);
48
+ __exportStar(require("./dtos/responses/EnsureCustomerByPhoneResponse"), exports);
47
49
  // Contratos de eventos (PascalCase + sufijo V1)
48
50
  __exportStar(require("./events/CustomerCreatedV1"), exports);
49
51
  __exportStar(require("./events/CustomerUpdatedV1"), exports);
@@ -0,0 +1,7 @@
1
+ /** Línea del carrito de accesorios; el precio lo pone el catálogo, no el request. */
2
+ export declare class AccessorySaleLine {
3
+ sku: string;
4
+ qty: number;
5
+ /** Serie de cada pieza cuando el SKU se rastrea por pieza; ausente si se rastrea por cantidad. */
6
+ identifiers?: string[];
7
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AccessorySaleLine = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ /** Línea del carrito de accesorios; el precio lo pone el catálogo, no el request. */
16
+ class AccessorySaleLine {
17
+ }
18
+ exports.AccessorySaleLine = AccessorySaleLine;
19
+ __decorate([
20
+ (0, class_transformer_1.Expose)(),
21
+ (0, class_validator_1.IsString)(),
22
+ (0, class_validator_1.MinLength)(1),
23
+ __metadata("design:type", String)
24
+ ], AccessorySaleLine.prototype, "sku", void 0);
25
+ __decorate([
26
+ (0, class_transformer_1.Expose)(),
27
+ (0, class_validator_1.IsInt)(),
28
+ (0, class_validator_1.Min)(1),
29
+ __metadata("design:type", Number)
30
+ ], AccessorySaleLine.prototype, "qty", void 0);
31
+ __decorate([
32
+ (0, class_transformer_1.Expose)(),
33
+ (0, class_validator_1.IsOptional)(),
34
+ (0, class_validator_1.IsArray)(),
35
+ (0, class_validator_1.ArrayMaxSize)(100),
36
+ (0, class_validator_1.IsString)({ each: true }),
37
+ __metadata("design:type", Array)
38
+ ], AccessorySaleLine.prototype, "identifiers", void 0);
@@ -1,6 +1,7 @@
1
1
  import type { SaleTypeEnum } from '../enums/SaleTypeEnum';
2
2
  import type { SaleStatusEnum } from '../enums/SaleStatusEnum';
3
3
  import type { SalePaymentMethodEnum } from '../enums/SalePaymentMethodEnum';
4
+ import type { SaleChannelEnum } from '../enums/SaleChannelEnum';
4
5
  import type { ExternalProviderEnum } from '../enums/ExternalProviderEnum';
5
6
  import type { CentralSyncStatusEnum } from '../enums/CentralSyncStatusEnum';
6
7
  import type { SalePaymentDetail } from './SalePaymentDetail';
@@ -17,7 +18,10 @@ export interface Sale {
17
18
  storeId: string;
18
19
  sellerRetailUserId: string;
19
20
  retailCustomerId: string;
20
- wizardSessionId: string;
21
+ /** Sesión del wizard que cerró la venta; ausente en la venta de mostrador. */
22
+ wizardSessionId?: string;
23
+ /** Canal de la venta; ausente = `WIZARD` (ventas anteriores al campo). */
24
+ saleChannel?: SaleChannelEnum;
21
25
  type: SaleTypeEnum;
22
26
  externalProvider: ExternalProviderEnum | null;
23
27
  /** SKU del teléfono de la venta; `null` en la venta sin teléfono (en DDB se omite). */
@@ -0,0 +1,18 @@
1
+ import { SalePaymentMethodEnum } from '../../enums/SalePaymentMethodEnum';
2
+ import { SalePaymentDetail } from '../SalePaymentDetail';
3
+ import { AccessorySaleLine } from '../AccessorySaleLine';
4
+ /**
5
+ * POST /wizard/accessory-sales — cierra la venta de mostrador con el celular ya verificado.
6
+ * `amountCents` es lo cobrado en caja y debe igualar la suma del catálogo.
7
+ */
8
+ export declare class CreateAccessorySaleRequest {
9
+ otpChallengeId: string;
10
+ lines: AccessorySaleLine[];
11
+ paymentMethod: SalePaymentMethodEnum;
12
+ amountCents: number;
13
+ paymentDetail: SalePaymentDetail;
14
+ /** El cliente aceptó el aviso de privacidad; sin `true` el back responde 400 PRIVACY_NOTICE_REQUIRED. */
15
+ privacyNoticeAccepted?: boolean;
16
+ /** Versión del aviso de privacidad que se mostró. */
17
+ privacyNoticeVersion: string;
18
+ }
@@ -0,0 +1,69 @@
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.CreateAccessorySaleRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const SalePaymentMethodEnum_1 = require("../../enums/SalePaymentMethodEnum");
16
+ const SalePaymentDetail_1 = require("../SalePaymentDetail");
17
+ const AccessorySaleLine_1 = require("../AccessorySaleLine");
18
+ /**
19
+ * POST /wizard/accessory-sales — cierra la venta de mostrador con el celular ya verificado.
20
+ * `amountCents` es lo cobrado en caja y debe igualar la suma del catálogo.
21
+ */
22
+ class CreateAccessorySaleRequest {
23
+ }
24
+ exports.CreateAccessorySaleRequest = CreateAccessorySaleRequest;
25
+ __decorate([
26
+ (0, class_transformer_1.Expose)(),
27
+ (0, class_validator_1.IsString)(),
28
+ (0, class_validator_1.MinLength)(1),
29
+ __metadata("design:type", String)
30
+ ], CreateAccessorySaleRequest.prototype, "otpChallengeId", void 0);
31
+ __decorate([
32
+ (0, class_transformer_1.Expose)(),
33
+ (0, class_validator_1.IsArray)(),
34
+ (0, class_validator_1.ArrayMinSize)(1),
35
+ (0, class_validator_1.ArrayMaxSize)(50),
36
+ (0, class_validator_1.ValidateNested)({ each: true }),
37
+ (0, class_transformer_1.Type)(() => AccessorySaleLine_1.AccessorySaleLine),
38
+ __metadata("design:type", Array)
39
+ ], CreateAccessorySaleRequest.prototype, "lines", void 0);
40
+ __decorate([
41
+ (0, class_transformer_1.Expose)(),
42
+ (0, class_validator_1.IsEnum)(SalePaymentMethodEnum_1.SalePaymentMethodEnum),
43
+ __metadata("design:type", String)
44
+ ], CreateAccessorySaleRequest.prototype, "paymentMethod", void 0);
45
+ __decorate([
46
+ (0, class_transformer_1.Expose)(),
47
+ (0, class_validator_1.IsInt)(),
48
+ (0, class_validator_1.Min)(0),
49
+ __metadata("design:type", Number)
50
+ ], CreateAccessorySaleRequest.prototype, "amountCents", void 0);
51
+ __decorate([
52
+ (0, class_transformer_1.Expose)(),
53
+ (0, class_validator_1.IsDefined)(),
54
+ (0, class_validator_1.ValidateNested)(),
55
+ (0, class_transformer_1.Type)(() => SalePaymentDetail_1.SalePaymentDetail),
56
+ __metadata("design:type", SalePaymentDetail_1.SalePaymentDetail)
57
+ ], CreateAccessorySaleRequest.prototype, "paymentDetail", void 0);
58
+ __decorate([
59
+ (0, class_transformer_1.Expose)(),
60
+ (0, class_validator_1.IsOptional)(),
61
+ (0, class_validator_1.IsBoolean)(),
62
+ __metadata("design:type", Boolean)
63
+ ], CreateAccessorySaleRequest.prototype, "privacyNoticeAccepted", void 0);
64
+ __decorate([
65
+ (0, class_transformer_1.Expose)(),
66
+ (0, class_validator_1.IsString)(),
67
+ (0, class_validator_1.MinLength)(1),
68
+ __metadata("design:type", String)
69
+ ], CreateAccessorySaleRequest.prototype, "privacyNoticeVersion", void 0);
@@ -0,0 +1,12 @@
1
+ import { ReturnPieceCondition } from '../../../retailCatalog/dtos/requests/ReturnPieceCondition';
2
+ /**
3
+ * POST /portal/sales/:saleId/cancel — el vendedor cancela una venta cerrada de su tienda, dentro de la
4
+ * ventana. Mismas validaciones que `BackofficeCancelSaleRequest`, sin la excepción de cancelación tardía.
5
+ */
6
+ export declare class PortalCancelSaleRequest {
7
+ reason: string;
8
+ /** Equipo o piezas confirmados en tienda; ausente cuenta como no confirmado. */
9
+ equipmentVerified?: boolean;
10
+ /** Condición de cada pieza que regresa al inventario; las no listadas vuelven GOOD. */
11
+ returnConditions?: ReturnPieceCondition[];
12
+ }
@@ -0,0 +1,43 @@
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.PortalCancelSaleRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const ReturnPieceCondition_1 = require("../../../retailCatalog/dtos/requests/ReturnPieceCondition");
16
+ /**
17
+ * POST /portal/sales/:saleId/cancel — el vendedor cancela una venta cerrada de su tienda, dentro de la
18
+ * ventana. Mismas validaciones que `BackofficeCancelSaleRequest`, sin la excepción de cancelación tardía.
19
+ */
20
+ class PortalCancelSaleRequest {
21
+ }
22
+ exports.PortalCancelSaleRequest = PortalCancelSaleRequest;
23
+ __decorate([
24
+ (0, class_transformer_1.Expose)(),
25
+ (0, class_validator_1.IsString)(),
26
+ (0, class_validator_1.MinLength)(10),
27
+ (0, class_validator_1.MaxLength)(200),
28
+ __metadata("design:type", String)
29
+ ], PortalCancelSaleRequest.prototype, "reason", void 0);
30
+ __decorate([
31
+ (0, class_transformer_1.Expose)(),
32
+ (0, class_validator_1.IsOptional)(),
33
+ (0, class_validator_1.IsBoolean)(),
34
+ __metadata("design:type", Boolean)
35
+ ], PortalCancelSaleRequest.prototype, "equipmentVerified", void 0);
36
+ __decorate([
37
+ (0, class_transformer_1.Expose)(),
38
+ (0, class_validator_1.IsOptional)(),
39
+ (0, class_validator_1.IsArray)(),
40
+ (0, class_validator_1.ValidateNested)({ each: true }),
41
+ (0, class_transformer_1.Type)(() => ReturnPieceCondition_1.ReturnPieceCondition),
42
+ __metadata("design:type", Array)
43
+ ], PortalCancelSaleRequest.prototype, "returnConditions", void 0);
@@ -0,0 +1,4 @@
1
+ /** POST /wizard/accessory-sales/otp — manda el OTP al celular del cliente del mostrador. */
2
+ export declare class SendAccessoryOtpRequest {
3
+ phone: string;
4
+ }
@@ -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.SendAccessoryOtpRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ const regex_1 = require("../../../helpers/constans/regex");
16
+ /** POST /wizard/accessory-sales/otp — manda el OTP al celular del cliente del mostrador. */
17
+ class SendAccessoryOtpRequest {
18
+ }
19
+ exports.SendAccessoryOtpRequest = SendAccessoryOtpRequest;
20
+ __decorate([
21
+ (0, class_transformer_1.Expose)(),
22
+ (0, class_validator_1.IsString)(),
23
+ (0, class_validator_1.Matches)(regex_1.regexPhoneMx, { message: 'phone debe tener 10 dígitos' }),
24
+ __metadata("design:type", String)
25
+ ], SendAccessoryOtpRequest.prototype, "phone", void 0);
@@ -0,0 +1,4 @@
1
+ /** POST /wizard/accessory-sales/otp/{otpChallengeId}/verify — código que dicta el cliente. */
2
+ export declare class VerifyAccessoryOtpRequest {
3
+ code: string;
4
+ }
@@ -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
+ 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.VerifyAccessoryOtpRequest = void 0;
13
+ const class_transformer_1 = require("class-transformer");
14
+ const class_validator_1 = require("class-validator");
15
+ /** POST /wizard/accessory-sales/otp/{otpChallengeId}/verify — código que dicta el cliente. */
16
+ class VerifyAccessoryOtpRequest {
17
+ }
18
+ exports.VerifyAccessoryOtpRequest = VerifyAccessoryOtpRequest;
19
+ __decorate([
20
+ (0, class_transformer_1.Expose)(),
21
+ (0, class_validator_1.IsString)(),
22
+ (0, class_validator_1.Length)(4, 8),
23
+ __metadata("design:type", String)
24
+ ], VerifyAccessoryOtpRequest.prototype, "code", void 0);
@@ -0,0 +1,7 @@
1
+ /** Reto OTP del mostrador de accesorios (send y resend). `phoneMasked` muestra solo los últimos 4 dígitos. */
2
+ export interface AccessoryOtpChallenge {
3
+ otpChallengeId: string;
4
+ phoneMasked: string;
5
+ expiresAt: string;
6
+ resendAvailableAt: string;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,7 @@
1
+ /** Reto verificado: ampara una sola venta hasta `usableUntil`. */
2
+ export interface VerifyAccessoryOtpResponse {
3
+ otpChallengeId: string;
4
+ verified: true;
5
+ verifiedAt: string;
6
+ usableUntil: string;
7
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,5 @@
1
+ /** Canal por el que se cerró la venta: el wizard por sesión o el mostrador de accesorios. */
2
+ export declare enum SaleChannelEnum {
3
+ WIZARD = "WIZARD",
4
+ ACCESSORY_COUNTER = "ACCESSORY_COUNTER"
5
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SaleChannelEnum = void 0;
4
+ /** Canal por el que se cerró la venta: el wizard por sesión o el mostrador de accesorios. */
5
+ var SaleChannelEnum;
6
+ (function (SaleChannelEnum) {
7
+ SaleChannelEnum["WIZARD"] = "WIZARD";
8
+ SaleChannelEnum["ACCESSORY_COUNTER"] = "ACCESSORY_COUNTER";
9
+ })(SaleChannelEnum || (exports.SaleChannelEnum = SaleChannelEnum = {}));
@@ -29,6 +29,7 @@ export * from './enums/WizardLineStatusEnum';
29
29
  export * from './enums/LinePaymentTypeEnum';
30
30
  export * from './enums/WizardLineRoleEnum';
31
31
  export * from './enums/EmailStateEnum';
32
+ export * from './enums/SaleChannelEnum';
32
33
  export * from './dtos/WizardConsents';
33
34
  export * from './dtos/WizardPayment';
34
35
  export * from './dtos/WizardProduct';
@@ -52,6 +53,7 @@ export * from './dtos/WizardFinancingPreview';
52
53
  export * from './dtos/WizardReservedLine';
53
54
  export * from './dtos/WizardGiftLine';
54
55
  export * from './dtos/SaleLine';
56
+ export * from './dtos/AccessorySaleLine';
55
57
  export * from './dtos/WizardSession';
56
58
  export * from './dtos/OtpVerification';
57
59
  export * from './dtos/Sale';
@@ -97,6 +99,9 @@ export * from './dtos/requests/CompleteSaleRequest';
97
99
  export * from './dtos/requests/SuggestIdentifiersQuery';
98
100
  export * from './dtos/requests/SendEmailOtpRequest';
99
101
  export * from './dtos/requests/VerifyEmailOtpRequest';
102
+ export * from './dtos/requests/SendAccessoryOtpRequest';
103
+ export * from './dtos/requests/VerifyAccessoryOtpRequest';
104
+ export * from './dtos/requests/CreateAccessorySaleRequest';
100
105
  export * from './dtos/responses/KycPrepareResponse';
101
106
  export * from './dtos/responses/ProofOfAddressPrepareResponse';
102
107
  export * from './dtos/responses/SessionFinanciersResponse';
@@ -115,6 +120,8 @@ export * from './dtos/responses/ProspectResumeResponse';
115
120
  export * from './dtos/responses/CancelOtherStoreSaleResponse';
116
121
  export * from './dtos/responses/ProspectByPhoneResponse';
117
122
  export * from './dtos/responses/AppOnboardingResponse';
123
+ export * from './dtos/responses/AccessoryOtpChallenge';
124
+ export * from './dtos/responses/VerifyAccessoryOtpResponse';
118
125
  export * from './enums/SaleFinancierEnum';
119
126
  export * from './enums/SaleExceptionTypeEnum';
120
127
  export * from './enums/SaleExceptionStatusEnum';
@@ -138,6 +145,7 @@ export * from './dtos/requests/ApplySaleExceptionRequest';
138
145
  export * from './dtos/requests/AddSaleExceptionNoteRequest';
139
146
  export * from './dtos/requests/RunSalesReportRequest';
140
147
  export * from './dtos/requests/BackofficeCancelSaleRequest';
148
+ export * from './dtos/requests/PortalCancelSaleRequest';
141
149
  export * from './dtos/responses/BackofficeSalesStatsResponse';
142
150
  export * from './dtos/responses/BackofficeSalesKpisResponse';
143
151
  export * from './dtos/responses/BackofficeReportsResponse';
@@ -48,6 +48,7 @@ __exportStar(require("./enums/WizardLineStatusEnum"), exports);
48
48
  __exportStar(require("./enums/LinePaymentTypeEnum"), exports);
49
49
  __exportStar(require("./enums/WizardLineRoleEnum"), exports);
50
50
  __exportStar(require("./enums/EmailStateEnum"), exports);
51
+ __exportStar(require("./enums/SaleChannelEnum"), exports);
51
52
  // DTOs anidados
52
53
  __exportStar(require("./dtos/WizardConsents"), exports);
53
54
  __exportStar(require("./dtos/WizardPayment"), exports);
@@ -74,6 +75,7 @@ __exportStar(require("./dtos/WizardFinancingPreview"), exports);
74
75
  __exportStar(require("./dtos/WizardReservedLine"), exports);
75
76
  __exportStar(require("./dtos/WizardGiftLine"), exports);
76
77
  __exportStar(require("./dtos/SaleLine"), exports);
78
+ __exportStar(require("./dtos/AccessorySaleLine"), exports);
77
79
  // Entidades principales (shapes de estado/persistencia — planas)
78
80
  __exportStar(require("./dtos/WizardSession"), exports);
79
81
  __exportStar(require("./dtos/OtpVerification"), exports);
@@ -122,6 +124,9 @@ __exportStar(require("./dtos/requests/CompleteSaleRequest"), exports);
122
124
  __exportStar(require("./dtos/requests/SuggestIdentifiersQuery"), exports);
123
125
  __exportStar(require("./dtos/requests/SendEmailOtpRequest"), exports);
124
126
  __exportStar(require("./dtos/requests/VerifyEmailOtpRequest"), exports);
127
+ __exportStar(require("./dtos/requests/SendAccessoryOtpRequest"), exports);
128
+ __exportStar(require("./dtos/requests/VerifyAccessoryOtpRequest"), exports);
129
+ __exportStar(require("./dtos/requests/CreateAccessorySaleRequest"), exports);
125
130
  // Response DTOs (output tipado por endpoint)
126
131
  __exportStar(require("./dtos/responses/KycPrepareResponse"), exports);
127
132
  __exportStar(require("./dtos/responses/ProofOfAddressPrepareResponse"), exports);
@@ -141,6 +146,8 @@ __exportStar(require("./dtos/responses/ProspectResumeResponse"), exports);
141
146
  __exportStar(require("./dtos/responses/CancelOtherStoreSaleResponse"), exports);
142
147
  __exportStar(require("./dtos/responses/ProspectByPhoneResponse"), exports);
143
148
  __exportStar(require("./dtos/responses/AppOnboardingResponse"), exports);
149
+ __exportStar(require("./dtos/responses/AccessoryOtpChallenge"), exports);
150
+ __exportStar(require("./dtos/responses/VerifyAccessoryOtpResponse"), exports);
144
151
  // ── F3 · Backoffice VentasLuga ────────────────────────────────────────────────
145
152
  // Enums
146
153
  __exportStar(require("./enums/SaleFinancierEnum"), exports);
@@ -169,6 +176,7 @@ __exportStar(require("./dtos/requests/ApplySaleExceptionRequest"), exports);
169
176
  __exportStar(require("./dtos/requests/AddSaleExceptionNoteRequest"), exports);
170
177
  __exportStar(require("./dtos/requests/RunSalesReportRequest"), exports);
171
178
  __exportStar(require("./dtos/requests/BackofficeCancelSaleRequest"), exports);
179
+ __exportStar(require("./dtos/requests/PortalCancelSaleRequest"), exports);
172
180
  // Responses
173
181
  __exportStar(require("./dtos/responses/BackofficeSalesStatsResponse"), exports);
174
182
  __exportStar(require("./dtos/responses/BackofficeSalesKpisResponse"), exports);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fiado/type-kit",
3
- "version": "3.539.0",
3
+ "version": "3.540.0",
4
4
  "description": "",
5
5
  "main": "bin/index.js",
6
6
  "types": "bin/index.d.ts",
@@ -0,0 +1,20 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsString, Matches, MinLength } from 'class-validator';
3
+ import { regexPhoneMx } from '../../../helpers/constans/regex';
4
+
5
+ /**
6
+ * POST /private/customers/ensure-by-phone — da de alta al cliente solo con su celular verificado,
7
+ * o devuelve el que ya existe con ese número.
8
+ */
9
+ export class EnsureCustomerByPhoneRequest {
10
+ @Expose()
11
+ @IsString()
12
+ @Matches(regexPhoneMx, { message: 'phone debe tener 10 dígitos' })
13
+ phone!: string;
14
+
15
+ /** Tienda del primer contacto; no cambia si el cliente ya existía. */
16
+ @Expose()
17
+ @IsString()
18
+ @MinLength(1)
19
+ originStoreId!: string;
20
+ }
@@ -0,0 +1,6 @@
1
+ import { CustomerResponse } from './CustomerResponse';
2
+
3
+ /** Cliente resuelto por celular; `created` dice si esta llamada lo dio de alta. */
4
+ export interface EnsureCustomerByPhoneResponse extends CustomerResponse {
5
+ created: boolean;
6
+ }
@@ -24,6 +24,7 @@ export * from './dtos/requests/KycReviewRequest';
24
24
  export * from './dtos/requests/WelcomeAccreditationRequest';
25
25
  export * from './dtos/requests/WelcomeAccreditationResultRequest';
26
26
  export * from './dtos/requests/UpsertPromotionBonusRequest';
27
+ export * from './dtos/requests/EnsureCustomerByPhoneRequest';
27
28
 
28
29
  // Response DTOs
29
30
  export * from './dtos/responses/CustomerResponse';
@@ -31,6 +32,7 @@ export * from './dtos/responses/Customer360Response';
31
32
  export * from './dtos/responses/WelcomeBonusResponse';
32
33
  export * from './dtos/responses/WelcomeAccreditationResponse';
33
34
  export * from './dtos/responses/PromotionBonusEntryResponse';
35
+ export * from './dtos/responses/EnsureCustomerByPhoneResponse';
34
36
 
35
37
  // Contratos de eventos (PascalCase + sufijo V1)
36
38
  export * from './events/CustomerCreatedV1';
@@ -0,0 +1,23 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { ArrayMaxSize, IsArray, IsInt, IsOptional, IsString, Min, MinLength } from 'class-validator';
3
+
4
+ /** Línea del carrito de accesorios; el precio lo pone el catálogo, no el request. */
5
+ export class AccessorySaleLine {
6
+ @Expose()
7
+ @IsString()
8
+ @MinLength(1)
9
+ sku!: string;
10
+
11
+ @Expose()
12
+ @IsInt()
13
+ @Min(1)
14
+ qty!: number;
15
+
16
+ /** Serie de cada pieza cuando el SKU se rastrea por pieza; ausente si se rastrea por cantidad. */
17
+ @Expose()
18
+ @IsOptional()
19
+ @IsArray()
20
+ @ArrayMaxSize(100)
21
+ @IsString({ each: true })
22
+ identifiers?: string[];
23
+ }
@@ -1,6 +1,7 @@
1
1
  import type { SaleTypeEnum } from '../enums/SaleTypeEnum';
2
2
  import type { SaleStatusEnum } from '../enums/SaleStatusEnum';
3
3
  import type { SalePaymentMethodEnum } from '../enums/SalePaymentMethodEnum';
4
+ import type { SaleChannelEnum } from '../enums/SaleChannelEnum';
4
5
  import type { ExternalProviderEnum } from '../enums/ExternalProviderEnum';
5
6
  import type { CentralSyncStatusEnum } from '../enums/CentralSyncStatusEnum';
6
7
  import type { SalePaymentDetail } from './SalePaymentDetail';
@@ -18,7 +19,10 @@ export interface Sale {
18
19
  storeId: string;
19
20
  sellerRetailUserId: string;
20
21
  retailCustomerId: string;
21
- wizardSessionId: string;
22
+ /** Sesión del wizard que cerró la venta; ausente en la venta de mostrador. */
23
+ wizardSessionId?: string;
24
+ /** Canal de la venta; ausente = `WIZARD` (ventas anteriores al campo). */
25
+ saleChannel?: SaleChannelEnum;
22
26
  type: SaleTypeEnum;
23
27
  externalProvider: ExternalProviderEnum | null;
24
28
  /** SKU del teléfono de la venta; `null` en la venta sin teléfono (en DDB se omite). */
@@ -0,0 +1,64 @@
1
+ import { Expose, Type } from 'class-transformer';
2
+ import {
3
+ ArrayMaxSize,
4
+ ArrayMinSize,
5
+ IsArray,
6
+ IsBoolean,
7
+ IsDefined,
8
+ IsEnum,
9
+ IsInt,
10
+ IsOptional,
11
+ IsString,
12
+ Min,
13
+ MinLength,
14
+ ValidateNested,
15
+ } from 'class-validator';
16
+ import { SalePaymentMethodEnum } from '../../enums/SalePaymentMethodEnum';
17
+ import { SalePaymentDetail } from '../SalePaymentDetail';
18
+ import { AccessorySaleLine } from '../AccessorySaleLine';
19
+
20
+ /**
21
+ * POST /wizard/accessory-sales — cierra la venta de mostrador con el celular ya verificado.
22
+ * `amountCents` es lo cobrado en caja y debe igualar la suma del catálogo.
23
+ */
24
+ export class CreateAccessorySaleRequest {
25
+ @Expose()
26
+ @IsString()
27
+ @MinLength(1)
28
+ otpChallengeId!: string;
29
+
30
+ @Expose()
31
+ @IsArray()
32
+ @ArrayMinSize(1)
33
+ @ArrayMaxSize(50)
34
+ @ValidateNested({ each: true })
35
+ @Type(() => AccessorySaleLine)
36
+ lines!: AccessorySaleLine[];
37
+
38
+ @Expose()
39
+ @IsEnum(SalePaymentMethodEnum)
40
+ paymentMethod!: SalePaymentMethodEnum;
41
+
42
+ @Expose()
43
+ @IsInt()
44
+ @Min(0)
45
+ amountCents!: number;
46
+
47
+ @Expose()
48
+ @IsDefined()
49
+ @ValidateNested()
50
+ @Type(() => SalePaymentDetail)
51
+ paymentDetail!: SalePaymentDetail;
52
+
53
+ /** El cliente aceptó el aviso de privacidad; sin `true` el back responde 400 PRIVACY_NOTICE_REQUIRED. */
54
+ @Expose()
55
+ @IsOptional()
56
+ @IsBoolean()
57
+ privacyNoticeAccepted?: boolean;
58
+
59
+ /** Versión del aviso de privacidad que se mostró. */
60
+ @Expose()
61
+ @IsString()
62
+ @MinLength(1)
63
+ privacyNoticeVersion!: string;
64
+ }
@@ -0,0 +1,29 @@
1
+ import { Expose, Type } from 'class-transformer';
2
+ import { IsArray, IsBoolean, IsOptional, IsString, MaxLength, MinLength, ValidateNested } from 'class-validator';
3
+ import { ReturnPieceCondition } from '../../../retailCatalog/dtos/requests/ReturnPieceCondition';
4
+
5
+ /**
6
+ * POST /portal/sales/:saleId/cancel — el vendedor cancela una venta cerrada de su tienda, dentro de la
7
+ * ventana. Mismas validaciones que `BackofficeCancelSaleRequest`, sin la excepción de cancelación tardía.
8
+ */
9
+ export class PortalCancelSaleRequest {
10
+ @Expose()
11
+ @IsString()
12
+ @MinLength(10)
13
+ @MaxLength(200)
14
+ reason!: string;
15
+
16
+ /** Equipo o piezas confirmados en tienda; ausente cuenta como no confirmado. */
17
+ @Expose()
18
+ @IsOptional()
19
+ @IsBoolean()
20
+ equipmentVerified?: boolean;
21
+
22
+ /** Condición de cada pieza que regresa al inventario; las no listadas vuelven GOOD. */
23
+ @Expose()
24
+ @IsOptional()
25
+ @IsArray()
26
+ @ValidateNested({ each: true })
27
+ @Type(() => ReturnPieceCondition)
28
+ returnConditions?: ReturnPieceCondition[];
29
+ }
@@ -0,0 +1,11 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsString, Matches } from 'class-validator';
3
+ import { regexPhoneMx } from '../../../helpers/constans/regex';
4
+
5
+ /** POST /wizard/accessory-sales/otp — manda el OTP al celular del cliente del mostrador. */
6
+ export class SendAccessoryOtpRequest {
7
+ @Expose()
8
+ @IsString()
9
+ @Matches(regexPhoneMx, { message: 'phone debe tener 10 dígitos' })
10
+ phone!: string;
11
+ }
@@ -0,0 +1,10 @@
1
+ import { Expose } from 'class-transformer';
2
+ import { IsString, Length } from 'class-validator';
3
+
4
+ /** POST /wizard/accessory-sales/otp/{otpChallengeId}/verify — código que dicta el cliente. */
5
+ export class VerifyAccessoryOtpRequest {
6
+ @Expose()
7
+ @IsString()
8
+ @Length(4, 8)
9
+ code!: string;
10
+ }
@@ -0,0 +1,7 @@
1
+ /** Reto OTP del mostrador de accesorios (send y resend). `phoneMasked` muestra solo los últimos 4 dígitos. */
2
+ export interface AccessoryOtpChallenge {
3
+ otpChallengeId: string;
4
+ phoneMasked: string;
5
+ expiresAt: string;
6
+ resendAvailableAt: string;
7
+ }
@@ -0,0 +1,7 @@
1
+ /** Reto verificado: ampara una sola venta hasta `usableUntil`. */
2
+ export interface VerifyAccessoryOtpResponse {
3
+ otpChallengeId: string;
4
+ verified: true;
5
+ verifiedAt: string;
6
+ usableUntil: string;
7
+ }
@@ -0,0 +1,5 @@
1
+ /** Canal por el que se cerró la venta: el wizard por sesión o el mostrador de accesorios. */
2
+ export enum SaleChannelEnum {
3
+ WIZARD = 'WIZARD',
4
+ ACCESSORY_COUNTER = 'ACCESSORY_COUNTER',
5
+ }
@@ -32,6 +32,7 @@ export * from './enums/WizardLineStatusEnum';
32
32
  export * from './enums/LinePaymentTypeEnum';
33
33
  export * from './enums/WizardLineRoleEnum';
34
34
  export * from './enums/EmailStateEnum';
35
+ export * from './enums/SaleChannelEnum';
35
36
 
36
37
  // DTOs anidados
37
38
  export * from './dtos/WizardConsents';
@@ -57,6 +58,7 @@ export * from './dtos/WizardFinancingPreview';
57
58
  export * from './dtos/WizardReservedLine';
58
59
  export * from './dtos/WizardGiftLine';
59
60
  export * from './dtos/SaleLine';
61
+ export * from './dtos/AccessorySaleLine';
60
62
 
61
63
  // Entidades principales (shapes de estado/persistencia — planas)
62
64
  export * from './dtos/WizardSession';
@@ -108,6 +110,9 @@ export * from './dtos/requests/CompleteSaleRequest';
108
110
  export * from './dtos/requests/SuggestIdentifiersQuery';
109
111
  export * from './dtos/requests/SendEmailOtpRequest';
110
112
  export * from './dtos/requests/VerifyEmailOtpRequest';
113
+ export * from './dtos/requests/SendAccessoryOtpRequest';
114
+ export * from './dtos/requests/VerifyAccessoryOtpRequest';
115
+ export * from './dtos/requests/CreateAccessorySaleRequest';
111
116
 
112
117
  // Response DTOs (output tipado por endpoint)
113
118
  export * from './dtos/responses/KycPrepareResponse';
@@ -128,6 +133,8 @@ export * from './dtos/responses/ProspectResumeResponse';
128
133
  export * from './dtos/responses/CancelOtherStoreSaleResponse';
129
134
  export * from './dtos/responses/ProspectByPhoneResponse';
130
135
  export * from './dtos/responses/AppOnboardingResponse';
136
+ export * from './dtos/responses/AccessoryOtpChallenge';
137
+ export * from './dtos/responses/VerifyAccessoryOtpResponse';
131
138
 
132
139
  // ── F3 · Backoffice VentasLuga ────────────────────────────────────────────────
133
140
  // Enums
@@ -160,6 +167,7 @@ export * from './dtos/requests/ApplySaleExceptionRequest';
160
167
  export * from './dtos/requests/AddSaleExceptionNoteRequest';
161
168
  export * from './dtos/requests/RunSalesReportRequest';
162
169
  export * from './dtos/requests/BackofficeCancelSaleRequest';
170
+ export * from './dtos/requests/PortalCancelSaleRequest';
163
171
 
164
172
  // Responses
165
173
  export * from './dtos/responses/BackofficeSalesStatsResponse';