@fiado/type-kit 3.547.0 → 3.548.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/loanCredit/cancelLoanCreditRequest.test.ts +40 -0
- package/_test_/unit/loanRetailAudit/loanRetailAuditContracts.test.ts +9 -0
- package/_test_/unit/retailWizard/saleCancellation.test.ts +25 -0
- package/bin/loanCredit/dtos/requests/CancelLoanCreditRequest.d.ts +7 -0
- package/bin/loanCredit/dtos/requests/CancelLoanCreditRequest.js +33 -0
- package/bin/loanCredit/dtos/responses/LoanCreditResponse.d.ts +2 -0
- package/bin/loanCredit/index.d.ts +1 -0
- package/bin/loanCredit/index.js +1 -0
- package/bin/loanRetailAudit/enums/RetailAuditEntityTypeEnum.d.ts +3 -1
- package/bin/loanRetailAudit/enums/RetailAuditEntityTypeEnum.js +2 -0
- package/bin/loanRetailAudit/events/AuditTrailRecordedV1.d.ts +1 -1
- package/bin/retailWizard/dtos/Sale.d.ts +3 -0
- package/bin/retailWizard/dtos/SaleCancellation.d.ts +9 -0
- package/bin/retailWizard/dtos/SaleCancellation.js +2 -0
- package/bin/retailWizard/enums/SaleCancellationReasonEnum.d.ts +8 -0
- package/bin/retailWizard/enums/SaleCancellationReasonEnum.js +12 -0
- package/bin/retailWizard/index.d.ts +2 -0
- package/bin/retailWizard/index.js +2 -0
- package/package.json +1 -1
- package/src/loanCredit/dtos/requests/CancelLoanCreditRequest.ts +20 -0
- package/src/loanCredit/dtos/responses/LoanCreditResponse.ts +2 -0
- package/src/loanCredit/index.ts +1 -0
- package/src/loanRetailAudit/enums/RetailAuditEntityTypeEnum.ts +2 -0
- package/src/loanRetailAudit/events/AuditTrailRecordedV1.ts +1 -1
- package/src/retailWizard/dtos/Sale.ts +3 -0
- package/src/retailWizard/dtos/SaleCancellation.ts +10 -0
- package/src/retailWizard/enums/SaleCancellationReasonEnum.ts +8 -0
- package/src/retailWizard/index.ts +2 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import { CancelLoanCreditRequest } from '../../../src/loanCredit/index';
|
|
5
|
+
import type { LoanCreditResponse } from '../../../src/loanCredit/index';
|
|
6
|
+
|
|
7
|
+
const errorsOf = async (body: Record<string, unknown>): Promise<string[]> => {
|
|
8
|
+
const errors = await validate(plainToInstance(CancelLoanCreditRequest, body));
|
|
9
|
+
return errors.map((error) => error.property);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const VALID = { saleId: '01M5B1V5R2KZ90G8CNEA8TTC46', reason: 'El cliente se arrepintió' };
|
|
13
|
+
|
|
14
|
+
describe('CancelLoanCreditRequest', () => {
|
|
15
|
+
it('acepta la venta y el motivo', async () => {
|
|
16
|
+
expect(await errorsOf(VALID)).toEqual([]);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('exige saleId y reason', async () => {
|
|
20
|
+
expect((await errorsOf({})).sort()).toEqual(['reason', 'saleId']);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('rechaza saleId o reason vacíos', async () => {
|
|
24
|
+
expect(await errorsOf({ ...VALID, saleId: '' })).toEqual(['saleId']);
|
|
25
|
+
expect(await errorsOf({ ...VALID, reason: '' })).toEqual(['reason']);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('rechaza un saleId con caracteres fuera de la referencia del hecho', async () => {
|
|
29
|
+
expect(await errorsOf({ ...VALID, saleId: 'SALE#123' })).toEqual(['saleId']);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('LoanCreditResponse.hasPayments', () => {
|
|
34
|
+
it('es opcional y booleano', () => {
|
|
35
|
+
const partial: Pick<LoanCreditResponse, 'hasPayments'> = {};
|
|
36
|
+
const withFlag: Pick<LoanCreditResponse, 'hasPayments'> = { hasPayments: true };
|
|
37
|
+
expect(partial.hasPayments).toBeUndefined();
|
|
38
|
+
expect(withFlag.hasPayments).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
@@ -123,6 +123,15 @@ describe('ListAuditTrailQuery', () => {
|
|
|
123
123
|
});
|
|
124
124
|
|
|
125
125
|
describe('catálogos', () => {
|
|
126
|
+
it('incluye PROSPECT y RETAIL_CUSTOMER del wizard y los acepta en el evento', () => {
|
|
127
|
+
for (const entityType of ['PROSPECT', 'RETAIL_CUSTOMER']) {
|
|
128
|
+
expect(AUDIT_TRAIL_ENTITY_TYPES).toContain(entityType);
|
|
129
|
+
expect(errorsOf(AuditTrailRecordedV1, { ...validEvent, entityType })).toEqual([]);
|
|
130
|
+
}
|
|
131
|
+
expect(RetailAuditEntityTypeEnum.PROSPECT).toBe('PROSPECT');
|
|
132
|
+
expect(RetailAuditEntityTypeEnum.RETAIL_CUSTOMER).toBe('RETAIL_CUSTOMER');
|
|
133
|
+
});
|
|
134
|
+
|
|
126
135
|
it('AUDIT_TRAIL_ENTITY_TYPES une Loan y Retail sin repetidos', () => {
|
|
127
136
|
const all = [...Object.values(LoanAuditEntityTypeEnum), ...Object.values(RetailAuditEntityTypeEnum)];
|
|
128
137
|
expect([...AUDIT_TRAIL_ENTITY_TYPES].sort()).toEqual([...all].sort());
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { SaleCancellationReasonEnum } from '../../../src/retailWizard/index';
|
|
3
|
+
import type { Sale, SaleCancellation } from '../../../src/retailWizard/index';
|
|
4
|
+
|
|
5
|
+
describe('SaleCancellation', () => {
|
|
6
|
+
it('cataloga los cinco motivos por los que no se puede cancelar', () => {
|
|
7
|
+
expect(Object.values(SaleCancellationReasonEnum).sort()).toEqual([
|
|
8
|
+
'CANCEL_WINDOW_EXPIRED',
|
|
9
|
+
'CREDIT_HAS_PAYMENTS',
|
|
10
|
+
'CREDIT_NOT_CANCELLABLE',
|
|
11
|
+
'IMEI_NOT_RETURNABLE',
|
|
12
|
+
'SALE_ALREADY_CANCELLED',
|
|
13
|
+
]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('viaja opcional en la venta', () => {
|
|
17
|
+
const cancellation: SaleCancellation = {
|
|
18
|
+
allowed: false,
|
|
19
|
+
reason: SaleCancellationReasonEnum.CREDIT_HAS_PAYMENTS,
|
|
20
|
+
windowEndsAt: '2026-10-26T00:00:00.000Z',
|
|
21
|
+
};
|
|
22
|
+
const sale: Pick<Sale, 'cancellation'> = { cancellation };
|
|
23
|
+
expect(sale.cancellation?.allowed).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/** Body de `POST /private/credits/:creditId/cancel` (loan-credit-business): la venta que se cancela. */
|
|
2
|
+
export declare class CancelLoanCreditRequest {
|
|
3
|
+
/** Venta que origina la cancelación; es la referencia del aviso al cliente. */
|
|
4
|
+
saleId: string;
|
|
5
|
+
/** Motivo de la cancelación; va a la auditoría del crédito y no se loguea. */
|
|
6
|
+
reason: string;
|
|
7
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
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.CancelLoanCreditRequest = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/** Body de `POST /private/credits/:creditId/cancel` (loan-credit-business): la venta que se cancela. */
|
|
16
|
+
class CancelLoanCreditRequest {
|
|
17
|
+
}
|
|
18
|
+
exports.CancelLoanCreditRequest = CancelLoanCreditRequest;
|
|
19
|
+
__decorate([
|
|
20
|
+
(0, class_transformer_1.Expose)(),
|
|
21
|
+
(0, class_validator_1.IsString)(),
|
|
22
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
23
|
+
(0, class_validator_1.MaxLength)(120),
|
|
24
|
+
(0, class_validator_1.Matches)(/^[A-Za-z0-9._:-]+$/),
|
|
25
|
+
__metadata("design:type", String)
|
|
26
|
+
], CancelLoanCreditRequest.prototype, "saleId", void 0);
|
|
27
|
+
__decorate([
|
|
28
|
+
(0, class_transformer_1.Expose)(),
|
|
29
|
+
(0, class_validator_1.IsString)(),
|
|
30
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
31
|
+
(0, class_validator_1.MaxLength)(500),
|
|
32
|
+
__metadata("design:type", String)
|
|
33
|
+
], CancelLoanCreditRequest.prototype, "reason", void 0);
|
|
@@ -51,6 +51,8 @@ export interface LoanCreditResponse {
|
|
|
51
51
|
effectiveTerms?: EffectiveTermsSnapshot | null;
|
|
52
52
|
activatedAt?: string;
|
|
53
53
|
voluntaryCancelDeadline?: string;
|
|
54
|
+
/** Si ya se abonó alguna cuota (el enganche no cuenta); solo lo traen la lectura y la cancelación privadas. */
|
|
55
|
+
hasPayments?: boolean;
|
|
54
56
|
firstDueDate?: string;
|
|
55
57
|
lastDueDate?: string;
|
|
56
58
|
createdBy: string;
|
|
@@ -117,6 +117,7 @@ export * from './dtos/WriteOffConfirmations';
|
|
|
117
117
|
export * from './dtos/requests/BackofficeSettleCreditRequest';
|
|
118
118
|
export * from './dtos/requests/BackofficeListWriteOffCandidatesRequest';
|
|
119
119
|
export * from './dtos/requests/BackofficeWriteOffCreditRequest';
|
|
120
|
+
export * from './dtos/requests/CancelLoanCreditRequest';
|
|
120
121
|
export * from './dtos/requests/BackofficeCollectWrittenOffCreditRequest';
|
|
121
122
|
export * from './dtos/requests/BackofficeProposeRestructureRequest';
|
|
122
123
|
export * from './dtos/requests/BackofficeApproveRestructureRequest';
|
package/bin/loanCredit/index.js
CHANGED
|
@@ -159,6 +159,7 @@ __exportStar(require("./dtos/WriteOffConfirmations"), exports);
|
|
|
159
159
|
__exportStar(require("./dtos/requests/BackofficeSettleCreditRequest"), exports);
|
|
160
160
|
__exportStar(require("./dtos/requests/BackofficeListWriteOffCandidatesRequest"), exports);
|
|
161
161
|
__exportStar(require("./dtos/requests/BackofficeWriteOffCreditRequest"), exports);
|
|
162
|
+
__exportStar(require("./dtos/requests/CancelLoanCreditRequest"), exports);
|
|
162
163
|
__exportStar(require("./dtos/requests/BackofficeCollectWrittenOffCreditRequest"), exports);
|
|
163
164
|
__exportStar(require("./dtos/requests/BackofficeProposeRestructureRequest"), exports);
|
|
164
165
|
__exportStar(require("./dtos/requests/BackofficeApproveRestructureRequest"), exports);
|
|
@@ -13,5 +13,7 @@ export declare enum RetailAuditEntityTypeEnum {
|
|
|
13
13
|
COMMISSION_PAYOUT = "COMMISSION_PAYOUT",
|
|
14
14
|
COMMISSION_ADJUSTMENT = "COMMISSION_ADJUSTMENT",
|
|
15
15
|
COMMISSION_RULE = "COMMISSION_RULE",
|
|
16
|
-
COMMISSION_POLICY = "COMMISSION_POLICY"
|
|
16
|
+
COMMISSION_POLICY = "COMMISSION_POLICY",
|
|
17
|
+
PROSPECT = "PROSPECT",
|
|
18
|
+
RETAIL_CUSTOMER = "RETAIL_CUSTOMER"
|
|
17
19
|
}
|
|
@@ -18,4 +18,6 @@ var RetailAuditEntityTypeEnum;
|
|
|
18
18
|
RetailAuditEntityTypeEnum["COMMISSION_ADJUSTMENT"] = "COMMISSION_ADJUSTMENT";
|
|
19
19
|
RetailAuditEntityTypeEnum["COMMISSION_RULE"] = "COMMISSION_RULE";
|
|
20
20
|
RetailAuditEntityTypeEnum["COMMISSION_POLICY"] = "COMMISSION_POLICY";
|
|
21
|
+
RetailAuditEntityTypeEnum["PROSPECT"] = "PROSPECT";
|
|
22
|
+
RetailAuditEntityTypeEnum["RETAIL_CUSTOMER"] = "RETAIL_CUSTOMER";
|
|
21
23
|
})(RetailAuditEntityTypeEnum || (exports.RetailAuditEntityTypeEnum = RetailAuditEntityTypeEnum = {}));
|
|
@@ -10,7 +10,7 @@ export declare class AuditTrailRecordedV1 {
|
|
|
10
10
|
action: AuditTrailActionEnum;
|
|
11
11
|
changes: AuditTrailChange[];
|
|
12
12
|
context: AuditTrailContextEntry[];
|
|
13
|
-
/** userId del actor
|
|
13
|
+
/** userId del actor; nunca `system`: sin usuario va el nombre del lambda que lo disparó. */
|
|
14
14
|
performedBy: string;
|
|
15
15
|
sourceLambda: string;
|
|
16
16
|
occurredAt: string;
|
|
@@ -7,6 +7,7 @@ import type { CentralSyncStatusEnum } from '../enums/CentralSyncStatusEnum';
|
|
|
7
7
|
import type { SalePaymentDetail } from './SalePaymentDetail';
|
|
8
8
|
import type { SaleLine } from './SaleLine';
|
|
9
9
|
import type { SalePromotionRef } from '../../retailPromotions/dtos/SalePromotionRef';
|
|
10
|
+
import type { SaleCancellation } from './SaleCancellation';
|
|
10
11
|
/**
|
|
11
12
|
* Venta (modelo-datos §3). pk `SALE#<saleId>` · sk `META` · 4 GSIs (`retailerId-soldAt-index`,
|
|
12
13
|
* `storeId-soldAt-index`, `seller-soldAt-index`, `customerId-soldAt-index`). Unicidad de folio vía
|
|
@@ -65,6 +66,8 @@ export interface Sale {
|
|
|
65
66
|
cancelledAt: string | null;
|
|
66
67
|
/** Reason OBLIGATORIO en cancelación (AuditTrail) — flujo C. */
|
|
67
68
|
cancelReason: string | null;
|
|
69
|
+
/** Si la venta se puede cancelar hoy y, si no, por qué; solo lo trae el detalle del backoffice. */
|
|
70
|
+
cancellation?: SaleCancellation;
|
|
68
71
|
/**
|
|
69
72
|
* SNAPSHOT de identidad y contexto, congelado al cerrar la venta. NO se refresca: una venta es la
|
|
70
73
|
* fotografía de un hecho, no la caché de un perfil. Si el cliente corrige su nombre, la venta
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { SaleCancellationReasonEnum } from '../enums/SaleCancellationReasonEnum';
|
|
2
|
+
/** Si la venta se puede cancelar hoy; el backend valida igual al cancelar. */
|
|
3
|
+
export interface SaleCancellation {
|
|
4
|
+
allowed: boolean;
|
|
5
|
+
/** Ausente cuando `allowed` es true. */
|
|
6
|
+
reason?: SaleCancellationReasonEnum;
|
|
7
|
+
/** Fin de la ventana de cancelación voluntaria, ISO-8601. */
|
|
8
|
+
windowEndsAt?: string;
|
|
9
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Por qué una venta no se puede cancelar; coincide con el `code` que respondería la cancelación. */
|
|
2
|
+
export declare enum SaleCancellationReasonEnum {
|
|
3
|
+
SALE_ALREADY_CANCELLED = "SALE_ALREADY_CANCELLED",
|
|
4
|
+
IMEI_NOT_RETURNABLE = "IMEI_NOT_RETURNABLE",
|
|
5
|
+
CANCEL_WINDOW_EXPIRED = "CANCEL_WINDOW_EXPIRED",
|
|
6
|
+
CREDIT_HAS_PAYMENTS = "CREDIT_HAS_PAYMENTS",
|
|
7
|
+
CREDIT_NOT_CANCELLABLE = "CREDIT_NOT_CANCELLABLE"
|
|
8
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SaleCancellationReasonEnum = void 0;
|
|
4
|
+
/** Por qué una venta no se puede cancelar; coincide con el `code` que respondería la cancelación. */
|
|
5
|
+
var SaleCancellationReasonEnum;
|
|
6
|
+
(function (SaleCancellationReasonEnum) {
|
|
7
|
+
SaleCancellationReasonEnum["SALE_ALREADY_CANCELLED"] = "SALE_ALREADY_CANCELLED";
|
|
8
|
+
SaleCancellationReasonEnum["IMEI_NOT_RETURNABLE"] = "IMEI_NOT_RETURNABLE";
|
|
9
|
+
SaleCancellationReasonEnum["CANCEL_WINDOW_EXPIRED"] = "CANCEL_WINDOW_EXPIRED";
|
|
10
|
+
SaleCancellationReasonEnum["CREDIT_HAS_PAYMENTS"] = "CREDIT_HAS_PAYMENTS";
|
|
11
|
+
SaleCancellationReasonEnum["CREDIT_NOT_CANCELLABLE"] = "CREDIT_NOT_CANCELLABLE";
|
|
12
|
+
})(SaleCancellationReasonEnum || (exports.SaleCancellationReasonEnum = SaleCancellationReasonEnum = {}));
|
|
@@ -57,6 +57,8 @@ export * from './dtos/AccessorySaleLine';
|
|
|
57
57
|
export * from './dtos/WizardSession';
|
|
58
58
|
export * from './dtos/OtpVerification';
|
|
59
59
|
export * from './dtos/Sale';
|
|
60
|
+
export * from './dtos/SaleCancellation';
|
|
61
|
+
export * from './enums/SaleCancellationReasonEnum';
|
|
60
62
|
export * from './dtos/Prospect';
|
|
61
63
|
export * from './dtos/PaginatedResult';
|
|
62
64
|
export * from './dtos/requests/StartSessionRequest';
|
|
@@ -80,6 +80,8 @@ __exportStar(require("./dtos/AccessorySaleLine"), exports);
|
|
|
80
80
|
__exportStar(require("./dtos/WizardSession"), exports);
|
|
81
81
|
__exportStar(require("./dtos/OtpVerification"), exports);
|
|
82
82
|
__exportStar(require("./dtos/Sale"), exports);
|
|
83
|
+
__exportStar(require("./dtos/SaleCancellation"), exports);
|
|
84
|
+
__exportStar(require("./enums/SaleCancellationReasonEnum"), exports);
|
|
83
85
|
__exportStar(require("./dtos/Prospect"), exports);
|
|
84
86
|
// Paginación genérica
|
|
85
87
|
__exportStar(require("./dtos/PaginatedResult"), exports);
|
package/package.json
CHANGED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsNotEmpty, IsString, Matches, MaxLength } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
/** Body de `POST /private/credits/:creditId/cancel` (loan-credit-business): la venta que se cancela. */
|
|
5
|
+
export class CancelLoanCreditRequest {
|
|
6
|
+
/** Venta que origina la cancelación; es la referencia del aviso al cliente. */
|
|
7
|
+
@Expose()
|
|
8
|
+
@IsString()
|
|
9
|
+
@IsNotEmpty()
|
|
10
|
+
@MaxLength(120)
|
|
11
|
+
@Matches(/^[A-Za-z0-9._:-]+$/)
|
|
12
|
+
saleId!: string;
|
|
13
|
+
|
|
14
|
+
/** Motivo de la cancelación; va a la auditoría del crédito y no se loguea. */
|
|
15
|
+
@Expose()
|
|
16
|
+
@IsString()
|
|
17
|
+
@IsNotEmpty()
|
|
18
|
+
@MaxLength(500)
|
|
19
|
+
reason!: string;
|
|
20
|
+
}
|
|
@@ -52,6 +52,8 @@ export interface LoanCreditResponse {
|
|
|
52
52
|
effectiveTerms?: EffectiveTermsSnapshot | null;
|
|
53
53
|
activatedAt?: string;
|
|
54
54
|
voluntaryCancelDeadline?: string;
|
|
55
|
+
/** Si ya se abonó alguna cuota (el enganche no cuenta); solo lo traen la lectura y la cancelación privadas. */
|
|
56
|
+
hasPayments?: boolean;
|
|
55
57
|
firstDueDate?: string;
|
|
56
58
|
lastDueDate?: string;
|
|
57
59
|
createdBy: string;
|
package/src/loanCredit/index.ts
CHANGED
|
@@ -141,6 +141,7 @@ export * from './dtos/WriteOffConfirmations';
|
|
|
141
141
|
export * from './dtos/requests/BackofficeSettleCreditRequest';
|
|
142
142
|
export * from './dtos/requests/BackofficeListWriteOffCandidatesRequest';
|
|
143
143
|
export * from './dtos/requests/BackofficeWriteOffCreditRequest';
|
|
144
|
+
export * from './dtos/requests/CancelLoanCreditRequest';
|
|
144
145
|
export * from './dtos/requests/BackofficeCollectWrittenOffCreditRequest';
|
|
145
146
|
export * from './dtos/requests/BackofficeProposeRestructureRequest';
|
|
146
147
|
export * from './dtos/requests/BackofficeApproveRestructureRequest';
|
|
@@ -37,7 +37,7 @@ export class AuditTrailRecordedV1 {
|
|
|
37
37
|
@Type(() => AuditTrailContextEntry)
|
|
38
38
|
context!: AuditTrailContextEntry[];
|
|
39
39
|
|
|
40
|
-
/** userId del actor
|
|
40
|
+
/** userId del actor; nunca `system`: sin usuario va el nombre del lambda que lo disparó. */
|
|
41
41
|
@Expose()
|
|
42
42
|
@IsString()
|
|
43
43
|
@IsNotEmpty()
|
|
@@ -7,6 +7,7 @@ import type { CentralSyncStatusEnum } from '../enums/CentralSyncStatusEnum';
|
|
|
7
7
|
import type { SalePaymentDetail } from './SalePaymentDetail';
|
|
8
8
|
import type { SaleLine } from './SaleLine';
|
|
9
9
|
import type { SalePromotionRef } from '../../retailPromotions/dtos/SalePromotionRef';
|
|
10
|
+
import type { SaleCancellation } from './SaleCancellation';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Venta (modelo-datos §3). pk `SALE#<saleId>` · sk `META` · 4 GSIs (`retailerId-soldAt-index`,
|
|
@@ -66,6 +67,8 @@ export interface Sale {
|
|
|
66
67
|
cancelledAt: string | null;
|
|
67
68
|
/** Reason OBLIGATORIO en cancelación (AuditTrail) — flujo C. */
|
|
68
69
|
cancelReason: string | null;
|
|
70
|
+
/** Si la venta se puede cancelar hoy y, si no, por qué; solo lo trae el detalle del backoffice. */
|
|
71
|
+
cancellation?: SaleCancellation;
|
|
69
72
|
/**
|
|
70
73
|
* SNAPSHOT de identidad y contexto, congelado al cerrar la venta. NO se refresca: una venta es la
|
|
71
74
|
* fotografía de un hecho, no la caché de un perfil. Si el cliente corrige su nombre, la venta
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SaleCancellationReasonEnum } from '../enums/SaleCancellationReasonEnum';
|
|
2
|
+
|
|
3
|
+
/** Si la venta se puede cancelar hoy; el backend valida igual al cancelar. */
|
|
4
|
+
export interface SaleCancellation {
|
|
5
|
+
allowed: boolean;
|
|
6
|
+
/** Ausente cuando `allowed` es true. */
|
|
7
|
+
reason?: SaleCancellationReasonEnum;
|
|
8
|
+
/** Fin de la ventana de cancelación voluntaria, ISO-8601. */
|
|
9
|
+
windowEndsAt?: string;
|
|
10
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Por qué una venta no se puede cancelar; coincide con el `code` que respondería la cancelación. */
|
|
2
|
+
export enum SaleCancellationReasonEnum {
|
|
3
|
+
SALE_ALREADY_CANCELLED = 'SALE_ALREADY_CANCELLED',
|
|
4
|
+
IMEI_NOT_RETURNABLE = 'IMEI_NOT_RETURNABLE',
|
|
5
|
+
CANCEL_WINDOW_EXPIRED = 'CANCEL_WINDOW_EXPIRED',
|
|
6
|
+
CREDIT_HAS_PAYMENTS = 'CREDIT_HAS_PAYMENTS',
|
|
7
|
+
CREDIT_NOT_CANCELLABLE = 'CREDIT_NOT_CANCELLABLE',
|
|
8
|
+
}
|
|
@@ -64,6 +64,8 @@ export * from './dtos/AccessorySaleLine';
|
|
|
64
64
|
export * from './dtos/WizardSession';
|
|
65
65
|
export * from './dtos/OtpVerification';
|
|
66
66
|
export * from './dtos/Sale';
|
|
67
|
+
export * from './dtos/SaleCancellation';
|
|
68
|
+
export * from './enums/SaleCancellationReasonEnum';
|
|
67
69
|
export * from './dtos/Prospect';
|
|
68
70
|
|
|
69
71
|
// Paginación genérica
|