@fiado/type-kit 3.551.0 → 3.553.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_test_/unit/common/InputPatternValidators.test.ts +64 -0
- package/_test_/unit/common/InputPatterns.test.ts +104 -0
- package/_test_/unit/retailCatalog/backofficeRequests.test.ts +1 -1
- package/_test_/unit/retailCatalog/singlePriceFields.test.ts +48 -0
- package/_test_/unit/retailIntegration/eventPayloads.test.ts +1 -0
- package/_test_/unit/retailOrg/dtos/requests/inputPatternRequests.test.ts +93 -0
- package/_test_/unit/retailPromotions/giftOptionValue.test.ts +20 -0
- package/_test_/unit/retailWizard/linesWithoutListPrice.test.ts +40 -0
- package/bin/common/constants/InputPatterns.d.ts +25 -0
- package/bin/common/constants/InputPatterns.js +28 -0
- package/bin/common/decorators/UpperCase.d.ts +2 -0
- package/bin/common/decorators/UpperCase.js +7 -0
- package/bin/common/helpers/imeiChecksum.d.ts +2 -0
- package/bin/common/helpers/imeiChecksum.js +20 -0
- package/bin/common/index.d.ts +8 -0
- package/bin/common/index.js +10 -0
- package/bin/common/validators/IsMxPhone.d.ts +3 -0
- package/bin/common/validators/IsMxPhone.js +8 -0
- package/bin/common/validators/IsMxZipCode.d.ts +3 -0
- package/bin/common/validators/IsMxZipCode.js +8 -0
- package/bin/common/validators/IsRfc.d.ts +3 -0
- package/bin/common/validators/IsRfc.js +8 -0
- package/bin/common/validators/IsSku.d.ts +3 -0
- package/bin/common/validators/IsSku.js +8 -0
- package/bin/common/validators/matchesInputPattern.d.ts +3 -0
- package/bin/common/validators/matchesInputPattern.js +16 -0
- package/bin/helpers/constans/regex.js +2 -1
- package/bin/loanCredit/dtos/LoanContractDetails.js +2 -2
- package/bin/loanCredit/dtos/LoanDeviceEnrollItem.js +4 -4
- package/bin/retailCatalog/constants/SkuPattern.d.ts +2 -2
- package/bin/retailCatalog/constants/SkuPattern.js +5 -3
- package/bin/retailCatalog/dtos/Product.d.ts +2 -1
- package/bin/retailCatalog/dtos/ProductComponent.js +1 -1
- package/bin/retailCatalog/dtos/requests/BackofficeCreateKitRequest.js +1 -1
- package/bin/retailCatalog/dtos/requests/BackofficeCreateProductRequest.js +1 -1
- package/bin/retailCatalog/dtos/requests/BackofficeCreateServiceRequest.js +1 -1
- package/bin/retailCatalog/dtos/requests/BackofficeCreateSkuPriceRequest.d.ts +1 -0
- package/bin/retailCatalog/dtos/requests/BackofficeCreateTransferRequest.js +1 -1
- package/bin/retailCatalog/dtos/requests/BackofficeRegisterAdjustmentRequest.js +1 -1
- package/bin/retailCatalog/dtos/requests/BackofficeRegisterEntryRequest.js +1 -1
- package/bin/retailCatalog/dtos/requests/CreateProductRequest.d.ts +1 -0
- package/bin/retailCatalog/dtos/requests/CreateProductRequest.js +1 -1
- package/bin/retailCatalog/dtos/requests/ReturnPieceCondition.js +1 -1
- package/bin/retailCatalog/dtos/requests/SyncInventoryRequest.d.ts +1 -0
- package/bin/retailCatalog/dtos/requests/SyncInventoryRequest.js +1 -1
- package/bin/retailCatalog/dtos/requests/UpdateProductRequest.d.ts +1 -0
- package/bin/retailCatalog/dtos/responses/InventoryLensResponse.d.ts +1 -1
- package/bin/retailCatalog/dtos/responses/ReserveStockResponse.d.ts +4 -1
- package/bin/retailCatalog/dtos/responses/SkuPriceEntry.d.ts +2 -1
- package/bin/retailCatalog/dtos/responses/StoreCatalogItem.d.ts +1 -1
- package/bin/retailIntegration/constants/retailIntegrationLimits.d.ts +1 -1
- package/bin/retailIntegration/constants/retailIntegrationLimits.js +2 -2
- package/bin/retailOrg/dtos/requests/CreateRetailUserRequest.js +2 -1
- package/bin/retailOrg/dtos/requests/CreateRetailerRequest.d.ts +1 -1
- package/bin/retailOrg/dtos/requests/CreateRetailerRequest.js +6 -2
- package/bin/retailOrg/dtos/requests/CreateStoreRequest.js +2 -1
- package/bin/retailOrg/dtos/requests/CreateSubdistributorRequest.d.ts +1 -1
- package/bin/retailOrg/dtos/requests/CreateSubdistributorRequest.js +6 -2
- package/bin/retailOrg/dtos/requests/ProvisionRetailUserRequest.js +2 -1
- package/bin/retailOrg/dtos/requests/RetailAddressInput.d.ts +1 -1
- package/bin/retailOrg/dtos/requests/RetailAddressInput.js +2 -2
- package/bin/retailOrg/dtos/requests/UpdateRetailUserRequest.js +2 -1
- package/bin/retailOrg/dtos/requests/UpdateRetailerRequest.js +2 -1
- package/bin/retailOrg/dtos/requests/UpdateStoreRequest.js +2 -1
- package/bin/retailPromotions/dtos/responses/WizardSalePromotionResponses.d.ts +4 -1
- package/bin/retailWizard/dtos/SaleLine.d.ts +2 -1
- package/bin/retailWizard/dtos/WizardGiftLine.d.ts +1 -1
- package/bin/retailWizard/dtos/WizardLinePromotionFields.d.ts +1 -1
- package/bin/retailWizard/dtos/WizardReservedLine.d.ts +2 -1
- package/bin/retailWizard/events/SaleCompletedV1.d.ts +1 -1
- package/bin/retailWizard/events/SaleCompletedV2.d.ts +1 -1
- package/package.json +1 -1
- package/src/common/constants/InputPatterns.ts +32 -0
- package/src/common/decorators/UpperCase.ts +5 -0
- package/src/common/helpers/imeiChecksum.ts +16 -0
- package/src/common/index.ts +12 -0
- package/src/common/validators/IsMxPhone.ts +7 -0
- package/src/common/validators/IsMxZipCode.ts +7 -0
- package/src/common/validators/IsRfc.ts +7 -0
- package/src/common/validators/IsSku.ts +7 -0
- package/src/common/validators/matchesInputPattern.ts +24 -0
- package/src/helpers/constans/regex.ts +2 -1
- package/src/loanCredit/dtos/LoanContractDetails.ts +1 -1
- package/src/loanCredit/dtos/LoanDeviceEnrollItem.ts +3 -3
- package/src/retailCatalog/constants/SkuPattern.ts +2 -2
- package/src/retailCatalog/dtos/Product.ts +2 -1
- package/src/retailCatalog/dtos/ProductComponent.ts +2 -2
- package/src/retailCatalog/dtos/requests/BackofficeCreateKitRequest.ts +2 -2
- package/src/retailCatalog/dtos/requests/BackofficeCreateProductRequest.ts +2 -2
- package/src/retailCatalog/dtos/requests/BackofficeCreateServiceRequest.ts +2 -2
- package/src/retailCatalog/dtos/requests/BackofficeCreateSkuPriceRequest.ts +1 -0
- package/src/retailCatalog/dtos/requests/BackofficeCreateTransferRequest.ts +2 -2
- package/src/retailCatalog/dtos/requests/BackofficeRegisterAdjustmentRequest.ts +2 -2
- package/src/retailCatalog/dtos/requests/BackofficeRegisterEntryRequest.ts +2 -2
- package/src/retailCatalog/dtos/requests/CreateProductRequest.ts +3 -2
- package/src/retailCatalog/dtos/requests/ReturnPieceCondition.ts +2 -2
- package/src/retailCatalog/dtos/requests/SyncInventoryRequest.ts +3 -2
- package/src/retailCatalog/dtos/requests/UpdateProductRequest.ts +1 -0
- package/src/retailCatalog/dtos/responses/InventoryLensResponse.ts +1 -1
- package/src/retailCatalog/dtos/responses/ReserveStockResponse.ts +4 -1
- package/src/retailCatalog/dtos/responses/SkuPriceEntry.ts +2 -1
- package/src/retailCatalog/dtos/responses/StoreCatalogItem.ts +1 -1
- package/src/retailIntegration/constants/retailIntegrationLimits.ts +2 -2
- package/src/retailOrg/dtos/requests/CreateRetailUserRequest.ts +2 -1
- package/src/retailOrg/dtos/requests/CreateRetailerRequest.ts +8 -4
- package/src/retailOrg/dtos/requests/CreateStoreRequest.ts +2 -1
- package/src/retailOrg/dtos/requests/CreateSubdistributorRequest.ts +8 -4
- package/src/retailOrg/dtos/requests/ProvisionRetailUserRequest.ts +2 -1
- package/src/retailOrg/dtos/requests/RetailAddressInput.ts +3 -3
- package/src/retailOrg/dtos/requests/UpdateRetailUserRequest.ts +2 -1
- package/src/retailOrg/dtos/requests/UpdateRetailerRequest.ts +2 -1
- package/src/retailOrg/dtos/requests/UpdateStoreRequest.ts +2 -1
- package/src/retailPromotions/dtos/responses/WizardSalePromotionResponses.ts +4 -1
- package/src/retailWizard/dtos/SaleLine.ts +2 -1
- package/src/retailWizard/dtos/WizardGiftLine.ts +1 -1
- package/src/retailWizard/dtos/WizardLinePromotionFields.ts +1 -1
- package/src/retailWizard/dtos/WizardReservedLine.ts +2 -1
- package/src/retailWizard/events/SaleCompletedV1.ts +1 -1
- package/src/retailWizard/events/SaleCompletedV2.ts +1 -1
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Teléfono MX tal como se teclea en la UI: exactamente 10 dígitos. */
|
|
2
|
+
export const PHONE_MX_PATTERN = /^\d{10}$/;
|
|
3
|
+
|
|
4
|
+
/** Teléfono MX en el backend: 10 dígitos, opcionalmente con `+52` para clientes que ya lo mandan. */
|
|
5
|
+
export const PHONE_MX_ACCEPTED_PATTERN = /^(?:\+52)?\d{10}$/;
|
|
6
|
+
export const PHONE_MX_MESSAGE = 'El teléfono debe tener 10 dígitos';
|
|
7
|
+
|
|
8
|
+
/** Correo pragmático: algo@dominio.tld, sin espacios. */
|
|
9
|
+
export const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
10
|
+
export const EMAIL_MAX_LENGTH = 254;
|
|
11
|
+
export const EMAIL_MESSAGE = 'Ingresa un correo válido';
|
|
12
|
+
|
|
13
|
+
/** RFC en mayúsculas: 12 caracteres persona moral, 13 persona física. */
|
|
14
|
+
export const RFC_PATTERN = /^[A-ZÑ&]{3,4}\d{6}[A-Z\d]{3}$/;
|
|
15
|
+
export const RFC_MESSAGE = 'El RFC debe tener 12 o 13 caracteres con el formato del SAT';
|
|
16
|
+
|
|
17
|
+
/** Código postal MX: 5 dígitos. */
|
|
18
|
+
export const ZIP_CODE_MX_PATTERN = /^\d{5}$/;
|
|
19
|
+
export const ZIP_CODE_MX_MESSAGE = 'El código postal debe tener 5 dígitos';
|
|
20
|
+
|
|
21
|
+
/** SKU: letras, dígitos y guiones, con espacios solo entre palabras. */
|
|
22
|
+
export const SKU_PATTERN = /^[A-Za-z0-9-]+(?: +[A-Za-z0-9-]+)*$/;
|
|
23
|
+
export const SKU_MAX_LENGTH = 64;
|
|
24
|
+
export const SKU_MESSAGE = 'El SKU admite letras, números, guiones y espacios entre palabras (máximo 64)';
|
|
25
|
+
|
|
26
|
+
/** IMEI: 15 dígitos; el checksum se valida con `isValidImei`. */
|
|
27
|
+
export const IMEI_PATTERN = /^\d{15}$/;
|
|
28
|
+
export const IMEI_MESSAGE = 'El IMEI debe tener 15 dígitos';
|
|
29
|
+
|
|
30
|
+
/** URL https sin espacios; en DTOs de backend también sirve `@IsUrl({ protocols: ['https'], require_protocol: true })`. */
|
|
31
|
+
export const HTTPS_URL_PATTERN = /^https:\/\/[^\s/$.?#][^\s]*$/i;
|
|
32
|
+
export const HTTPS_URL_MESSAGE = 'Ingresa una URL que empiece con https://';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Transform } from 'class-transformer';
|
|
2
|
+
|
|
3
|
+
/** Pasa un string a mayúsculas antes de validarlo; deja pasar cualquier otro tipo sin tocarlo. */
|
|
4
|
+
export const UpperCase = (): PropertyDecorator =>
|
|
5
|
+
Transform(({ value }) => (typeof value === 'string' ? value.toUpperCase() : value));
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { IMEI_PATTERN } from '../constants/InputPatterns';
|
|
2
|
+
|
|
3
|
+
/** Valida un IMEI: 15 dígitos y checksum Luhn. */
|
|
4
|
+
export function isValidImei(imei: string): boolean {
|
|
5
|
+
if (!IMEI_PATTERN.test(imei)) return false;
|
|
6
|
+
let sum = 0;
|
|
7
|
+
for (let i = 0; i < 15; i++) {
|
|
8
|
+
let digit = Number(imei[i]);
|
|
9
|
+
if (i % 2 === 1) {
|
|
10
|
+
digit *= 2;
|
|
11
|
+
if (digit > 9) digit -= 9;
|
|
12
|
+
}
|
|
13
|
+
sum += digit;
|
|
14
|
+
}
|
|
15
|
+
return sum % 10 === 0;
|
|
16
|
+
}
|
package/src/common/index.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
|
+
//constants
|
|
2
|
+
export * from './constants/InputPatterns';
|
|
3
|
+
|
|
4
|
+
//helpers
|
|
5
|
+
export * from './helpers/imeiChecksum';
|
|
6
|
+
|
|
1
7
|
//decorators
|
|
2
8
|
export * from './decorators/Trim';
|
|
9
|
+
export * from './decorators/UpperCase';
|
|
3
10
|
|
|
4
11
|
//validators
|
|
5
12
|
export * from './validators/IsStringValueRecord';
|
|
13
|
+
export * from './validators/matchesInputPattern';
|
|
14
|
+
export * from './validators/IsMxPhone';
|
|
15
|
+
export * from './validators/IsMxZipCode';
|
|
16
|
+
export * from './validators/IsRfc';
|
|
17
|
+
export * from './validators/IsSku';
|
|
6
18
|
|
|
7
19
|
//dtos
|
|
8
20
|
export * from './dtos/ProcessValidationResultDto';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ValidationOptions } from 'class-validator';
|
|
2
|
+
import { PHONE_MX_ACCEPTED_PATTERN, PHONE_MX_MESSAGE } from '../constants/InputPatterns';
|
|
3
|
+
import { matchesInputPattern } from './matchesInputPattern';
|
|
4
|
+
|
|
5
|
+
/** Teléfono MX de 10 dígitos; admite el prefijo `+52`. */
|
|
6
|
+
export const IsMxPhone = (validationOptions?: ValidationOptions): PropertyDecorator =>
|
|
7
|
+
matchesInputPattern('isMxPhone', PHONE_MX_ACCEPTED_PATTERN, PHONE_MX_MESSAGE, validationOptions);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ValidationOptions } from 'class-validator';
|
|
2
|
+
import { ZIP_CODE_MX_MESSAGE, ZIP_CODE_MX_PATTERN } from '../constants/InputPatterns';
|
|
3
|
+
import { matchesInputPattern } from './matchesInputPattern';
|
|
4
|
+
|
|
5
|
+
/** Código postal MX de 5 dígitos. */
|
|
6
|
+
export const IsMxZipCode = (validationOptions?: ValidationOptions): PropertyDecorator =>
|
|
7
|
+
matchesInputPattern('isMxZipCode', ZIP_CODE_MX_PATTERN, ZIP_CODE_MX_MESSAGE, validationOptions);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ValidationOptions } from 'class-validator';
|
|
2
|
+
import { RFC_MESSAGE, RFC_PATTERN } from '../constants/InputPatterns';
|
|
3
|
+
import { matchesInputPattern } from './matchesInputPattern';
|
|
4
|
+
|
|
5
|
+
/** RFC en mayúsculas; combínalo con `@UpperCase()` para normalizar la entrada. */
|
|
6
|
+
export const IsRfc = (validationOptions?: ValidationOptions): PropertyDecorator =>
|
|
7
|
+
matchesInputPattern('isRfc', RFC_PATTERN, RFC_MESSAGE, validationOptions);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ValidationOptions } from 'class-validator';
|
|
2
|
+
import { SKU_MAX_LENGTH, SKU_MESSAGE, SKU_PATTERN } from '../constants/InputPatterns';
|
|
3
|
+
import { matchesInputPattern } from './matchesInputPattern';
|
|
4
|
+
|
|
5
|
+
/** SKU de 1 a 64 caracteres: letras, dígitos, guiones y espacios entre palabras. */
|
|
6
|
+
export const IsSku = (validationOptions?: ValidationOptions): PropertyDecorator =>
|
|
7
|
+
matchesInputPattern('isSku', SKU_PATTERN, SKU_MESSAGE, validationOptions, SKU_MAX_LENGTH);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { ValidateBy, ValidationOptions } from 'class-validator';
|
|
2
|
+
|
|
3
|
+
/** Arma un decorador que exige un string que cumpla `pattern` y, si se da, `maxLength`. */
|
|
4
|
+
export function matchesInputPattern(
|
|
5
|
+
name: string,
|
|
6
|
+
pattern: RegExp,
|
|
7
|
+
message: string,
|
|
8
|
+
validationOptions?: ValidationOptions,
|
|
9
|
+
maxLength?: number,
|
|
10
|
+
): PropertyDecorator {
|
|
11
|
+
return ValidateBy(
|
|
12
|
+
{
|
|
13
|
+
name,
|
|
14
|
+
validator: {
|
|
15
|
+
validate: (value: unknown): boolean =>
|
|
16
|
+
typeof value === 'string' &&
|
|
17
|
+
(maxLength === undefined || value.length <= maxLength) &&
|
|
18
|
+
pattern.test(value),
|
|
19
|
+
defaultMessage: (): string => message,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
validationOptions,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PHONE_MX_PATTERN } from '../../common/constants/InputPatterns';
|
|
1
2
|
|
|
2
3
|
|
|
3
4
|
// Expresión regular para validar UUID v4
|
|
@@ -21,7 +22,7 @@ export const regexCurp =
|
|
|
21
22
|
|
|
22
23
|
// Teléfono MX: exactamente 10 dígitos (se normalizan espacios/guiones antes de validar).
|
|
23
24
|
// Usado por retailCustomer y retailWizard. SureKeep Fase 2 — pista Retail.
|
|
24
|
-
export const regexPhoneMx =
|
|
25
|
+
export const regexPhoneMx = PHONE_MX_PATTERN;
|
|
25
26
|
|
|
26
27
|
|
|
27
28
|
|
|
@@ -6,7 +6,7 @@ const SHORT_TEXT = 120;
|
|
|
6
6
|
/** Largo máximo de un texto largo del contrato (nombre, domicilio, razón social). */
|
|
7
7
|
const LONG_TEXT = 300;
|
|
8
8
|
/** IMEI: exactamente 15 dígitos. */
|
|
9
|
-
|
|
9
|
+
import { IMEI_PATTERN } from '../../common/constants/InputPatterns';
|
|
10
10
|
|
|
11
11
|
/** Datos del acreditado tal como se imprimen en el contrato (Sección II.1). */
|
|
12
12
|
export class LoanContractBorrowerDetails {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Expose } from 'class-transformer';
|
|
2
2
|
import { IsISO8601, IsInt, IsNotEmpty, IsOptional, IsPositive, IsString, Matches, Max, MaxLength } from 'class-validator';
|
|
3
|
-
import { SKU_PATTERN } from '../../retailCatalog/constants/SkuPattern';
|
|
3
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../retailCatalog/constants/SkuPattern';
|
|
4
4
|
import { CREDIT_ID_MESSAGE, CREDIT_ID_PATTERN } from '../constants/CreditIdPattern';
|
|
5
5
|
|
|
6
6
|
/** Charset y largo del IMEI: exactamente 15 dígitos. */
|
|
7
|
-
|
|
7
|
+
import { IMEI_PATTERN } from '../../common/constants/InputPatterns';
|
|
8
8
|
|
|
9
9
|
/** Plazo máximo del crédito en meses. */
|
|
10
10
|
const MAX_TERM_MONTHS = 60;
|
|
@@ -32,7 +32,7 @@ export class LoanDeviceEnrollItem {
|
|
|
32
32
|
@IsString()
|
|
33
33
|
@IsNotEmpty()
|
|
34
34
|
@MaxLength(64)
|
|
35
|
-
@Matches(SKU_PATTERN, { message:
|
|
35
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
36
36
|
productSku: string;
|
|
37
37
|
|
|
38
38
|
@Expose()
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
/** Charset
|
|
2
|
-
export
|
|
1
|
+
/** Charset del SKU: letras, dígitos, guiones y espacios entre palabras; el tope de 64 va con `@Length`. */
|
|
2
|
+
export { SKU_PATTERN, SKU_MESSAGE } from '../../common/constants/InputPatterns';
|
|
@@ -28,7 +28,8 @@ export class Product {
|
|
|
28
28
|
/** `null` = Sin gama. */
|
|
29
29
|
tier!: ProductTierEnum | null;
|
|
30
30
|
basePriceCents!: number;
|
|
31
|
-
|
|
31
|
+
/** @deprecated Ya no se usa; el único precio es `basePriceCents`. */
|
|
32
|
+
listPriceCents?: number | null;
|
|
32
33
|
eligibleFinanciers!: string[];
|
|
33
34
|
mdmEnabled!: boolean;
|
|
34
35
|
mdmProvider!: MdmProviderEnum | null;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { IsInt, IsString, Length, Matches, Min } from 'class-validator';
|
|
2
|
-
import { SKU_PATTERN } from '../constants/SkuPattern';
|
|
2
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../constants/SkuPattern';
|
|
3
3
|
|
|
4
4
|
/** Componente de un kit (BUNDLE): qué SKU consume y cuántas piezas por kit. */
|
|
5
5
|
export class ProductComponent {
|
|
6
|
-
@Matches(SKU_PATTERN, { message:
|
|
6
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
7
7
|
@Length(1, 64)
|
|
8
8
|
@IsString()
|
|
9
9
|
sku!: string;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Type } from 'class-transformer';
|
|
2
2
|
import { ArrayMinSize, IsArray, IsBoolean, IsOptional, IsString, Length, Matches, ValidateNested } from 'class-validator';
|
|
3
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
3
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
4
4
|
import { ProductComponent } from '../ProductComponent';
|
|
5
5
|
|
|
6
6
|
/** Body de POST /backoffice/catalog/kits (backofficeCreateKit); category BUNDLE y origen BACKOFFICE los fija el servidor. */
|
|
7
7
|
export class BackofficeCreateKitRequest {
|
|
8
|
-
@Matches(SKU_PATTERN, { message:
|
|
8
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
9
9
|
@Length(1, 64)
|
|
10
10
|
@IsString()
|
|
11
11
|
sku!: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IsArray, IsBoolean, IsEnum, IsIn, IsInt, IsISO8601, IsObject, IsOptional, IsString, Length, Matches, Max, Min, Validate, ValidateIf } from 'class-validator';
|
|
2
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
2
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
3
3
|
import { NON_BUNDLE_CATEGORIES } from '../../constants/NonBundleCategories';
|
|
4
4
|
import { ProductCategoryEnum } from '../../enums/ProductCategoryEnum';
|
|
5
5
|
import { AccessorySubcategoryEnum } from '../../enums/AccessorySubcategoryEnum';
|
|
@@ -11,7 +11,7 @@ import { IsMdmCoherentConstraint } from '../../validators/IsMdmCoherentConstrain
|
|
|
11
11
|
|
|
12
12
|
/** Body de POST /backoffice/catalog/products (backofficeCreateProduct); itemType PRODUCT y origen BACKOFFICE los fija el servidor. */
|
|
13
13
|
export class BackofficeCreateProductRequest {
|
|
14
|
-
@Matches(SKU_PATTERN, { message:
|
|
14
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
15
15
|
@Length(1, 64)
|
|
16
16
|
@IsString()
|
|
17
17
|
sku!: string;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { IsBoolean, IsOptional, IsString, Length, Matches } from 'class-validator';
|
|
2
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
2
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
3
3
|
|
|
4
4
|
/** Body de POST /backoffice/catalog/services (backofficeCreateService); itemType SERVICE y trackingMode QUANTITY los fija el servidor. */
|
|
5
5
|
export class BackofficeCreateServiceRequest {
|
|
6
|
-
@Matches(SKU_PATTERN, { message:
|
|
6
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
7
7
|
@Length(1, 64)
|
|
8
8
|
@IsString()
|
|
9
9
|
sku!: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArrayMinSize, ArrayUnique, IsArray, IsInt, IsOptional, IsString, Length, Matches, Min } from 'class-validator';
|
|
2
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
2
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
3
3
|
|
|
4
4
|
/** Body de POST /backoffice/inventory/transfers (backofficeCreateTransfer); origen = destino lo rechaza el dominio. */
|
|
5
5
|
export class BackofficeCreateTransferRequest {
|
|
@@ -11,7 +11,7 @@ export class BackofficeCreateTransferRequest {
|
|
|
11
11
|
@IsString()
|
|
12
12
|
toStoreId!: string;
|
|
13
13
|
|
|
14
|
-
@Matches(SKU_PATTERN, { message:
|
|
14
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
15
15
|
@Length(1, 64)
|
|
16
16
|
@IsString()
|
|
17
17
|
sku!: string;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ArrayMinSize, ArrayUnique, IsArray, IsIn, IsInt, IsOptional, IsString, Length, Matches, Min } from 'class-validator';
|
|
2
2
|
import { ADJUSTMENT_REASONS } from '../../constants/AdjustmentReasons';
|
|
3
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
3
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
4
4
|
import { InventoryMovementReasonEnum } from '../../enums/InventoryMovementReasonEnum';
|
|
5
5
|
|
|
6
6
|
/** Body de POST /backoffice/inventory/adjustments (backofficeRegisterAdjustment); resta del disponible con motivo. */
|
|
@@ -10,7 +10,7 @@ export class BackofficeRegisterAdjustmentRequest {
|
|
|
10
10
|
@IsString()
|
|
11
11
|
storeId!: string;
|
|
12
12
|
|
|
13
|
-
@Matches(SKU_PATTERN, { message:
|
|
13
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
14
14
|
@Length(1, 64)
|
|
15
15
|
@IsString()
|
|
16
16
|
sku!: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ArrayMinSize, ArrayUnique, IsArray, IsEnum, IsInt, IsOptional, IsString, Length, Matches, Min } from 'class-validator';
|
|
2
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
2
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
3
3
|
import { InventoryMovementReasonEnum } from '../../enums/InventoryMovementReasonEnum';
|
|
4
4
|
|
|
5
5
|
/** Body de POST /backoffice/inventory/entries (backofficeRegisterEntry); suma al saldo de la tienda con un MOV# ENTRY. */
|
|
@@ -9,7 +9,7 @@ export class BackofficeRegisterEntryRequest {
|
|
|
9
9
|
@IsString()
|
|
10
10
|
storeId!: string;
|
|
11
11
|
|
|
12
|
-
@Matches(SKU_PATTERN, { message:
|
|
12
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
13
13
|
@Length(1, 64)
|
|
14
14
|
@IsString()
|
|
15
15
|
sku!: string;
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
Min,
|
|
12
12
|
Validate,
|
|
13
13
|
} from 'class-validator';
|
|
14
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
14
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
15
15
|
import { MdmLockModeEnum } from '../../enums/MdmLockModeEnum';
|
|
16
16
|
import { MdmProviderEnum } from '../../enums/MdmProviderEnum';
|
|
17
17
|
import { ProductTierEnum } from '../../enums/ProductTierEnum';
|
|
@@ -22,7 +22,7 @@ import { IsMdmCoherentConstraint } from '../../validators/IsMdmCoherentConstrain
|
|
|
22
22
|
* @deprecated Modelo viejo por IMEI; usar BackofficeCreateProductRequest. Se conserva porque otras ramas lo importan.
|
|
23
23
|
*/
|
|
24
24
|
export class CreateProductRequest {
|
|
25
|
-
@Matches(SKU_PATTERN, { message:
|
|
25
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
26
26
|
@Length(1, 64)
|
|
27
27
|
@IsString()
|
|
28
28
|
sku!: string;
|
|
@@ -61,6 +61,7 @@ export class CreateProductRequest {
|
|
|
61
61
|
@Min(0)
|
|
62
62
|
basePriceCents!: number;
|
|
63
63
|
|
|
64
|
+
/** @deprecated Ya no se usa; el único precio es `basePriceCents`. */
|
|
64
65
|
@IsOptional()
|
|
65
66
|
@IsInt()
|
|
66
67
|
@Min(0)
|
|
@@ -10,14 +10,14 @@ import {
|
|
|
10
10
|
Validate,
|
|
11
11
|
ValidateIf,
|
|
12
12
|
} from 'class-validator';
|
|
13
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
13
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
14
14
|
import { ReturnConditionEnum } from '../../enums/ReturnConditionEnum';
|
|
15
15
|
import { IsPieceRefConstraint } from '../../validators/IsPieceRefConstraint';
|
|
16
16
|
|
|
17
17
|
/** Condición de una pieza devuelta; ausente = GOOD. Un accesorio por cantidad se declara con sku + qty. */
|
|
18
18
|
export class ReturnPieceCondition {
|
|
19
19
|
@Expose()
|
|
20
|
-
@Matches(SKU_PATTERN, { message:
|
|
20
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
21
21
|
@Length(1, 64)
|
|
22
22
|
@IsString()
|
|
23
23
|
sku!: string;
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
Min,
|
|
13
13
|
ValidateNested,
|
|
14
14
|
} from 'class-validator';
|
|
15
|
-
import { SKU_PATTERN } from '../../constants/SkuPattern';
|
|
15
|
+
import { SKU_MESSAGE, SKU_PATTERN } from '../../constants/SkuPattern';
|
|
16
16
|
import { MdmLockModeEnum } from '../../enums/MdmLockModeEnum';
|
|
17
17
|
import { MdmProviderEnum } from '../../enums/MdmProviderEnum';
|
|
18
18
|
import { ProductCategoryEnum } from '../../enums/ProductCategoryEnum';
|
|
@@ -22,6 +22,7 @@ import { ProductComponent } from '../ProductComponent';
|
|
|
22
22
|
|
|
23
23
|
/** Precio de un producto en la puerta de entrada; crea PRICE# solo si cambió el monto. */
|
|
24
24
|
export class SyncPrice {
|
|
25
|
+
/** @deprecated Ya no se usa; el único precio es `basePriceCents`. */
|
|
25
26
|
@IsOptional()
|
|
26
27
|
@IsInt()
|
|
27
28
|
@Min(0)
|
|
@@ -37,7 +38,7 @@ export class SyncPrice {
|
|
|
37
38
|
|
|
38
39
|
/** Producto tal como llega de Zentral. */
|
|
39
40
|
export class SyncProduct {
|
|
40
|
-
@Matches(SKU_PATTERN, { message:
|
|
41
|
+
@Matches(SKU_PATTERN, { message: SKU_MESSAGE })
|
|
41
42
|
@Length(1, 64)
|
|
42
43
|
@IsString()
|
|
43
44
|
sku!: string;
|
|
@@ -69,7 +69,7 @@ export interface InventoryLensSkuItem {
|
|
|
69
69
|
/** Unidades de este SKU vendidas hoy en esta tienda, **financiadas por SureKeep**. */
|
|
70
70
|
soldTodayUnits: number;
|
|
71
71
|
|
|
72
|
-
/** Precio de contado en centavos (`
|
|
72
|
+
/** Precio de contado en centavos (`basePriceCents`). */
|
|
73
73
|
cashPriceCents: number;
|
|
74
74
|
}
|
|
75
75
|
|
|
@@ -16,7 +16,10 @@ export interface ReservedComponent {
|
|
|
16
16
|
export interface ReserveStockResponse {
|
|
17
17
|
expiresAt: string;
|
|
18
18
|
basePriceCents: number;
|
|
19
|
-
|
|
19
|
+
/** @deprecated Usa `giftValueCents`; en reservas GIFT trae el mismo valor, en las demás `null`. */
|
|
20
|
+
listPriceCents?: number | null;
|
|
21
|
+
/** Solo en reservas `purpose: GIFT`: valor del regalo, su precio de venta. */
|
|
22
|
+
giftValueCents?: number;
|
|
20
23
|
/** Llave del registro PRICE# del que salió el precio fijado. */
|
|
21
24
|
priceSk: string;
|
|
22
25
|
eligibleFinanciers: string[];
|
|
@@ -3,7 +3,8 @@ import type { PriceSourceEnum } from '../../enums/PriceSourceEnum';
|
|
|
3
3
|
/** Un registro del historial de precios PRICE# de un SKU. */
|
|
4
4
|
export interface SkuPriceEntry {
|
|
5
5
|
effectiveFrom: string;
|
|
6
|
-
|
|
6
|
+
/** @deprecated Ya no se usa; el único precio es `basePriceCents`. */
|
|
7
|
+
listPriceCents?: number | null;
|
|
7
8
|
basePriceCents: number;
|
|
8
9
|
source: PriceSourceEnum;
|
|
9
10
|
createdBy: string;
|
|
@@ -38,7 +38,7 @@ export interface StoreCatalogItem {
|
|
|
38
38
|
itemType?: ItemTypeEnum;
|
|
39
39
|
/** Nombre visible para kits y servicios, que no tienen marca/modelo. */
|
|
40
40
|
description?: string;
|
|
41
|
-
/**
|
|
41
|
+
/** @deprecated Ya no se usa; el valor de un regalo es `basePriceCents`. */
|
|
42
42
|
listPriceCents?: number;
|
|
43
43
|
/** Prioridad de venta de 0 a 100; «Recomendados» ordena por ella. */
|
|
44
44
|
salePriority?: number;
|
|
@@ -21,8 +21,8 @@ export const RETAIL_STORE_CODE_MAX_LENGTH = 10;
|
|
|
21
21
|
export const RETAIL_ZIP_CODE_MIN_LENGTH = 4;
|
|
22
22
|
export const RETAIL_ZIP_CODE_MAX_LENGTH = 10;
|
|
23
23
|
|
|
24
|
-
/** SKU del catálogo del retailer. */
|
|
25
|
-
export const RETAIL_SKU_PATTERN = /^[A-Za-z0-9-]
|
|
24
|
+
/** SKU del catálogo del retailer: el charset de `SKU_PATTERN` con tope de 64. */
|
|
25
|
+
export const RETAIL_SKU_PATTERN = /^(?=.{1,64}$)[A-Za-z0-9-]+(?: +[A-Za-z0-9-]+)*$/;
|
|
26
26
|
|
|
27
27
|
/** Decimal del contrato: string con dos decimales, nunca negativo. */
|
|
28
28
|
export const RETAIL_DECIMAL_PATTERN = /^\d+\.\d{2}$/;
|
|
@@ -2,6 +2,7 @@ import { Expose } from 'class-transformer';
|
|
|
2
2
|
import { IsArray, IsEnum, IsOptional, IsString } from 'class-validator';
|
|
3
3
|
import { CollectorSeniorityEnum } from '../../enums/CollectorSeniorityEnum';
|
|
4
4
|
import { EmploymentTypeEnum } from '../../enums/EmploymentTypeEnum';
|
|
5
|
+
import { IsMxPhone } from '../../../common/validators/IsMxPhone';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Body de POST /retailers/:retailerId/users — alta de usuario retail (el `retailerId` sale del path;
|
|
@@ -42,7 +43,7 @@ export class CreateRetailUserRequest {
|
|
|
42
43
|
/** Teléfono de contacto del usuario retail; opcional. */
|
|
43
44
|
@Expose()
|
|
44
45
|
@IsOptional()
|
|
45
|
-
@
|
|
46
|
+
@IsMxPhone()
|
|
46
47
|
phone?: string;
|
|
47
48
|
|
|
48
49
|
/** Seniority del cobrador; solo aplica a usuarios retail con rol de cobrador. */
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Expose, Type } from 'class-transformer';
|
|
2
|
-
import { IsDefined, IsEmail, IsEnum, IsString,
|
|
2
|
+
import { IsDefined, IsEmail, IsEnum, IsString, ValidateNested } from 'class-validator';
|
|
3
3
|
import { RetailerTypeEnum } from '../../enums/RetailerTypeEnum';
|
|
4
4
|
import { RetailAddressInput } from './RetailAddressInput';
|
|
5
|
+
import { IsMxPhone } from '../../../common/validators/IsMxPhone';
|
|
6
|
+
import { IsRfc } from '../../../common/validators/IsRfc';
|
|
7
|
+
import { UpperCase } from '../../../common/decorators/UpperCase';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Body de POST /retailers — alta de un retailer raíz (SureKeep Fase 1 — pista Retail).
|
|
@@ -21,10 +24,11 @@ export class CreateRetailerRequest {
|
|
|
21
24
|
@IsString()
|
|
22
25
|
legalName!: string;
|
|
23
26
|
|
|
24
|
-
/** RFC
|
|
27
|
+
/** RFC — 12 (persona moral) o 13 (persona física); se pasa a mayúsculas antes de validar. */
|
|
25
28
|
@Expose()
|
|
26
29
|
@IsString()
|
|
27
|
-
@
|
|
30
|
+
@UpperCase()
|
|
31
|
+
@IsRfc()
|
|
28
32
|
rfc!: string;
|
|
29
33
|
|
|
30
34
|
@Expose()
|
|
@@ -32,7 +36,7 @@ export class CreateRetailerRequest {
|
|
|
32
36
|
contactEmail!: string;
|
|
33
37
|
|
|
34
38
|
@Expose()
|
|
35
|
-
@
|
|
39
|
+
@IsMxPhone()
|
|
36
40
|
contactPhone!: string;
|
|
37
41
|
|
|
38
42
|
@Expose()
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from 'class-validator';
|
|
10
10
|
import { GeoLocation } from '../GeoLocation';
|
|
11
11
|
import { RetailAddressInput } from './RetailAddressInput';
|
|
12
|
+
import { IsMxPhone } from '../../../common/validators/IsMxPhone';
|
|
12
13
|
|
|
13
14
|
/**
|
|
14
15
|
* Body de POST /retailers/:retailerId/stores — alta de tienda física (el `retailerId` sale del path).
|
|
@@ -44,7 +45,7 @@ export class CreateStoreRequest {
|
|
|
44
45
|
location!: GeoLocation;
|
|
45
46
|
|
|
46
47
|
@Expose()
|
|
47
|
-
@
|
|
48
|
+
@IsMxPhone()
|
|
48
49
|
phone!: string;
|
|
49
50
|
|
|
50
51
|
/** Usuario retail responsable; `null` si no hay gerente asignado. */
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { Expose, Type } from 'class-transformer';
|
|
2
|
-
import { IsDefined, IsEmail, IsIn, IsString,
|
|
2
|
+
import { IsDefined, IsEmail, IsIn, IsString, ValidateNested } from 'class-validator';
|
|
3
3
|
import { RetailerTypeEnum } from '../../enums/RetailerTypeEnum';
|
|
4
4
|
import { RetailAddressInput } from './RetailAddressInput';
|
|
5
|
+
import { IsMxPhone } from '../../../common/validators/IsMxPhone';
|
|
6
|
+
import { IsRfc } from '../../../common/validators/IsRfc';
|
|
7
|
+
import { UpperCase } from '../../../common/decorators/UpperCase';
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* Body de POST /retailers/:retailerId/subdistributors — alta de un retailer hijo colgando de
|
|
@@ -23,10 +26,11 @@ export class CreateSubdistributorRequest {
|
|
|
23
26
|
@IsString()
|
|
24
27
|
legalName!: string;
|
|
25
28
|
|
|
26
|
-
/** RFC
|
|
29
|
+
/** RFC — 12 (persona moral) o 13 (persona física); se pasa a mayúsculas antes de validar. */
|
|
27
30
|
@Expose()
|
|
28
31
|
@IsString()
|
|
29
|
-
@
|
|
32
|
+
@UpperCase()
|
|
33
|
+
@IsRfc()
|
|
30
34
|
rfc!: string;
|
|
31
35
|
|
|
32
36
|
@Expose()
|
|
@@ -34,7 +38,7 @@ export class CreateSubdistributorRequest {
|
|
|
34
38
|
contactEmail!: string;
|
|
35
39
|
|
|
36
40
|
@Expose()
|
|
37
|
-
@
|
|
41
|
+
@IsMxPhone()
|
|
38
42
|
contactPhone!: string;
|
|
39
43
|
|
|
40
44
|
@Expose()
|
|
@@ -3,6 +3,7 @@ import { IsArray, IsEmail, IsEnum, IsOptional, IsString } from 'class-validator'
|
|
|
3
3
|
import { CollectorSeniorityEnum } from '../../enums/CollectorSeniorityEnum';
|
|
4
4
|
import { EmploymentTypeEnum } from '../../enums/EmploymentTypeEnum';
|
|
5
5
|
import { PermissionScope } from '../../../platformRbac/enums/PermissionScope';
|
|
6
|
+
import { IsMxPhone } from '../../../common/validators/IsMxPhone';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Body de POST /retailers/:retailerId/users/provision — alta de usuario retail ORQUESTADA (SureKeep F1,
|
|
@@ -64,7 +65,7 @@ export class ProvisionRetailUserRequest {
|
|
|
64
65
|
/** Teléfono de contacto del usuario retail; opcional. */
|
|
65
66
|
@Expose()
|
|
66
67
|
@IsOptional()
|
|
67
|
-
@
|
|
68
|
+
@IsMxPhone()
|
|
68
69
|
phone?: string;
|
|
69
70
|
|
|
70
71
|
/** Seniority del cobrador; solo aplica a usuarios retail con rol de cobrador. */
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Expose } from 'class-transformer';
|
|
2
2
|
import { IsOptional, IsString, Length } from 'class-validator';
|
|
3
|
+
import { IsMxZipCode } from '../../../common/validators/IsMxZipCode';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Dirección comercial de entrada (input validado) para los requests de creación/edición del dominio
|
|
@@ -53,10 +54,9 @@ export class RetailAddressInput {
|
|
|
53
54
|
@Length(1, 150)
|
|
54
55
|
state!: string;
|
|
55
56
|
|
|
56
|
-
/** Código postal (espejo de `LocationAddress.zipCode`). */
|
|
57
|
+
/** Código postal MX de 5 dígitos (espejo de `LocationAddress.zipCode`). */
|
|
57
58
|
@Expose()
|
|
58
|
-
@
|
|
59
|
-
@Length(4, 10)
|
|
59
|
+
@IsMxZipCode()
|
|
60
60
|
zipCode!: string;
|
|
61
61
|
|
|
62
62
|
/** País ISO. OPCIONAL — sin slot en `LocationAddress` (TD-SKF1-007). */
|
|
@@ -2,6 +2,7 @@ import { Expose } from 'class-transformer';
|
|
|
2
2
|
import { IsArray, IsEnum, IsOptional, IsString } from 'class-validator';
|
|
3
3
|
import { CollectorSeniorityEnum } from '../../enums/CollectorSeniorityEnum';
|
|
4
4
|
import { EmploymentTypeEnum } from '../../enums/EmploymentTypeEnum';
|
|
5
|
+
import { IsMxPhone } from '../../../common/validators/IsMxPhone';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* Body de PUT /users/:retailUserId — edición de usuario retail (campos editables opcionales).
|
|
@@ -33,7 +34,7 @@ export class UpdateRetailUserRequest {
|
|
|
33
34
|
/** Teléfono de contacto del usuario retail; opcional. */
|
|
34
35
|
@Expose()
|
|
35
36
|
@IsOptional()
|
|
36
|
-
@
|
|
37
|
+
@IsMxPhone()
|
|
37
38
|
phone?: string;
|
|
38
39
|
|
|
39
40
|
/** Seniority del cobrador; solo aplica a usuarios retail con rol de cobrador. */
|