@fiado/type-kit 3.601.0 → 3.603.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 (38) hide show
  1. package/_test_/unit/retailIntegration/retailSaleContracts.test.ts +162 -10
  2. package/_test_/unit/retailIntegration/retailSystemEnums.test.ts +3 -1
  3. package/bin/collection/dtos/AuthorizeCollectionMovementRequest.d.ts +7 -0
  4. package/bin/collection/dtos/AuthorizeCollectionMovementRequest.js +5 -0
  5. package/bin/retailIntegration/constants/retailIntegrationLimits.d.ts +15 -0
  6. package/bin/retailIntegration/constants/retailIntegrationLimits.js +16 -1
  7. package/bin/retailIntegration/dtos/CancelRetailSaleRequest.d.ts +7 -0
  8. package/bin/retailIntegration/dtos/CancelRetailSaleRequest.js +34 -1
  9. package/bin/retailIntegration/enums/RetailPaymentFrequencyEnum.d.ts +6 -0
  10. package/bin/retailIntegration/enums/RetailPaymentFrequencyEnum.js +10 -0
  11. package/bin/retailIntegration/enums/RetailPaymentMethodEnum.d.ts +3 -2
  12. package/bin/retailIntegration/enums/RetailPaymentMethodEnum.js +3 -2
  13. package/bin/retailIntegration/enums/index.d.ts +1 -0
  14. package/bin/retailIntegration/enums/index.js +1 -0
  15. package/bin/retailIntegration/index.d.ts +2 -0
  16. package/bin/retailIntegration/index.js +2 -0
  17. package/bin/retailIntegration/models/RetailSystemSale.d.ts +23 -2
  18. package/bin/retailIntegration/models/RetailSystemSale.js +89 -11
  19. package/bin/retailIntegration/validators/IsCalendarDate.d.ts +6 -0
  20. package/bin/retailIntegration/validators/IsCalendarDate.js +25 -0
  21. package/bin/retailIntegration/validators/IsIsoDateTimeWithZone.js +2 -6
  22. package/bin/retailIntegration/validators/calendarDate.d.ts +2 -0
  23. package/bin/retailIntegration/validators/calendarDate.js +8 -0
  24. package/bin/retailIntegration/validators/saleValidators.d.ts +26 -0
  25. package/bin/retailIntegration/validators/saleValidators.js +100 -0
  26. package/package.json +1 -1
  27. package/src/collection/dtos/AuthorizeCollectionMovementRequest.ts +9 -1
  28. package/src/retailIntegration/constants/retailIntegrationLimits.ts +22 -0
  29. package/src/retailIntegration/dtos/CancelRetailSaleRequest.ts +14 -2
  30. package/src/retailIntegration/enums/RetailPaymentFrequencyEnum.ts +6 -0
  31. package/src/retailIntegration/enums/RetailPaymentMethodEnum.ts +3 -2
  32. package/src/retailIntegration/enums/index.ts +1 -0
  33. package/src/retailIntegration/index.ts +2 -0
  34. package/src/retailIntegration/models/RetailSystemSale.ts +57 -10
  35. package/src/retailIntegration/validators/IsCalendarDate.ts +16 -0
  36. package/src/retailIntegration/validators/IsIsoDateTimeWithZone.ts +1 -6
  37. package/src/retailIntegration/validators/calendarDate.ts +5 -0
  38. package/src/retailIntegration/validators/saleValidators.ts +80 -0
@@ -23,6 +23,12 @@ async function errorsOf(cls: new () => object, plain: object): Promise<string[]>
23
23
  return paths(await validate(plainToInstance(cls, plain)));
24
24
  }
25
25
 
26
+ const cashPayment = { method: 'CASH', amount: '400.00', cardLast4: null, authCode: null, speiTrackingKey: null, senderClabe: null } as const;
27
+ const cardPayment = { method: 'CARD', amount: '200.00', cardLast4: '4242', authCode: 'A1B2C3', speiTrackingKey: null, senderClabe: null } as const;
28
+ const wirePayment = {
29
+ method: 'WIRE', amount: '200.00', cardLast4: null, authCode: null, speiTrackingKey: '123456789012345678', senderClabe: '012180001234567897',
30
+ } as const;
31
+
26
32
  // Literal tipado: prueba en compilación que la clase sigue aceptando objetos planos.
27
33
  const sale: RetailSystemSale = {
28
34
  saleId: '7f0c2a52-1b7e-4f0e-9d7a-2a1d3c4b5e6f',
@@ -33,30 +39,39 @@ const sale: RetailSystemSale = {
33
39
  saleType: 'CREDIT',
34
40
  financier: 'SUREKEEP',
35
41
  creditId: 'CR-991',
42
+ credit: {
43
+ paymentFrequency: 'WEEKLY', installments: 16, installmentAmount: '260.67', downPayment: '600.00', totalToPay: '4170.72', firstPaymentDate: '2026-10-30',
44
+ },
36
45
  currencyId: 'MXN',
37
46
  customer: { customerId: 'C-1', names: 'Ana', paternalLastName: 'López', maternalLastName: null, phone: '7221234567' },
38
47
  equipmentPrice: '5999.00',
39
48
  amountPaid: '600.00',
40
- paymentMethod: 'CASH',
49
+ payments: [cashPayment, cardPayment],
41
50
  lines: [
42
51
  {
43
52
  lineId: 'L1', sku: 'IPH-15', qty: 1, basePrice: '5999.00', discount: '0.00', paymentType: 'CREDIT',
44
- financedAmount: '5399.00', role: null, components: [{ sku: 'IPH-15', qty: 1, identifiers: ['356789012345678'] }],
53
+ financedAmount: '5399.00', role: null, promotionId: null, components: [{ sku: 'IPH-15', qty: 1, identifiers: ['356789012345678'] }],
45
54
  },
46
55
  {
47
56
  lineId: 'L2', sku: 'FUNDA-1', qty: 1, basePrice: '0.00', discount: '0.00', paymentType: 'CASH',
48
- financedAmount: '0.00', role: 'GIFT', components: [],
57
+ financedAmount: '0.00', role: 'GIFT', promotionId: 'PRM-0012', components: [],
49
58
  },
50
59
  ],
51
60
  };
52
61
 
62
+ const cashSale = { ...sale, saleType: 'CASH', financier: 'NONE', creditId: null, credit: null };
63
+
53
64
  describe('RetailSystemSale (body de privateRegisterRetailSale)', () => {
54
- it('acepta una venta completa', async () => {
65
+ it('acepta una venta a crédito SureKeep completa', async () => {
55
66
  expect(await errorsOf(RetailSystemSale, sale)).toEqual([]);
56
67
  });
57
68
 
58
- it('acepta los nullables en null', async () => {
59
- expect(await errorsOf(RetailSystemSale, { ...sale, creditId: null, paymentMethod: null })).toEqual([]);
69
+ it('acepta una venta de contado con creditId y credit en null', async () => {
70
+ expect(await errorsOf(RetailSystemSale, cashSale)).toEqual([]);
71
+ });
72
+
73
+ it('acepta una referida sin creditId ni credit', async () => {
74
+ expect(await errorsOf(RetailSystemSale, { ...sale, financier: 'PAYJOY', creditId: null, credit: null })).toEqual([]);
60
75
  });
61
76
 
62
77
  it.each([
@@ -67,14 +82,19 @@ describe('RetailSystemSale (body de privateRegisterRetailSale)', () => {
67
82
  ['financier', { financier: 'OTRO' }],
68
83
  ['currencyId', { currencyId: 'EUR' }],
69
84
  ['equipmentPrice', { equipmentPrice: '5999' }],
70
- ['amountPaid', { amountPaid: '-1.00' }],
71
- ['paymentMethod', { paymentMethod: 'BITCOIN' }],
85
+ ['equipmentPrice', { equipmentPrice: '1234567890123.00' }],
72
86
  ['creditId', { creditId: undefined }],
87
+ ['credit', { credit: undefined }],
88
+ ['payments', { payments: undefined }],
73
89
  ['lines', { lines: [] }],
74
90
  ])('rechaza %s inválido', async (field, patch) => {
75
91
  expect(await errorsOf(RetailSystemSale, { ...sale, ...patch })).toEqual([field]);
76
92
  });
77
93
 
94
+ it.each(['722123456', '72212345678', '+527221234567', '722-123-4567'])('rechaza customer.phone %s', async (phone) => {
95
+ expect(await errorsOf(RetailSystemSale, { ...sale, customer: { ...sale.customer, phone } })).toEqual(['customer.phone']);
96
+ });
97
+
78
98
  it('valida el cliente anidado', async () => {
79
99
  expect(await errorsOf(RetailSystemSale, { ...sale, customer: { ...sale.customer, names: '' } })).toEqual(['customer.names']);
80
100
  });
@@ -90,11 +110,130 @@ describe('RetailSystemSale (body de privateRegisterRetailSale)', () => {
90
110
  });
91
111
  });
92
112
 
113
+ describe('RetailSystemSale.credit', () => {
114
+ it('SUREKEEP exige credit y creditId', async () => {
115
+ expect(await errorsOf(RetailSystemSale, { ...sale, credit: null })).toEqual(['financier']);
116
+ expect(await errorsOf(RetailSystemSale, { ...sale, creditId: null })).toEqual(['financier']);
117
+ });
118
+
119
+ it('contado exige credit y creditId en null', async () => {
120
+ expect(await errorsOf(RetailSystemSale, { ...cashSale, credit: sale.credit })).toEqual(['financier']);
121
+ expect(await errorsOf(RetailSystemSale, { ...cashSale, creditId: 'CR-1' })).toEqual(['financier']);
122
+ });
123
+
124
+ it.each([
125
+ ['paymentFrequency', { paymentFrequency: 'DAILY' }],
126
+ ['installments', { installments: 0 }],
127
+ ['installments', { installments: 1.5 }],
128
+ ['installmentAmount', { installmentAmount: '260.6' }],
129
+ ['downPayment', { downPayment: undefined }],
130
+ ['totalToPay', { totalToPay: '1234567890123.00' }],
131
+ ['firstPaymentDate', { firstPaymentDate: '2026-02-30' }],
132
+ ['firstPaymentDate', { firstPaymentDate: '2026-10-30T00:00:00Z' }],
133
+ ])('rechaza credit.%s inválido', async (field, patch) => {
134
+ expect(await errorsOf(RetailSystemSale, { ...sale, credit: { ...sale.credit, ...patch } })).toEqual([`credit.${field}`]);
135
+ });
136
+ });
137
+
138
+ describe('RetailSystemSale.payments', () => {
139
+ it('acepta [] cuando amountPaid es 0.00', async () => {
140
+ expect(await errorsOf(RetailSystemSale, { ...sale, amountPaid: '0.00', payments: [] })).toEqual([]);
141
+ });
142
+
143
+ it('acepta WIRE con y sin senderClabe', async () => {
144
+ expect(await errorsOf(RetailSystemSale, { ...sale, payments: [cashPayment, wirePayment] })).toEqual([]);
145
+ expect(await errorsOf(RetailSystemSale, { ...sale, payments: [cashPayment, { ...wirePayment, senderClabe: null }] })).toEqual([]);
146
+ });
147
+
148
+ it('acepta FIADO sin detalle', async () => {
149
+ expect(await errorsOf(RetailSystemSale, { ...sale, payments: [{ ...cashPayment, method: 'FIADO', amount: '600.00' }] })).toEqual([]);
150
+ });
151
+
152
+ it('rechaza que la suma no cuadre con amountPaid', async () => {
153
+ expect(await errorsOf(RetailSystemSale, { ...sale, payments: [cashPayment] })).toEqual(['payments']);
154
+ expect(await errorsOf(RetailSystemSale, { ...sale, payments: [] })).toEqual(['payments']);
155
+ });
156
+
157
+ it.each([
158
+ ['method', { method: 'SPEI' }],
159
+ ['amount', { amount: '0.00' }],
160
+ ['amount', { amount: '400' }],
161
+ ['cardLast4', { cardLast4: '4242' }],
162
+ ['cardLast4', { cardLast4: undefined }],
163
+ ['authCode', { authCode: 'X' }],
164
+ ['speiTrackingKey', { speiTrackingKey: undefined }],
165
+ ['senderClabe', { senderClabe: undefined }],
166
+ ])('rechaza %s fuera de regla en CASH', async (field, patch) => {
167
+ const payments = [{ ...cashPayment, ...patch }, cardPayment];
168
+ expect(await errorsOf(RetailSystemSale, { ...sale, payments })).toEqual([`payments.0.${field}`]);
169
+ });
170
+
171
+ it.each([
172
+ ['cardLast4', { cardLast4: null }],
173
+ ['cardLast4', { cardLast4: '424' }],
174
+ ['authCode', { authCode: null }],
175
+ ['authCode', { authCode: ' ' }],
176
+ ['authCode', { authCode: 'A'.repeat(65) }],
177
+ ['speiTrackingKey', { speiTrackingKey: '123456789012345678' }],
178
+ ])('rechaza %s fuera de regla en CARD', async (field, patch) => {
179
+ const payments = [cashPayment, { ...cardPayment, ...patch }];
180
+ expect(await errorsOf(RetailSystemSale, { ...sale, payments })).toEqual([`payments.1.${field}`]);
181
+ });
182
+
183
+ it.each([
184
+ ['speiTrackingKey', { speiTrackingKey: null }],
185
+ ['speiTrackingKey', { speiTrackingKey: '12345' }],
186
+ ['senderClabe', { senderClabe: '0121' }],
187
+ ['cardLast4', { cardLast4: '4242' }],
188
+ ])('rechaza %s fuera de regla en WIRE', async (field, patch) => {
189
+ const payments = [cashPayment, { ...wirePayment, ...patch }];
190
+ expect(await errorsOf(RetailSystemSale, { ...sale, payments })).toEqual([`payments.1.${field}`]);
191
+ });
192
+ });
193
+
194
+ describe('RetailSystemSale.lines[].promotionId', () => {
195
+ it('la llave es obligatoria aunque sea null', async () => {
196
+ const lines = [{ ...sale.lines[0], promotionId: undefined }, sale.lines[1]];
197
+ expect(await errorsOf(RetailSystemSale, { ...sale, lines })).toEqual(['lines.0.promotionId']);
198
+ });
199
+
200
+ it('acepta una promoción en una línea con descuento', async () => {
201
+ const lines = [{ ...sale.lines[0], discount: '500.00', promotionId: 'PRM-1' }, sale.lines[1]];
202
+ expect(await errorsOf(RetailSystemSale, { ...sale, lines })).toEqual([]);
203
+ });
204
+
205
+ it.each([
206
+ ['vacío', ' '],
207
+ ['más de 64', 'P'.repeat(65)],
208
+ ])('rechaza promotionId %s', async (_case, promotionId) => {
209
+ const lines = [{ ...sale.lines[0], promotionId }, sale.lines[1]];
210
+ expect(await errorsOf(RetailSystemSale, { ...sale, lines })).toEqual(['lines.0.promotionId']);
211
+ });
212
+
213
+ it('un regalo exige promotionId', async () => {
214
+ const lines = [sale.lines[0], { ...sale.lines[1], promotionId: null }];
215
+ expect(await errorsOf(RetailSystemSale, { ...sale, lines })).toEqual(['lines.1.promotionId']);
216
+ });
217
+ });
218
+
93
219
  describe('CancelRetailSaleRequest', () => {
94
- const cancel = { saleId: sale.saleId, cancelledAt: '2026-10-25T19:00:00-06:00', reason: 'Cliente desistió' };
220
+ const cancel: CancelRetailSaleRequest = {
221
+ saleId: sale.saleId,
222
+ cancelledAt: '2026-10-25T19:00:00-06:00',
223
+ reason: 'Cliente desistió',
224
+ damaged: [
225
+ { sku: 'IPH-15', identifier: '356789012345678', qty: 1 },
226
+ { sku: 'FUNDA-1', identifier: null, qty: 3 },
227
+ ],
228
+ };
95
229
 
96
- it('acepta la cancelación', async () => {
230
+ it('acepta la cancelación con y sin dañados', async () => {
97
231
  expect(await errorsOf(CancelRetailSaleRequest, cancel)).toEqual([]);
232
+ expect(await errorsOf(CancelRetailSaleRequest, { ...cancel, damaged: [] })).toEqual([]);
233
+ });
234
+
235
+ it('acepta reason de 200 caracteres', async () => {
236
+ expect(await errorsOf(CancelRetailSaleRequest, { ...cancel, reason: 'r'.repeat(200) })).toEqual([]);
98
237
  });
99
238
 
100
239
  it.each([
@@ -102,10 +241,23 @@ describe('CancelRetailSaleRequest', () => {
102
241
  ['cancelledAt', { cancelledAt: '2026-02-31T10:00:00Z' }],
103
242
  ['reason', { reason: '' }],
104
243
  ['reason', { reason: undefined }],
244
+ ['reason', { reason: 'r'.repeat(201) }],
245
+ ['damaged', { damaged: undefined }],
105
246
  ])('rechaza %s inválido', async (field, patch) => {
106
247
  expect(await errorsOf(CancelRetailSaleRequest, { ...cancel, ...patch })).toEqual([field]);
107
248
  });
108
249
 
250
+ it.each([
251
+ ['sku', { sku: 'a/b' }],
252
+ ['identifier', { identifier: undefined }],
253
+ ['identifier', { identifier: ' ' }],
254
+ ['qty', { qty: 0 }],
255
+ ['qty', { qty: 2 }],
256
+ ])('rechaza damaged[].%s inválido', async (field, patch) => {
257
+ const damaged = [{ ...cancel.damaged[0], ...patch }];
258
+ expect(await errorsOf(CancelRetailSaleRequest, { ...cancel, damaged })).toEqual([`damaged.0.${field}`]);
259
+ });
260
+
109
261
  it('la respuesta trae el saleId', () => {
110
262
  const response: CancelRetailSaleResponse = { saleId: cancel.saleId };
111
263
  expect(response.saleId).toBe(cancel.saleId);
@@ -5,6 +5,7 @@ import {
5
5
  RetailFinancierEnum,
6
6
  RetailLinePaymentTypeEnum,
7
7
  RetailMdmProviderEnum,
8
+ RetailPaymentFrequencyEnum,
8
9
  RetailPaymentMethodEnum,
9
10
  RetailPieceReasonEnum,
10
11
  RetailPieceStatusEnum,
@@ -35,7 +36,8 @@ describe('enums de los objetos del retailer', () => {
35
36
  [RetailUserAccessStatusEnum, ['ACTIVE', 'SUSPENDED', 'INACTIVE']],
36
37
  [RetailSaleTypeEnum, ['CASH', 'CREDIT', 'EXTERNAL_REFERRAL']],
37
38
  [RetailSaleFinancierEnum, ['NONE', 'SUREKEEP', 'PAYJOY', 'CREDIYA', 'LESPAGO', 'INNOVA']],
38
- [RetailPaymentMethodEnum, ['CASH', 'CARD', 'SPEI']],
39
+ [RetailPaymentMethodEnum, ['CASH', 'CARD', 'WIRE', 'FIADO']],
40
+ [RetailPaymentFrequencyEnum, ['WEEKLY', 'BIWEEKLY', 'MONTHLY']],
39
41
  [RetailLinePaymentTypeEnum, ['CASH', 'CREDIT']],
40
42
  ])('%p trae exactamente los valores del contrato', (enumObject, values) => {
41
43
  expect(Object.values(enumObject)).toEqual(values);
@@ -18,4 +18,11 @@ export declare class AuthorizeCollectionMovementRequest {
18
18
  * no romper a quien todavía no manda tarifa.
19
19
  */
20
20
  pricing?: CollectionPricingDto;
21
+ /**
22
+ * La config del producto en el motor permite un reserve/débito PARCIAL cuando la wallet no cubre
23
+ * el monto completo. Presente en `true`, el procesador reserva/debita lo disponible por encima de
24
+ * su mínimo por moneda y responde `PARTIAL`. Ausente o `false` conserva el comportamiento de todo
25
+ * o nada: si el saldo no cubre el monto, responde `NONE`.
26
+ */
27
+ allowPartial?: boolean;
21
28
  }
@@ -63,3 +63,8 @@ __decorate([
63
63
  (0, class_transformer_1.Type)(() => CollectionPricingDto_1.CollectionPricingDto),
64
64
  __metadata("design:type", CollectionPricingDto_1.CollectionPricingDto)
65
65
  ], AuthorizeCollectionMovementRequest.prototype, "pricing", void 0);
66
+ __decorate([
67
+ (0, class_validator_1.IsOptional)(),
68
+ (0, class_validator_1.IsBoolean)(),
69
+ __metadata("design:type", Boolean)
70
+ ], AuthorizeCollectionMovementRequest.prototype, "allowPartial", void 0);
@@ -45,3 +45,18 @@ export declare const RETAIL_LINE_INDEX_MIN = 0;
45
45
  export declare const RETAIL_LINE_INDEX_MAX = 999;
46
46
  /** Rango máximo de `GET /inventory/movements`: 7 días en milisegundos. */
47
47
  export declare const RETAIL_MOVEMENTS_RANGE_MAX_MS: number;
48
+ /** Decimal de la venta y la cancelación: hasta 12 enteros y dos decimales, nunca negativo. */
49
+ export declare const RETAIL_SALE_DECIMAL_PATTERN: RegExp;
50
+ /** Decimal de la venta mayor que cero, como `payments[].amount`. */
51
+ export declare const RETAIL_SALE_POSITIVE_DECIMAL_PATTERN: RegExp;
52
+ /** Texto libre corto de la venta, como `authCode` y `promotionId`: no vacío y de a lo más 64. */
53
+ export declare const RETAIL_SALE_ID_TEXT_PATTERN: RegExp;
54
+ /** Últimos 4 dígitos de la tarjeta en un pago `CARD`. */
55
+ export declare const RETAIL_CARD_LAST4_PATTERN: RegExp;
56
+ /** Clave de rastreo SPEI y CLABE de un pago `WIRE`: 18 dígitos. */
57
+ export declare const RETAIL_SPEI_TRACKING_KEY_PATTERN: RegExp;
58
+ export declare const RETAIL_CLABE_PATTERN: RegExp;
59
+ /** Tope del motivo de cancelación de una venta. */
60
+ export declare const RETAIL_CANCEL_REASON_MAX_LENGTH = 200;
61
+ /** Teléfono del cliente en la venta: 10 dígitos. */
62
+ export declare const RETAIL_CUSTOMER_PHONE_PATTERN: RegExp;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RETAIL_MOVEMENTS_RANGE_MAX_MS = exports.RETAIL_LINE_INDEX_MAX = exports.RETAIL_LINE_INDEX_MIN = exports.RETAIL_ERROR_CODE_MAX_LENGTH = exports.RETAIL_EXTERNAL_ID_PATTERN = exports.RETAIL_NEXT_TOKEN_MAX_LENGTH = exports.RETAIL_EVENT_DECIMAL_PATTERN = exports.RETAIL_ELIGIBLE_FINANCIERS_MAX = exports.RETAIL_EVENT_STOCK_MAX = exports.RETAIL_LONG_TEXT_MAX_LENGTH = exports.RETAIL_SHORT_TEXT_MAX_LENGTH = exports.RETAIL_ID_TEXT_MAX_LENGTH = exports.RETAIL_EVENT_PIECES_MAX = exports.RETAIL_LIVE_CHECK_IDENTIFIERS_MAX = exports.RETAIL_DECIMAL_PATTERN = exports.RETAIL_SKU_PATTERN = exports.RETAIL_ZIP_CODE_MAX_LENGTH = exports.RETAIL_ZIP_CODE_MIN_LENGTH = exports.RETAIL_STORE_CODE_MAX_LENGTH = exports.RETAIL_ZONE_ID_PATTERN = exports.RETAIL_ENTITY_ID_PATTERN = exports.RETAIL_TENANT_ID_PATTERN = exports.RETAIL_LIST_LIMIT_MAX = exports.RETAIL_LIST_LIMIT_MIN = exports.RETAIL_EVENT_ID_MAX_LENGTH = void 0;
3
+ exports.RETAIL_CUSTOMER_PHONE_PATTERN = exports.RETAIL_CANCEL_REASON_MAX_LENGTH = exports.RETAIL_CLABE_PATTERN = exports.RETAIL_SPEI_TRACKING_KEY_PATTERN = exports.RETAIL_CARD_LAST4_PATTERN = exports.RETAIL_SALE_ID_TEXT_PATTERN = exports.RETAIL_SALE_POSITIVE_DECIMAL_PATTERN = exports.RETAIL_SALE_DECIMAL_PATTERN = exports.RETAIL_MOVEMENTS_RANGE_MAX_MS = exports.RETAIL_LINE_INDEX_MAX = exports.RETAIL_LINE_INDEX_MIN = exports.RETAIL_ERROR_CODE_MAX_LENGTH = exports.RETAIL_EXTERNAL_ID_PATTERN = exports.RETAIL_NEXT_TOKEN_MAX_LENGTH = exports.RETAIL_EVENT_DECIMAL_PATTERN = exports.RETAIL_ELIGIBLE_FINANCIERS_MAX = exports.RETAIL_EVENT_STOCK_MAX = exports.RETAIL_LONG_TEXT_MAX_LENGTH = exports.RETAIL_SHORT_TEXT_MAX_LENGTH = exports.RETAIL_ID_TEXT_MAX_LENGTH = exports.RETAIL_EVENT_PIECES_MAX = exports.RETAIL_LIVE_CHECK_IDENTIFIERS_MAX = exports.RETAIL_DECIMAL_PATTERN = exports.RETAIL_SKU_PATTERN = exports.RETAIL_ZIP_CODE_MAX_LENGTH = exports.RETAIL_ZIP_CODE_MIN_LENGTH = exports.RETAIL_STORE_CODE_MAX_LENGTH = exports.RETAIL_ZONE_ID_PATTERN = exports.RETAIL_ENTITY_ID_PATTERN = exports.RETAIL_TENANT_ID_PATTERN = exports.RETAIL_LIST_LIMIT_MAX = exports.RETAIL_LIST_LIMIT_MIN = exports.RETAIL_EVENT_ID_MAX_LENGTH = void 0;
4
4
  /** Tope de `eventId`: el límite seguro de una llave de DynamoDB. */
5
5
  exports.RETAIL_EVENT_ID_MAX_LENGTH = 1024;
6
6
  /** Rango de `limit` en las listas paginadas del retailer. */
@@ -48,3 +48,18 @@ exports.RETAIL_LINE_INDEX_MIN = 0;
48
48
  exports.RETAIL_LINE_INDEX_MAX = 999;
49
49
  /** Rango máximo de `GET /inventory/movements`: 7 días en milisegundos. */
50
50
  exports.RETAIL_MOVEMENTS_RANGE_MAX_MS = 7 * 24 * 60 * 60 * 1000;
51
+ /** Decimal de la venta y la cancelación: hasta 12 enteros y dos decimales, nunca negativo. */
52
+ exports.RETAIL_SALE_DECIMAL_PATTERN = /^\d{1,12}\.\d{2}$/;
53
+ /** Decimal de la venta mayor que cero, como `payments[].amount`. */
54
+ exports.RETAIL_SALE_POSITIVE_DECIMAL_PATTERN = /^(?=.*[1-9])\d{1,12}\.\d{2}$/;
55
+ /** Texto libre corto de la venta, como `authCode` y `promotionId`: no vacío y de a lo más 64. */
56
+ exports.RETAIL_SALE_ID_TEXT_PATTERN = /^(?=.*\S).{1,64}$/;
57
+ /** Últimos 4 dígitos de la tarjeta en un pago `CARD`. */
58
+ exports.RETAIL_CARD_LAST4_PATTERN = /^\d{4}$/;
59
+ /** Clave de rastreo SPEI y CLABE de un pago `WIRE`: 18 dígitos. */
60
+ exports.RETAIL_SPEI_TRACKING_KEY_PATTERN = /^\d{18}$/;
61
+ exports.RETAIL_CLABE_PATTERN = /^\d{18}$/;
62
+ /** Tope del motivo de cancelación de una venta. */
63
+ exports.RETAIL_CANCEL_REASON_MAX_LENGTH = 200;
64
+ /** Teléfono del cliente en la venta: 10 dígitos. */
65
+ exports.RETAIL_CUSTOMER_PHONE_PATTERN = /^\d{10}$/;
@@ -1,6 +1,13 @@
1
+ /** Lo que regresa dañado al cancelar; `identifier` en `null` si el producto es `QUANTITY`. */
2
+ export declare class RetailSystemDamagedItem {
3
+ sku: string;
4
+ identifier: string | null;
5
+ qty: number;
6
+ }
1
7
  /** Cuerpo de `POST /private/retail/sales/cancel`; el `saleId` es el mismo del registro. */
2
8
  export declare class CancelRetailSaleRequest {
3
9
  saleId: string;
4
10
  cancelledAt: string;
5
11
  reason: string;
12
+ damaged: RetailSystemDamagedItem[];
6
13
  }
@@ -9,9 +9,35 @@ var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.CancelRetailSaleRequest = void 0;
12
+ exports.CancelRetailSaleRequest = exports.RetailSystemDamagedItem = void 0;
13
+ const class_transformer_1 = require("class-transformer");
13
14
  const class_validator_1 = require("class-validator");
15
+ const retailIntegrationLimits_1 = require("../constants/retailIntegrationLimits");
14
16
  const IsIsoDateTimeWithZone_1 = require("../validators/IsIsoDateTimeWithZone");
17
+ const payloadValidators_1 = require("../validators/payloadValidators");
18
+ const saleValidators_1 = require("../validators/saleValidators");
19
+ /** Lo que regresa dañado al cancelar; `identifier` en `null` si el producto es `QUANTITY`. */
20
+ class RetailSystemDamagedItem {
21
+ }
22
+ exports.RetailSystemDamagedItem = RetailSystemDamagedItem;
23
+ __decorate([
24
+ (0, class_validator_1.IsString)(),
25
+ (0, class_validator_1.Matches)(retailIntegrationLimits_1.RETAIL_SKU_PATTERN),
26
+ __metadata("design:type", String)
27
+ ], RetailSystemDamagedItem.prototype, "sku", void 0);
28
+ __decorate([
29
+ (0, class_validator_1.ValidateIf)(payloadValidators_1.isNullOrValidated),
30
+ (0, class_validator_1.IsString)(),
31
+ (0, class_validator_1.Matches)(/\S/),
32
+ (0, class_validator_1.MaxLength)(retailIntegrationLimits_1.RETAIL_SHORT_TEXT_MAX_LENGTH),
33
+ __metadata("design:type", String)
34
+ ], RetailSystemDamagedItem.prototype, "identifier", void 0);
35
+ __decorate([
36
+ (0, class_validator_1.IsInt)(),
37
+ (0, class_validator_1.Min)(1),
38
+ (0, class_validator_1.Validate)(saleValidators_1.QtyMatchesIdentifier),
39
+ __metadata("design:type", Number)
40
+ ], RetailSystemDamagedItem.prototype, "qty", void 0);
15
41
  /** Cuerpo de `POST /private/retail/sales/cancel`; el `saleId` es el mismo del registro. */
16
42
  class CancelRetailSaleRequest {
17
43
  }
@@ -28,5 +54,12 @@ __decorate([
28
54
  __decorate([
29
55
  (0, class_validator_1.IsString)(),
30
56
  (0, class_validator_1.Matches)(/\S/),
57
+ (0, class_validator_1.MaxLength)(retailIntegrationLimits_1.RETAIL_CANCEL_REASON_MAX_LENGTH),
31
58
  __metadata("design:type", String)
32
59
  ], CancelRetailSaleRequest.prototype, "reason", void 0);
60
+ __decorate([
61
+ (0, class_validator_1.IsArray)(),
62
+ (0, class_validator_1.ValidateNested)({ each: true }),
63
+ (0, class_transformer_1.Type)(() => RetailSystemDamagedItem),
64
+ __metadata("design:type", Array)
65
+ ], CancelRetailSaleRequest.prototype, "damaged", void 0);
@@ -0,0 +1,6 @@
1
+ /** Cada cuánto paga el cliente en `credit.paymentFrequency`. */
2
+ export declare enum RetailPaymentFrequencyEnum {
3
+ WEEKLY = "WEEKLY",
4
+ BIWEEKLY = "BIWEEKLY",
5
+ MONTHLY = "MONTHLY"
6
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RetailPaymentFrequencyEnum = void 0;
4
+ /** Cada cuánto paga el cliente en `credit.paymentFrequency`. */
5
+ var RetailPaymentFrequencyEnum;
6
+ (function (RetailPaymentFrequencyEnum) {
7
+ RetailPaymentFrequencyEnum["WEEKLY"] = "WEEKLY";
8
+ RetailPaymentFrequencyEnum["BIWEEKLY"] = "BIWEEKLY";
9
+ RetailPaymentFrequencyEnum["MONTHLY"] = "MONTHLY";
10
+ })(RetailPaymentFrequencyEnum || (exports.RetailPaymentFrequencyEnum = RetailPaymentFrequencyEnum = {}));
@@ -1,6 +1,7 @@
1
- /** Método de pago de la venta. */
1
+ /** Medio de pago de `payments[].method` en la venta. */
2
2
  export declare enum RetailPaymentMethodEnum {
3
3
  CASH = "CASH",
4
4
  CARD = "CARD",
5
- SPEI = "SPEI"
5
+ WIRE = "WIRE",
6
+ FIADO = "FIADO"
6
7
  }
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RetailPaymentMethodEnum = void 0;
4
- /** Método de pago de la venta. */
4
+ /** Medio de pago de `payments[].method` en la venta. */
5
5
  var RetailPaymentMethodEnum;
6
6
  (function (RetailPaymentMethodEnum) {
7
7
  RetailPaymentMethodEnum["CASH"] = "CASH";
8
8
  RetailPaymentMethodEnum["CARD"] = "CARD";
9
- RetailPaymentMethodEnum["SPEI"] = "SPEI";
9
+ RetailPaymentMethodEnum["WIRE"] = "WIRE";
10
+ RetailPaymentMethodEnum["FIADO"] = "FIADO";
10
11
  })(RetailPaymentMethodEnum || (exports.RetailPaymentMethodEnum = RetailPaymentMethodEnum = {}));
@@ -18,6 +18,7 @@ export * from './RetailUserAccessStatusEnum';
18
18
  export * from './RetailSaleTypeEnum';
19
19
  export * from './RetailSaleFinancierEnum';
20
20
  export * from './RetailPaymentMethodEnum';
21
+ export * from './RetailPaymentFrequencyEnum';
21
22
  export * from './RetailLinePaymentTypeEnum';
22
23
  export * from './RetailSaleLineRoleEnum';
23
24
  export * from './RetailEventRejectCodeEnum';
@@ -34,6 +34,7 @@ __exportStar(require("./RetailUserAccessStatusEnum"), exports);
34
34
  __exportStar(require("./RetailSaleTypeEnum"), exports);
35
35
  __exportStar(require("./RetailSaleFinancierEnum"), exports);
36
36
  __exportStar(require("./RetailPaymentMethodEnum"), exports);
37
+ __exportStar(require("./RetailPaymentFrequencyEnum"), exports);
37
38
  __exportStar(require("./RetailLinePaymentTypeEnum"), exports);
38
39
  __exportStar(require("./RetailSaleLineRoleEnum"), exports);
39
40
  __exportStar(require("./RetailEventRejectCodeEnum"), exports);
@@ -3,6 +3,8 @@ export * from './constants/retailIntegrationErrorHttpStatus';
3
3
  export * from './enums';
4
4
  export * from './validators/IsIsoDateTimeWithZone';
5
5
  export * from './validators/IsMovementsRangeValid';
6
+ export * from './validators/IsCalendarDate';
7
+ export * from './validators/saleValidators';
6
8
  export * from './dtos/RetailEventEnvelope';
7
9
  export * from './dtos/ReceiveStoreEventRequest';
8
10
  export * from './dtos/ReceiveRetailUserEventRequest';
@@ -19,6 +19,8 @@ __exportStar(require("./constants/retailIntegrationErrorHttpStatus"), exports);
19
19
  __exportStar(require("./enums"), exports);
20
20
  __exportStar(require("./validators/IsIsoDateTimeWithZone"), exports);
21
21
  __exportStar(require("./validators/IsMovementsRangeValid"), exports);
22
+ __exportStar(require("./validators/IsCalendarDate"), exports);
23
+ __exportStar(require("./validators/saleValidators"), exports);
22
24
  __exportStar(require("./dtos/RetailEventEnvelope"), exports);
23
25
  __exportStar(require("./dtos/ReceiveStoreEventRequest"), exports);
24
26
  __exportStar(require("./dtos/ReceiveRetailUserEventRequest"), exports);
@@ -1,8 +1,9 @@
1
- import { RetailLinePaymentTypeEnum, RetailPaymentMethodEnum, RetailSaleFinancierEnum, RetailSaleLineRoleEnum, RetailSaleTypeEnum } from '../enums';
1
+ import { RetailLinePaymentTypeEnum, RetailPaymentFrequencyEnum, RetailPaymentMethodEnum, RetailSaleFinancierEnum, RetailSaleLineRoleEnum, RetailSaleTypeEnum } from '../enums';
2
2
  import { RetailCurrency } from './RetailSystemProduct';
3
3
  export type RetailSaleType = `${RetailSaleTypeEnum}`;
4
4
  export type RetailSaleFinancier = `${RetailSaleFinancierEnum}`;
5
5
  export type RetailPaymentMethod = `${RetailPaymentMethodEnum}`;
6
+ export type RetailPaymentFrequency = `${RetailPaymentFrequencyEnum}`;
6
7
  export type RetailLinePaymentType = `${RetailLinePaymentTypeEnum}`;
7
8
  export type RetailSaleLineRole = `${RetailSaleLineRoleEnum}`;
8
9
  export declare class RetailSystemSaleCustomer {
@@ -12,6 +13,24 @@ export declare class RetailSystemSaleCustomer {
12
13
  maternalLastName: string | null;
13
14
  phone: string;
14
15
  }
16
+ /** Condiciones del crédito; todas obligatorias cuando `credit` no es `null`. */
17
+ export declare class RetailSystemSaleCredit {
18
+ paymentFrequency: RetailPaymentFrequency;
19
+ installments: number;
20
+ installmentAmount: string;
21
+ downPayment: string;
22
+ totalToPay: string;
23
+ firstPaymentDate: string;
24
+ }
25
+ /** Un medio de pago de `amountPaid`; las seis llaves van siempre, en `null` las que no aplican. */
26
+ export declare class RetailSystemSalePayment {
27
+ method: RetailPaymentMethod;
28
+ amount: string;
29
+ cardLast4: string | null;
30
+ authCode: string | null;
31
+ speiTrackingKey: string | null;
32
+ senderClabe: string | null;
33
+ }
15
34
  export declare class RetailSystemSaleComponent {
16
35
  sku: string;
17
36
  qty: number;
@@ -26,6 +45,7 @@ export declare class RetailSystemSaleLine {
26
45
  paymentType: RetailLinePaymentType;
27
46
  financedAmount: string;
28
47
  role: RetailSaleLineRole | null;
48
+ promotionId: string | null;
29
49
  components: RetailSystemSaleComponent[];
30
50
  }
31
51
  /** Cuerpo de `POST /sales` de la doc y de `privateRegisterRetailSale`; `saleId` es la llave de idempotencia. */
@@ -38,10 +58,11 @@ export declare class RetailSystemSale {
38
58
  saleType: RetailSaleType;
39
59
  financier: RetailSaleFinancier;
40
60
  creditId: string | null;
61
+ credit: RetailSystemSaleCredit | null;
41
62
  currencyId: RetailCurrency;
42
63
  customer: RetailSystemSaleCustomer;
43
64
  equipmentPrice: string;
44
65
  amountPaid: string;
45
- paymentMethod: RetailPaymentMethod | null;
66
+ payments: RetailSystemSalePayment[];
46
67
  lines: RetailSystemSaleLine[];
47
68
  }