@fiado/type-kit 3.490.0 → 3.492.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/customerPaymentDtos.test.ts +2 -0
- package/_test_/unit/loanCredit/dtos/createCustomerPaymentRequest.test.ts +18 -4
- package/_test_/unit/loanCredit/installmentPaidEvent.test.ts +17 -0
- package/_test_/unit/retailCommission/commissionPayout.test.ts +104 -0
- package/_test_/unit/retailCommission/commissionRent.test.ts +33 -0
- package/_test_/unit/retailCommission/commissionRules.test.ts +249 -0
- package/_test_/unit/retailCommission/commissionSimulation.test.ts +43 -0
- package/_test_/unit/retailCommission/myCommissions.test.ts +29 -0
- package/_test_/unit/retailLoan/paymentContract.test.ts +3 -1
- package/_test_/unit/retailWizard/ventaSagaMessages.test.ts +108 -11
- package/bin/loanCredit/dtos/InstallmentPaidEvent.d.ts +18 -0
- package/bin/loanCredit/dtos/InstallmentPaidEvent.js +5 -0
- package/bin/loanCredit/dtos/requests/CreateCustomerPaymentRequest.d.ts +3 -1
- package/bin/loanCredit/dtos/requests/CreateCustomerPaymentRequest.js +7 -0
- package/bin/loanCredit/dtos/responses/LoanCustomerPaymentOptions.d.ts +21 -2
- package/bin/loanCredit/dtos/responses/LoanCustomerPaymentResult.d.ts +2 -0
- package/bin/loanCredit/enums/LoanCustomerPaymentTypeEnum.d.ts +5 -1
- package/bin/loanCredit/enums/LoanCustomerPaymentTypeEnum.js +4 -0
- package/bin/loanCredit/index.d.ts +1 -0
- package/bin/loanCredit/index.js +1 -0
- package/bin/retailCommission/dtos/CommissionAccrual.d.ts +36 -0
- package/bin/retailCommission/dtos/CommissionApi.d.ts +241 -2
- package/bin/retailCommission/dtos/CommissionCalcTrace.d.ts +10 -0
- package/bin/retailCommission/dtos/CommissionCouponAccrual.d.ts +31 -0
- package/bin/retailCommission/dtos/CommissionCouponAccrual.js +2 -0
- package/bin/retailCommission/dtos/CommissionPayout.d.ts +84 -0
- package/bin/retailCommission/dtos/CommissionRule.d.ts +119 -0
- package/bin/retailCommission/dtos/CommissionRule.js +2 -0
- package/bin/retailCommission/enums/CommissionAggregateByEnum.d.ts +14 -0
- package/bin/retailCommission/enums/CommissionAggregateByEnum.js +18 -0
- package/bin/retailCommission/enums/CommissionBonusModeEnum.d.ts +10 -0
- package/bin/retailCommission/enums/CommissionBonusModeEnum.js +14 -0
- package/bin/retailCommission/enums/CommissionCalcStepEnum.d.ts +3 -1
- package/bin/retailCommission/enums/CommissionCalcStepEnum.js +2 -0
- package/bin/retailCommission/enums/CommissionMetricEnum.d.ts +14 -0
- package/bin/retailCommission/enums/CommissionMetricEnum.js +18 -0
- package/bin/retailCommission/enums/CommissionOperatorEnum.d.ts +15 -0
- package/bin/retailCommission/enums/CommissionOperatorEnum.js +19 -0
- package/bin/retailCommission/enums/CommissionRuleStatusEnum.d.ts +16 -0
- package/bin/retailCommission/enums/CommissionRuleStatusEnum.js +20 -0
- package/bin/retailCommission/enums/CommissionSeriesByEnum.d.ts +14 -0
- package/bin/retailCommission/enums/CommissionSeriesByEnum.js +18 -0
- package/bin/retailCommission/enums/CommissionSimulationSkipEnum.d.ts +14 -0
- package/bin/retailCommission/enums/CommissionSimulationSkipEnum.js +18 -0
- package/bin/retailCommission/enums/CommissionWindowEnum.d.ts +12 -0
- package/bin/retailCommission/enums/CommissionWindowEnum.js +16 -0
- package/bin/retailCommission/index.d.ts +10 -0
- package/bin/retailCommission/index.js +10 -0
- package/bin/retailLoan/dtos/CreateMyPaymentRequest.d.ts +3 -1
- package/bin/retailLoan/dtos/CreateMyPaymentRequest.js +7 -0
- package/bin/retailLoan/dtos/CreateMyPaymentResponse.d.ts +2 -0
- package/bin/retailLoan/dtos/MyPaymentOptions.d.ts +21 -1
- package/bin/retailLoan/enums/MyPaymentTypeEnum.d.ts +3 -2
- package/bin/retailLoan/enums/MyPaymentTypeEnum.js +2 -1
- package/bin/retailWizard/enums/RetailCommissionInboundMessageTypeEnum.d.ts +5 -0
- package/bin/retailWizard/enums/RetailCommissionInboundMessageTypeEnum.js +9 -0
- package/bin/retailWizard/events/RetailCommissionInboundMessage.d.ts +27 -1
- package/bin/retailWizard/events/RetailCommissionInboundMessage.js +70 -1
- package/bin/retailWizard/index.d.ts +1 -0
- package/bin/retailWizard/index.js +1 -0
- package/package.json +1 -1
- package/src/loanCredit/dtos/InstallmentPaidEvent.ts +20 -0
- package/src/loanCredit/dtos/requests/CreateCustomerPaymentRequest.ts +9 -2
- package/src/loanCredit/dtos/responses/LoanCustomerPaymentOptions.ts +26 -3
- package/src/loanCredit/dtos/responses/LoanCustomerPaymentResult.ts +2 -0
- package/src/loanCredit/enums/LoanCustomerPaymentTypeEnum.ts +4 -0
- package/src/loanCredit/index.ts +1 -0
- package/src/retailCommission/dtos/CommissionAccrual.ts +38 -0
- package/src/retailCommission/dtos/CommissionApi.ts +276 -2
- package/src/retailCommission/dtos/CommissionCalcTrace.ts +7 -0
- package/src/retailCommission/dtos/CommissionCouponAccrual.ts +33 -0
- package/src/retailCommission/dtos/CommissionPayout.ts +91 -0
- package/src/retailCommission/dtos/CommissionRule.ts +132 -0
- package/src/retailCommission/enums/CommissionAggregateByEnum.ts +14 -0
- package/src/retailCommission/enums/CommissionBonusModeEnum.ts +10 -0
- package/src/retailCommission/enums/CommissionCalcStepEnum.ts +2 -0
- package/src/retailCommission/enums/CommissionMetricEnum.ts +14 -0
- package/src/retailCommission/enums/CommissionOperatorEnum.ts +15 -0
- package/src/retailCommission/enums/CommissionRuleStatusEnum.ts +16 -0
- package/src/retailCommission/enums/CommissionSeriesByEnum.ts +14 -0
- package/src/retailCommission/enums/CommissionSimulationSkipEnum.ts +14 -0
- package/src/retailCommission/enums/CommissionWindowEnum.ts +12 -0
- package/src/retailCommission/index.ts +10 -0
- package/src/retailLoan/dtos/CreateMyPaymentRequest.ts +9 -2
- package/src/retailLoan/dtos/CreateMyPaymentResponse.ts +2 -0
- package/src/retailLoan/dtos/MyPaymentOptions.ts +26 -2
- package/src/retailLoan/enums/MyPaymentTypeEnum.ts +2 -1
- package/src/retailWizard/enums/RetailCommissionInboundMessageTypeEnum.ts +5 -0
- package/src/retailWizard/events/RetailCommissionInboundMessage.ts +75 -2
- package/src/retailWizard/index.ts +1 -0
|
@@ -2,12 +2,16 @@ import 'reflect-metadata';
|
|
|
2
2
|
import { plainToInstance, type ClassConstructor } from 'class-transformer';
|
|
3
3
|
import { validateSync, type ValidationError } from 'class-validator';
|
|
4
4
|
import {
|
|
5
|
+
ExternalProviderEnum,
|
|
6
|
+
LinePaymentTypeEnum,
|
|
5
7
|
RetailCommissionInboundMessage,
|
|
8
|
+
RetailCommissionInboundMessageTypeEnum,
|
|
6
9
|
RetailPromotionInboundMessage,
|
|
7
10
|
RetailPromotionInboundMessageTypeEnum,
|
|
11
|
+
SaleTypeEnum,
|
|
8
12
|
WizardLineRoleEnum,
|
|
9
13
|
} from '../../../src/retailWizard';
|
|
10
|
-
import { ItemTypeEnum } from '../../../src/retailCatalog';
|
|
14
|
+
import { ItemTypeEnum, ProductCategoryEnum, ProductTierEnum } from '../../../src/retailCatalog';
|
|
11
15
|
|
|
12
16
|
function paths(errors: ValidationError[], prefix = ''): string[] {
|
|
13
17
|
return errors.flatMap((e) => {
|
|
@@ -133,33 +137,126 @@ describe('RetailPromotionInboundMessage', () => {
|
|
|
133
137
|
});
|
|
134
138
|
});
|
|
135
139
|
|
|
140
|
+
describe('RetailCommissionInboundMessageTypeEnum', () => {
|
|
141
|
+
it('distingue venta y cancelación', () => {
|
|
142
|
+
expect(Object.values(RetailCommissionInboundMessageTypeEnum)).toEqual(['SALE_COMPLETED', 'SALE_CANCELLED']);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
136
146
|
describe('RetailCommissionInboundMessage', () => {
|
|
147
|
+
const phone = {
|
|
148
|
+
lineId: 'L1',
|
|
149
|
+
sku: 'PHONE-1',
|
|
150
|
+
qty: 1,
|
|
151
|
+
netCents: 299900,
|
|
152
|
+
itemType: ItemTypeEnum.PRODUCT,
|
|
153
|
+
category: ProductCategoryEnum.PHONE,
|
|
154
|
+
tier: ProductTierEnum.HIGH,
|
|
155
|
+
brand: 'Samsung',
|
|
156
|
+
paymentType: LinePaymentTypeEnum.CREDIT,
|
|
157
|
+
};
|
|
158
|
+
const service = {
|
|
159
|
+
lineId: 'L2',
|
|
160
|
+
sku: 'SVC-1',
|
|
161
|
+
qty: 1,
|
|
162
|
+
netCents: 9900,
|
|
163
|
+
itemType: ItemTypeEnum.SERVICE,
|
|
164
|
+
category: null,
|
|
165
|
+
tier: null,
|
|
166
|
+
brand: null,
|
|
167
|
+
paymentType: LinePaymentTypeEnum.CASH,
|
|
168
|
+
};
|
|
169
|
+
const gift = {
|
|
170
|
+
...service,
|
|
171
|
+
lineId: 'L3',
|
|
172
|
+
sku: 'CASE-1',
|
|
173
|
+
netCents: 0,
|
|
174
|
+
itemType: ItemTypeEnum.PRODUCT,
|
|
175
|
+
category: ProductCategoryEnum.ACCESSORY,
|
|
176
|
+
role: WizardLineRoleEnum.GIFT,
|
|
177
|
+
};
|
|
137
178
|
const ok = {
|
|
179
|
+
type: RetailCommissionInboundMessageTypeEnum.SALE_COMPLETED,
|
|
138
180
|
tenantId: 't',
|
|
139
181
|
retailerId: 'ret',
|
|
140
182
|
storeId: 'st',
|
|
141
183
|
saleId: 'sale-1',
|
|
142
184
|
sessionId: 'ses-1',
|
|
185
|
+
sellerRetailUserId: 'seller-1',
|
|
186
|
+
saleType: SaleTypeEnum.CREDIT,
|
|
187
|
+
externalProvider: null,
|
|
188
|
+
creditId: 'cred-1',
|
|
143
189
|
soldAt: '2026-09-28T20:00:00.000Z',
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
{ sku: 'SVC-1', qty: 1, netCents: 9900, itemType: ItemTypeEnum.SERVICE },
|
|
147
|
-
],
|
|
190
|
+
occurredAt: '2026-09-28T20:00:00.000Z',
|
|
191
|
+
lines: [phone, service, gift],
|
|
148
192
|
};
|
|
149
193
|
|
|
150
|
-
it('acepta la venta con sus líneas', () => expect(errorsOf(RetailCommissionInboundMessage, ok)).toEqual([]));
|
|
194
|
+
it('acepta la venta a crédito con sus líneas', () => expect(errorsOf(RetailCommissionInboundMessage, ok)).toEqual([]));
|
|
151
195
|
|
|
152
|
-
it('
|
|
153
|
-
|
|
154
|
-
|
|
196
|
+
it('acepta una derivada a financiera externa sin crédito', () =>
|
|
197
|
+
expect(
|
|
198
|
+
errorsOf(RetailCommissionInboundMessage, {
|
|
199
|
+
...ok,
|
|
200
|
+
saleType: SaleTypeEnum.EXTERNAL_REFERRAL,
|
|
201
|
+
externalProvider: ExternalProviderEnum.PAYJOY,
|
|
202
|
+
creditId: null,
|
|
203
|
+
}),
|
|
204
|
+
).toEqual([]));
|
|
205
|
+
|
|
206
|
+
it('acepta una cancelación con su motivo', () =>
|
|
207
|
+
expect(
|
|
208
|
+
errorsOf(RetailCommissionInboundMessage, {
|
|
209
|
+
...ok,
|
|
210
|
+
type: RetailCommissionInboundMessageTypeEnum.SALE_CANCELLED,
|
|
211
|
+
occurredAt: '2026-09-29T15:00:00.000Z',
|
|
212
|
+
cancelReason: 'el cliente se arrepintió',
|
|
213
|
+
}),
|
|
214
|
+
).toEqual([]));
|
|
215
|
+
|
|
216
|
+
it('la cancelación sin motivo también vale', () => {
|
|
217
|
+
const cancelled = { ...ok, type: RetailCommissionInboundMessageTypeEnum.SALE_CANCELLED };
|
|
218
|
+
expect(errorsOf(RetailCommissionInboundMessage, cancelled)).toEqual([]);
|
|
219
|
+
expect(errorsOf(RetailCommissionInboundMessage, { ...cancelled, cancelReason: '' })).toEqual([]);
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it('exige el tipo de mensaje, el vendedor, el tipo de venta y la identidad', () => {
|
|
223
|
+
const { type: _t, sellerRetailUserId: _s, saleType: _st, saleId: _id, soldAt: _so, occurredAt: _o, ...rest } = ok;
|
|
224
|
+
expect(errorsOf(RetailCommissionInboundMessage, rest)).toEqual(
|
|
225
|
+
expect.arrayContaining(['type', 'sellerRetailUserId', 'saleType', 'saleId', 'soldAt', 'occurredAt']),
|
|
226
|
+
);
|
|
155
227
|
});
|
|
156
228
|
|
|
157
229
|
it('rechaza sin líneas', () => expect(errorsOf(RetailCommissionInboundMessage, { ...ok, lines: [] })).toContain('lines'));
|
|
158
230
|
|
|
159
231
|
it('valida cada línea', () =>
|
|
160
232
|
expect(
|
|
161
|
-
errorsOf(RetailCommissionInboundMessage, {
|
|
162
|
-
|
|
233
|
+
errorsOf(RetailCommissionInboundMessage, {
|
|
234
|
+
...ok,
|
|
235
|
+
lines: [
|
|
236
|
+
{
|
|
237
|
+
lineId: '',
|
|
238
|
+
sku: 'X',
|
|
239
|
+
qty: 0,
|
|
240
|
+
netCents: -1,
|
|
241
|
+
itemType: 'KIT',
|
|
242
|
+
category: 'CELULAR',
|
|
243
|
+
tier: 'ORO',
|
|
244
|
+
brand: null,
|
|
245
|
+
paymentType: 'TARJETA',
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
}),
|
|
249
|
+
).toEqual(
|
|
250
|
+
expect.arrayContaining([
|
|
251
|
+
'lines.0.lineId',
|
|
252
|
+
'lines.0.qty',
|
|
253
|
+
'lines.0.netCents',
|
|
254
|
+
'lines.0.itemType',
|
|
255
|
+
'lines.0.category',
|
|
256
|
+
'lines.0.tier',
|
|
257
|
+
'lines.0.paymentType',
|
|
258
|
+
]),
|
|
259
|
+
));
|
|
163
260
|
});
|
|
164
261
|
|
|
165
262
|
describe('RetailPromotionInboundMessage — tipos nullables y ids no vacíos', () => {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { LoanInstallmentStatusEnum } from '../enums/LoanInstallmentStatusEnum';
|
|
2
|
+
/** `eventType` del outbox cuando una cuota queda pagada. */
|
|
3
|
+
export declare const INSTALLMENT_PAID_EVENT_TYPE = "InstallmentPaidV1";
|
|
4
|
+
/**
|
|
5
|
+
* Payload de `InstallmentPaidV1`: una cuota que pasó a `PAID` o `PAID_IN_ADVANCE` por cualquier
|
|
6
|
+
* camino (cargo de la cuota, revisión, adelanto, liquidación o recuperación). Se escribe al outbox en
|
|
7
|
+
* la misma transacción que la cuota. Sin PII.
|
|
8
|
+
*/
|
|
9
|
+
export interface InstallmentPaidV1Payload {
|
|
10
|
+
creditId: string;
|
|
11
|
+
installmentNumber: number;
|
|
12
|
+
/** Lo pagado de la cuota en total (capital + interés + IVA), en centavos. */
|
|
13
|
+
paidCents: number;
|
|
14
|
+
/** Instante del pago (ISO): decide el corte de la renta. */
|
|
15
|
+
paidAt: string;
|
|
16
|
+
installmentStatus: LoanInstallmentStatusEnum;
|
|
17
|
+
paymentId: string;
|
|
18
|
+
}
|
|
@@ -2,8 +2,10 @@ import { LoanCustomerPaymentTypeEnum } from '../../enums/LoanCustomerPaymentType
|
|
|
2
2
|
/** Body de `POST /private/customers/:directoryId/credits/:creditId/payments` (loan-credit-business). */
|
|
3
3
|
export declare class CreateCustomerPaymentRequest {
|
|
4
4
|
type: LoanCustomerPaymentTypeEnum;
|
|
5
|
-
/** Monto que vio el cliente; si ya no coincide, responde 409 CUSTOMER_PAYMENT_AMOUNT_CHANGED. */
|
|
5
|
+
/** Monto que vio el cliente (en PREPAYMENT, el que eligió); si ya no coincide, responde 409 CUSTOMER_PAYMENT_AMOUNT_CHANGED. */
|
|
6
6
|
expectedAmountCents: number;
|
|
7
7
|
/** Llave del reintento: la misma llave con el mismo cuerpo devuelve la misma respuesta. */
|
|
8
8
|
idempotencyKey: string;
|
|
9
|
+
/** Solo ADVANCE: cuántas cuotas adelanta. */
|
|
10
|
+
installmentCount?: number;
|
|
9
11
|
}
|
|
@@ -33,3 +33,10 @@ __decorate([
|
|
|
33
33
|
(0, class_validator_1.IsUUID)(),
|
|
34
34
|
__metadata("design:type", String)
|
|
35
35
|
], CreateCustomerPaymentRequest.prototype, "idempotencyKey", void 0);
|
|
36
|
+
__decorate([
|
|
37
|
+
(0, class_transformer_1.Expose)(),
|
|
38
|
+
(0, class_validator_1.IsOptional)(),
|
|
39
|
+
(0, class_validator_1.IsInt)(),
|
|
40
|
+
(0, class_validator_1.Min)(2),
|
|
41
|
+
__metadata("design:type", Number)
|
|
42
|
+
], CreateCustomerPaymentRequest.prototype, "installmentCount", void 0);
|
|
@@ -8,6 +8,13 @@ export interface LoanCustomerPaymentOption {
|
|
|
8
8
|
unavailableReason?: LoanPaymentOptionUnavailableReasonEnum;
|
|
9
9
|
amountCents?: number;
|
|
10
10
|
}
|
|
11
|
+
/** Una cuota que se puede adelantar. */
|
|
12
|
+
export interface LoanCustomerAdvanceInstallment {
|
|
13
|
+
installmentNumber: number;
|
|
14
|
+
/** `YYYY-MM-DD`. */
|
|
15
|
+
dueDate: string;
|
|
16
|
+
amountCents: number;
|
|
17
|
+
}
|
|
11
18
|
/** Response de `GET /private/customers/:directoryId/credits/:creditId/payment-options`. Montos en cents. */
|
|
12
19
|
export interface LoanCustomerPaymentOptions {
|
|
13
20
|
creditId: string;
|
|
@@ -15,6 +22,8 @@ export interface LoanCustomerPaymentOptions {
|
|
|
15
22
|
pendingCharge?: {
|
|
16
23
|
kind: LoanAdHocChargeKindEnum;
|
|
17
24
|
amountCents: number;
|
|
25
|
+
/** Solo en un adelanto: las cuotas que cubre. */
|
|
26
|
+
installmentNumbers?: number[];
|
|
18
27
|
};
|
|
19
28
|
nextInstallment: LoanCustomerPaymentOption & {
|
|
20
29
|
mode?: LoanNextInstallmentModeEnum;
|
|
@@ -22,8 +31,18 @@ export interface LoanCustomerPaymentOptions {
|
|
|
22
31
|
/** `YYYY-MM-DD`. */
|
|
23
32
|
dueDate?: string;
|
|
24
33
|
};
|
|
25
|
-
/** Varias cuotas
|
|
26
|
-
advance: LoanCustomerPaymentOption
|
|
34
|
+
/** Varias cuotas. `installments` trae las `maxInstallments` que se pueden adelantar, en orden. */
|
|
35
|
+
advance: LoanCustomerPaymentOption & {
|
|
36
|
+
minInstallments?: number;
|
|
37
|
+
maxInstallments?: number;
|
|
38
|
+
installments?: LoanCustomerAdvanceInstallment[];
|
|
39
|
+
};
|
|
40
|
+
/** Abono a capital: monto libre entre `minAmountCents` y `maxAmountCents`. */
|
|
41
|
+
prepayment: LoanCustomerPaymentOption & {
|
|
42
|
+
minAmountCents?: number;
|
|
43
|
+
maxAmountCents?: number;
|
|
44
|
+
outstandingCapitalCents?: number;
|
|
45
|
+
};
|
|
27
46
|
settlement: LoanCustomerPaymentOption & {
|
|
28
47
|
/** La cotización de hoy; su `settlementAmountCents` es el `amountCents`. */
|
|
29
48
|
quote?: LoanSettlementQuote;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/** Pago que el cliente puede pedir desde la app. */
|
|
2
2
|
export declare enum LoanCustomerPaymentTypeEnum {
|
|
3
3
|
NEXT_INSTALLMENT = "NEXT_INSTALLMENT",
|
|
4
|
-
SETTLEMENT = "SETTLEMENT"
|
|
4
|
+
SETTLEMENT = "SETTLEMENT",
|
|
5
|
+
/** Varias cuotas: las siguientes N tal como están, sin cambiar la tabla. */
|
|
6
|
+
ADVANCE = "ADVANCE",
|
|
7
|
+
/** Abono a capital: va completo a capital y baja las cuotas siguientes. */
|
|
8
|
+
PREPAYMENT = "PREPAYMENT"
|
|
5
9
|
}
|
|
@@ -6,4 +6,8 @@ var LoanCustomerPaymentTypeEnum;
|
|
|
6
6
|
(function (LoanCustomerPaymentTypeEnum) {
|
|
7
7
|
LoanCustomerPaymentTypeEnum["NEXT_INSTALLMENT"] = "NEXT_INSTALLMENT";
|
|
8
8
|
LoanCustomerPaymentTypeEnum["SETTLEMENT"] = "SETTLEMENT";
|
|
9
|
+
/** Varias cuotas: las siguientes N tal como están, sin cambiar la tabla. */
|
|
10
|
+
LoanCustomerPaymentTypeEnum["ADVANCE"] = "ADVANCE";
|
|
11
|
+
/** Abono a capital: va completo a capital y baja las cuotas siguientes. */
|
|
12
|
+
LoanCustomerPaymentTypeEnum["PREPAYMENT"] = "PREPAYMENT";
|
|
9
13
|
})(LoanCustomerPaymentTypeEnum || (exports.LoanCustomerPaymentTypeEnum = LoanCustomerPaymentTypeEnum = {}));
|
|
@@ -6,6 +6,7 @@ export * from './dtos/LoanBorrower';
|
|
|
6
6
|
export * from './dtos/LoanBeneficiary';
|
|
7
7
|
export * from './dtos/LoanCredit';
|
|
8
8
|
export * from './dtos/LoanInstallment';
|
|
9
|
+
export * from './dtos/InstallmentPaidEvent';
|
|
9
10
|
export * from './dtos/LoanContract';
|
|
10
11
|
export * from './dtos/ActivationChecklist';
|
|
11
12
|
export * from './dtos/AppliedPromotionSnapshot';
|
package/bin/loanCredit/index.js
CHANGED
|
@@ -27,6 +27,7 @@ __exportStar(require("./dtos/LoanBorrower"), exports);
|
|
|
27
27
|
__exportStar(require("./dtos/LoanBeneficiary"), exports);
|
|
28
28
|
__exportStar(require("./dtos/LoanCredit"), exports);
|
|
29
29
|
__exportStar(require("./dtos/LoanInstallment"), exports);
|
|
30
|
+
__exportStar(require("./dtos/InstallmentPaidEvent"), exports);
|
|
30
31
|
__exportStar(require("./dtos/LoanContract"), exports);
|
|
31
32
|
__exportStar(require("./dtos/ActivationChecklist"), exports);
|
|
32
33
|
__exportStar(require("./dtos/AppliedPromotionSnapshot"), exports);
|
|
@@ -2,6 +2,11 @@ import type { CommissionAccrualStatusEnum } from '../enums/CommissionAccrualStat
|
|
|
2
2
|
import type { CommissionPayeeTypeEnum } from '../enums/CommissionPayeeTypeEnum';
|
|
3
3
|
import type { SaleFinancierEnum } from '../../retailWizard/enums/SaleFinancierEnum';
|
|
4
4
|
import type { CommissionCalcTrace } from './CommissionCalcTrace';
|
|
5
|
+
import type { CommissionBonusModeEnum } from '../enums/CommissionBonusModeEnum';
|
|
6
|
+
import type { ProductCategoryEnum } from '../../retailCatalog/enums/ProductCategoryEnum';
|
|
7
|
+
import type { ProductTierEnum } from '../../retailCatalog/enums/ProductTierEnum';
|
|
8
|
+
import type { LinePaymentTypeEnum } from '../../retailWizard/enums/LinePaymentTypeEnum';
|
|
9
|
+
import type { WizardLineRoleEnum } from '../../retailWizard/enums/WizardLineRoleEnum';
|
|
5
10
|
/**
|
|
6
11
|
* El devengo: lo que se le debe a un vendedor por UNA venta.
|
|
7
12
|
* SureKeep Fase 3 — pista Retail.
|
|
@@ -50,6 +55,10 @@ export interface CommissionAccrual {
|
|
|
50
55
|
payoutId: string | null;
|
|
51
56
|
reversalReason: string | null;
|
|
52
57
|
calcTrace: CommissionCalcTrace;
|
|
58
|
+
/** Los bonos por venta que sumaron, uno por regla y por pieza. Solo en devengos calculados con reglas. */
|
|
59
|
+
appliedBonuses?: CommissionAppliedBonus[];
|
|
60
|
+
/** Suma de `appliedBonuses`. Solo en devengos calculados con reglas. */
|
|
61
|
+
subtotalBonusCents?: number;
|
|
53
62
|
}
|
|
54
63
|
/**
|
|
55
64
|
* Lo mínimo de una venta para devengarla. Es lo que llega por la cola y lo que se reconstruye
|
|
@@ -75,4 +84,31 @@ export interface CommissionSaleInput {
|
|
|
75
84
|
/** `CASH` | `CREDIT`, para `PERCENT_BY_PAYMENT`. */
|
|
76
85
|
paymentType: string;
|
|
77
86
|
soldAt: string;
|
|
87
|
+
/** Las líneas de la venta. Las ventas que se calculan con reglas siempre las traen. */
|
|
88
|
+
lines?: CommissionSaleLine[];
|
|
89
|
+
}
|
|
90
|
+
/** Una línea de la venta, congelada en el devengo. */
|
|
91
|
+
export interface CommissionSaleLine {
|
|
92
|
+
lineId: string;
|
|
93
|
+
sku: string;
|
|
94
|
+
qty: number;
|
|
95
|
+
/** Precio neto de la línea completa (todas sus piezas). */
|
|
96
|
+
netCents: number;
|
|
97
|
+
category: ProductCategoryEnum | null;
|
|
98
|
+
tier: ProductTierEnum | null;
|
|
99
|
+
brand: string | null;
|
|
100
|
+
paymentType: LinePaymentTypeEnum;
|
|
101
|
+
/** `GIFT` = regalo: no comisiona ni cuenta en la posición. */
|
|
102
|
+
role?: WizardLineRoleEnum;
|
|
103
|
+
}
|
|
104
|
+
/** Un bono por venta que sumó en el devengo. */
|
|
105
|
+
export interface CommissionAppliedBonus {
|
|
106
|
+
ruleId: string;
|
|
107
|
+
name: string;
|
|
108
|
+
lineId: string;
|
|
109
|
+
sku: string;
|
|
110
|
+
/** Posición de la pieza en el contador de la regla dentro del periodo. */
|
|
111
|
+
position: number;
|
|
112
|
+
mode: CommissionBonusModeEnum;
|
|
113
|
+
amountCents: number;
|
|
78
114
|
}
|
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
import type { CommissionPlanStatusEnum } from '../enums/CommissionPlanStatusEnum';
|
|
2
2
|
import type { CommissionPayoutStatusEnum } from '../enums/CommissionPayoutStatusEnum';
|
|
3
3
|
import type { CommissionAddOn, CommissionCategory, CommissionPlanSnapshot, CommissionQuota } from './CommissionPlan';
|
|
4
|
-
import type { CommissionAccrual, CommissionSaleInput } from './CommissionAccrual';
|
|
5
|
-
import type { CommissionAdjustment, CommissionPayout, CommissionPayoutSeller } from './CommissionPayout';
|
|
4
|
+
import type { CommissionAccrual, CommissionAppliedBonus, CommissionSaleInput, CommissionSaleLine } from './CommissionAccrual';
|
|
5
|
+
import type { CommissionAdjustment, CommissionAppliedMultiplier, CommissionAppliedThreshold, CommissionPayout, CommissionPayoutSeller, CommissionSellerBreakdown } from './CommissionPayout';
|
|
6
|
+
import type { CommissionPolicies, CommissionRule, CommissionRuleCondition, CommissionRuleLevers, CommissionRuleScope, CommissionRuleSetSnapshot } from './CommissionRule';
|
|
7
|
+
import type { CommissionWindowEnum } from '../enums/CommissionWindowEnum';
|
|
8
|
+
import type { CommissionAggregateByEnum } from '../enums/CommissionAggregateByEnum';
|
|
9
|
+
import type { CommissionSeriesByEnum } from '../enums/CommissionSeriesByEnum';
|
|
10
|
+
import type { CommissionAccrualStatusEnum } from '../enums/CommissionAccrualStatusEnum';
|
|
11
|
+
import type { CommissionSimulationSkipEnum } from '../enums/CommissionSimulationSkipEnum';
|
|
12
|
+
import type { ProductCategoryEnum } from '../../retailCatalog/enums/ProductCategoryEnum';
|
|
13
|
+
import type { ProductTierEnum } from '../../retailCatalog/enums/ProductTierEnum';
|
|
6
14
|
/**
|
|
7
15
|
* Los contratos HTTP del motor de comisiones — uno por endpoint, sin reutilizar.
|
|
8
16
|
* SureKeep Fase 3 — pista Retail.
|
|
@@ -167,3 +175,234 @@ export interface ClosePayoutResponse {
|
|
|
167
175
|
}
|
|
168
176
|
/** Lo que el simulador reconstruye desde el data lake para volver a correr el motor. */
|
|
169
177
|
export type CommissionSimulationSale = CommissionSaleInput;
|
|
178
|
+
/** `GET /backoffice/commissions/plan` — el plan vigente con reglas. `null` mientras no se publica nada. */
|
|
179
|
+
export interface GetRuleSetResponse {
|
|
180
|
+
active: CommissionRuleSetSnapshot | null;
|
|
181
|
+
}
|
|
182
|
+
/** `GET /backoffice/commissions/rules` — la última versión de cada regla. */
|
|
183
|
+
export interface ListRulesResponse {
|
|
184
|
+
rules: CommissionRule[];
|
|
185
|
+
}
|
|
186
|
+
/** Lo que el editor manda al crear o guardar una regla. */
|
|
187
|
+
export interface CommissionRuleInput {
|
|
188
|
+
name: string;
|
|
189
|
+
description: string | null;
|
|
190
|
+
levers: CommissionRuleLevers;
|
|
191
|
+
scope: CommissionRuleScope;
|
|
192
|
+
condition: CommissionRuleCondition | null;
|
|
193
|
+
effectiveFrom: string;
|
|
194
|
+
effectiveTo: string | null;
|
|
195
|
+
priority: number;
|
|
196
|
+
replacesOthers: boolean;
|
|
197
|
+
}
|
|
198
|
+
/** `POST /backoffice/commissions/rules` — la regla nace en borrador. */
|
|
199
|
+
export type CreateRuleRequest = CommissionRuleInput;
|
|
200
|
+
/** `PUT /backoffice/commissions/rules/{ruleId}` — `expectedVersion` es la versión que el editor cargó. */
|
|
201
|
+
export interface UpdateRuleRequest extends CommissionRuleInput {
|
|
202
|
+
expectedVersion: number;
|
|
203
|
+
}
|
|
204
|
+
export interface RuleResponse {
|
|
205
|
+
rule: CommissionRule;
|
|
206
|
+
}
|
|
207
|
+
/** `POST /backoffice/commissions/rules/{ruleId}/publish | pause | resume | expire` */
|
|
208
|
+
export interface RuleActionRequest {
|
|
209
|
+
expectedVersion: number;
|
|
210
|
+
}
|
|
211
|
+
/** Las acciones que cambian el plan vigente devuelven la regla y el snapshot nuevo. */
|
|
212
|
+
export interface RuleActionResponse {
|
|
213
|
+
rule: CommissionRule;
|
|
214
|
+
snapshotId: string;
|
|
215
|
+
}
|
|
216
|
+
/** Un evento del historial de una regla. */
|
|
217
|
+
export interface CommissionRuleEvent {
|
|
218
|
+
at: string;
|
|
219
|
+
action: string;
|
|
220
|
+
performedBy: string;
|
|
221
|
+
version: number | null;
|
|
222
|
+
}
|
|
223
|
+
/** `GET /backoffice/commissions/rules/{ruleId}/history` — del más nuevo al más viejo. */
|
|
224
|
+
export interface RuleHistoryResponse {
|
|
225
|
+
events: CommissionRuleEvent[];
|
|
226
|
+
}
|
|
227
|
+
/** `GET /backoffice/commissions/policies` */
|
|
228
|
+
export interface GetPoliciesResponse {
|
|
229
|
+
policies: CommissionPolicies;
|
|
230
|
+
}
|
|
231
|
+
/** `PUT /backoffice/commissions/policies` — las dos políticas se guardan juntas. */
|
|
232
|
+
export interface UpdatePoliciesRequest {
|
|
233
|
+
clawback: {
|
|
234
|
+
cancelacionDias: number;
|
|
235
|
+
devolucionDias: number;
|
|
236
|
+
npiM30Dias: number;
|
|
237
|
+
};
|
|
238
|
+
commissions: {
|
|
239
|
+
multiplicadorMaxBps: number;
|
|
240
|
+
ventanaDefault: CommissionWindowEnum;
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
export interface UpdatePoliciesResponse {
|
|
244
|
+
policies: CommissionPolicies;
|
|
245
|
+
snapshotId: string;
|
|
246
|
+
}
|
|
247
|
+
/** `GET /backoffice/commissions/live?periodId=` — el corte calculado al momento, sin escribir nada. */
|
|
248
|
+
export interface GetLivePayoutResponse {
|
|
249
|
+
periodId: string;
|
|
250
|
+
periodStart: string;
|
|
251
|
+
periodEnd: string;
|
|
252
|
+
status: CommissionPayoutStatusEnum;
|
|
253
|
+
sellers: CommissionSellerBreakdown[];
|
|
254
|
+
}
|
|
255
|
+
/** Una venta del vendedor en el corte, con sus bonos recalculados en orden. Sin datos del cliente. */
|
|
256
|
+
export interface CommissionLiveSale {
|
|
257
|
+
saleId: string;
|
|
258
|
+
soldAt: string;
|
|
259
|
+
storeId: string;
|
|
260
|
+
status: CommissionAccrualStatusEnum;
|
|
261
|
+
/** El snapshot con el que se devengó: es el que se usa para recalcularla. */
|
|
262
|
+
planSnapshotId: string;
|
|
263
|
+
lines: CommissionSaleLine[];
|
|
264
|
+
appliedBonuses: CommissionAppliedBonus[];
|
|
265
|
+
subtotalBonusCents: number;
|
|
266
|
+
}
|
|
267
|
+
/** `GET /backoffice/commissions/live/sellers/{sellerId}?periodId=` */
|
|
268
|
+
export interface GetLiveSellerResponse {
|
|
269
|
+
periodId: string;
|
|
270
|
+
seller: CommissionSellerBreakdown;
|
|
271
|
+
sales: CommissionLiveSale[];
|
|
272
|
+
}
|
|
273
|
+
/** Un renglón del agregado. `name` es el de la regla; tienda, SKU y vendedor los resuelve el front. */
|
|
274
|
+
export interface CommissionAggregateRow {
|
|
275
|
+
key: string;
|
|
276
|
+
name: string | null;
|
|
277
|
+
sellersCount: number;
|
|
278
|
+
salesCount: number;
|
|
279
|
+
unitsCount: number;
|
|
280
|
+
placementCents: number;
|
|
281
|
+
paidCents: number;
|
|
282
|
+
}
|
|
283
|
+
/** `GET /backoffice/commissions/payouts/aggregates?by=&from=&to=` — sobre los cortes cerrados del rango. */
|
|
284
|
+
export interface GetPayoutAggregatesResponse {
|
|
285
|
+
by: CommissionAggregateByEnum;
|
|
286
|
+
from: string;
|
|
287
|
+
to: string;
|
|
288
|
+
/** Los cortes cerrados que entraron. */
|
|
289
|
+
periodIds: string[];
|
|
290
|
+
rows: CommissionAggregateRow[];
|
|
291
|
+
totalPaidCents: number;
|
|
292
|
+
}
|
|
293
|
+
/** Un punto de la serie: un corte cerrado. */
|
|
294
|
+
export interface CommissionSeriesPoint {
|
|
295
|
+
periodId: string;
|
|
296
|
+
salesCount: number;
|
|
297
|
+
unitsCount: number;
|
|
298
|
+
placementCents: number;
|
|
299
|
+
paidCents: number;
|
|
300
|
+
}
|
|
301
|
+
/** `GET /backoffice/commissions/payouts/series?by=&id=&weeks=` — del corte más viejo al más nuevo. */
|
|
302
|
+
export interface GetPayoutSeriesResponse {
|
|
303
|
+
by: CommissionSeriesByEnum;
|
|
304
|
+
id: string;
|
|
305
|
+
points: CommissionSeriesPoint[];
|
|
306
|
+
}
|
|
307
|
+
/** El vendedor modelo: cómo va su semana. */
|
|
308
|
+
export interface CommissionSimulationProfile {
|
|
309
|
+
unitsInWeek: number;
|
|
310
|
+
placementCents: number;
|
|
311
|
+
distinctSkus: number;
|
|
312
|
+
}
|
|
313
|
+
/** El producto que vende en la simulación. */
|
|
314
|
+
export interface CommissionSimulationProduct {
|
|
315
|
+
sku: string;
|
|
316
|
+
category: ProductCategoryEnum | null;
|
|
317
|
+
tier: ProductTierEnum | null;
|
|
318
|
+
netCents: number;
|
|
319
|
+
}
|
|
320
|
+
/** `POST /backoffice/commissions/rules/simulate` */
|
|
321
|
+
export interface SimulateRulesRequest {
|
|
322
|
+
/** Reglas por id, en su última versión, como si estuvieran publicadas. Vacío = el plan vigente. */
|
|
323
|
+
ruleIds: string[];
|
|
324
|
+
profile: CommissionSimulationProfile;
|
|
325
|
+
product: CommissionSimulationProduct;
|
|
326
|
+
/** Con tienda se evalúa el alcance por tienda; sin ella, se ignora. */
|
|
327
|
+
storeId: string | null;
|
|
328
|
+
/** `YYYY-MM-DD`. `null` = hoy. */
|
|
329
|
+
date: string | null;
|
|
330
|
+
}
|
|
331
|
+
/** Lo que una regla de bono por venta pagaría en una posición, o por qué no. */
|
|
332
|
+
export interface CommissionSimulatedRule {
|
|
333
|
+
ruleId: string;
|
|
334
|
+
name: string;
|
|
335
|
+
amountCents: number;
|
|
336
|
+
skipped: CommissionSimulationSkipEnum | null;
|
|
337
|
+
}
|
|
338
|
+
export interface SimulateRulesResponse {
|
|
339
|
+
date: string;
|
|
340
|
+
/** La venta siguiente, en la posición `unitsInWeek + 1`. */
|
|
341
|
+
nextSale: {
|
|
342
|
+
position: number;
|
|
343
|
+
subtotalBonusCents: number;
|
|
344
|
+
rules: CommissionSimulatedRule[];
|
|
345
|
+
};
|
|
346
|
+
/** Las piezas de la semana, en las posiciones 1 a `unitsInWeek`. */
|
|
347
|
+
progression: Array<{
|
|
348
|
+
position: number;
|
|
349
|
+
subtotalBonusCents: number;
|
|
350
|
+
cumulativeBonusCents: number;
|
|
351
|
+
}>;
|
|
352
|
+
/** El corte de esa semana. */
|
|
353
|
+
week: {
|
|
354
|
+
subtotalBonusCents: number;
|
|
355
|
+
multiplierBps: number;
|
|
356
|
+
multiplierBeforeCapBps: number;
|
|
357
|
+
multipliers: CommissionAppliedMultiplier[];
|
|
358
|
+
thresholdBonusCents: number;
|
|
359
|
+
thresholds: CommissionAppliedThreshold[];
|
|
360
|
+
releasedCents: number;
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
/** Una regla como la ve el vendedor: sin estado interno ni datos de auditoría. */
|
|
364
|
+
export interface CommissionRuleView {
|
|
365
|
+
ruleId: string;
|
|
366
|
+
name: string;
|
|
367
|
+
description: string | null;
|
|
368
|
+
levers: CommissionRuleLevers;
|
|
369
|
+
scope: CommissionRuleScope;
|
|
370
|
+
condition: CommissionRuleCondition | null;
|
|
371
|
+
effectiveFrom: string;
|
|
372
|
+
effectiveTo: string | null;
|
|
373
|
+
}
|
|
374
|
+
/** Lo pagado en varios cortes. */
|
|
375
|
+
export interface MyCommissionsTotals {
|
|
376
|
+
periodsCount: number;
|
|
377
|
+
salesCount: number;
|
|
378
|
+
unitsCount: number;
|
|
379
|
+
netCents: number;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* `GET /commissions/me?weeks=` — las comisiones del vendedor que llama. El vendedor sale del token;
|
|
383
|
+
* no se puede pedir el de otro.
|
|
384
|
+
*/
|
|
385
|
+
export interface GetMyCommissionsResponse {
|
|
386
|
+
seller: {
|
|
387
|
+
sellerId: string;
|
|
388
|
+
name: string | null;
|
|
389
|
+
storeId: string | null;
|
|
390
|
+
};
|
|
391
|
+
period: {
|
|
392
|
+
periodId: string;
|
|
393
|
+
periodStart: string;
|
|
394
|
+
periodEnd: string;
|
|
395
|
+
};
|
|
396
|
+
/** El corte en curso; `null` si todavía no tiene ventas, renta ni ajustes. */
|
|
397
|
+
week: CommissionSellerBreakdown | null;
|
|
398
|
+
/** Cortes cuya semana empieza en el mes de hoy: cerrados, el anterior aún sin cerrar y el en curso. */
|
|
399
|
+
month: MyCommissionsTotals;
|
|
400
|
+
/** Cortes cuya semana empieza en el año de hoy: cerrados, el anterior aún sin cerrar y el en curso. */
|
|
401
|
+
year: MyCommissionsTotals;
|
|
402
|
+
/** Los cortes cerrados de las últimas `weeks` semanas, del más viejo al más nuevo. `paidCents` es el neto. */
|
|
403
|
+
history: CommissionSeriesPoint[];
|
|
404
|
+
/** Las reglas vigentes hoy que pueden pagarle: las de corte, las sin tienda y las de su tienda o de donde vendió. */
|
|
405
|
+
rules: CommissionRuleView[];
|
|
406
|
+
/** Tope del multiplicador de la política; `null` sin política. */
|
|
407
|
+
multiplierCapBps: number | null;
|
|
408
|
+
}
|
|
@@ -69,5 +69,15 @@ export type CommissionCalcTraceEntry = {
|
|
|
69
69
|
sku: string;
|
|
70
70
|
brand: string | null;
|
|
71
71
|
};
|
|
72
|
+
} | {
|
|
73
|
+
/** Una regla con bono por venta sumó por una pieza. */
|
|
74
|
+
step: CommissionCalcStepEnum.BONUS_PER_SALE;
|
|
75
|
+
label: string;
|
|
76
|
+
outputCents: number;
|
|
77
|
+
detail: {
|
|
78
|
+
ruleId: string;
|
|
79
|
+
lineId: string;
|
|
80
|
+
position: number;
|
|
81
|
+
};
|
|
72
82
|
};
|
|
73
83
|
export type CommissionCalcTrace = CommissionCalcTraceEntry[];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CommissionAccrualStatusEnum } from '../enums/CommissionAccrualStatusEnum';
|
|
2
|
+
import type { CommissionBonusModeEnum } from '../enums/CommissionBonusModeEnum';
|
|
3
|
+
/** Lo que paga una regla de renta de cartera por una cuota cobrada. */
|
|
4
|
+
export interface CommissionCouponAppliedBonus {
|
|
5
|
+
ruleId: string;
|
|
6
|
+
name: string;
|
|
7
|
+
mode: CommissionBonusModeEnum;
|
|
8
|
+
amountCents: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* La renta de cartera de una cuota pagada, en el corte de su pago.
|
|
12
|
+
* Clave `SELLER#<sellerId>` · `COUPON#<periodId>#<creditId>#<cuota>`: determinista, idempotente.
|
|
13
|
+
*/
|
|
14
|
+
export interface CommissionCouponAccrual {
|
|
15
|
+
sellerId: string;
|
|
16
|
+
retailerId: string;
|
|
17
|
+
periodId: string;
|
|
18
|
+
creditId: string;
|
|
19
|
+
/** La venta que originó el crédito. */
|
|
20
|
+
saleId: string;
|
|
21
|
+
installmentNumber: number;
|
|
22
|
+
/** Lo pagado de la cuota (capital + interés + IVA). */
|
|
23
|
+
couponAmountCents: number;
|
|
24
|
+
paidAt: string;
|
|
25
|
+
/** El snapshot con que se evaluó: de ahí salen las condiciones al cerrar el corte. */
|
|
26
|
+
planSnapshotId: string;
|
|
27
|
+
bonuses: CommissionCouponAppliedBonus[];
|
|
28
|
+
subtotalCents: number;
|
|
29
|
+
status: CommissionAccrualStatusEnum;
|
|
30
|
+
createdAt: string;
|
|
31
|
+
}
|