@fiado/type-kit 3.505.0 → 3.506.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/retailCommission/latestClosedPayout.test.ts +29 -0
- package/_test_/unit/retailOrg/dtos/sellerTableSources.test.ts +62 -0
- package/_test_/unit/retailWizard/sellerTableShapes.test.ts +43 -0
- package/bin/retailCommission/dtos/PrivateLatestClosedPayout.d.ts +24 -0
- package/bin/retailCommission/dtos/PrivateLatestClosedPayout.js +24 -0
- package/bin/retailCommission/index.d.ts +1 -0
- package/bin/retailCommission/index.js +1 -0
- package/bin/retailOrg/dtos/requests/PrivateGoalListQuery.d.ts +12 -0
- package/bin/retailOrg/dtos/requests/PrivateGoalListQuery.js +40 -0
- package/bin/retailOrg/dtos/requests/PrivateSellerListQuery.d.ts +2 -0
- package/bin/retailOrg/dtos/requests/PrivateSellerListQuery.js +6 -0
- package/bin/retailOrg/dtos/responses/PrivateGoalListResponse.d.ts +8 -0
- package/bin/retailOrg/dtos/responses/PrivateGoalListResponse.js +2 -0
- package/bin/retailOrg/dtos/validation/PrivateSellerListResponse.d.ts +2 -0
- package/bin/retailOrg/dtos/validation/StoreValidationDto.d.ts +2 -0
- package/bin/retailOrg/index.d.ts +2 -0
- package/bin/retailOrg/index.js +2 -0
- package/bin/retailWizard/dtos/responses/BackofficeSellerTableResponse.d.ts +57 -0
- package/bin/retailWizard/dtos/responses/BackofficeSellerTableResponse.js +2 -0
- package/bin/retailWizard/enums/SellerTableSourceStatusEnum.d.ts +5 -0
- package/bin/retailWizard/enums/SellerTableSourceStatusEnum.js +9 -0
- package/bin/retailWizard/index.d.ts +2 -0
- package/bin/retailWizard/index.js +2 -0
- package/package.json +1 -1
- package/src/retailCommission/dtos/PrivateLatestClosedPayout.ts +33 -0
- package/src/retailCommission/index.ts +1 -0
- package/src/retailOrg/dtos/requests/PrivateGoalListQuery.ts +27 -0
- package/src/retailOrg/dtos/requests/PrivateSellerListQuery.ts +8 -2
- package/src/retailOrg/dtos/responses/PrivateGoalListResponse.ts +9 -0
- package/src/retailOrg/dtos/validation/PrivateSellerListResponse.ts +2 -0
- package/src/retailOrg/dtos/validation/StoreValidationDto.ts +2 -0
- package/src/retailOrg/index.ts +2 -0
- package/src/retailWizard/dtos/responses/BackofficeSellerTableResponse.ts +61 -0
- package/src/retailWizard/enums/SellerTableSourceStatusEnum.ts +5 -0
- package/src/retailWizard/index.ts +2 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validateSync } from 'class-validator';
|
|
4
|
+
import {
|
|
5
|
+
PrivateLatestClosedPayoutQuery,
|
|
6
|
+
type PrivateLatestClosedPayoutResponse,
|
|
7
|
+
} from '../../../src/retailCommission';
|
|
8
|
+
|
|
9
|
+
describe('PrivateLatestClosedPayoutQuery', () => {
|
|
10
|
+
const errorsOf = (payload: object) =>
|
|
11
|
+
validateSync(plainToInstance(PrivateLatestClosedPayoutQuery, payload, { excludeExtraneousValues: true })).map(
|
|
12
|
+
(e) => e.property,
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
it('acepta un retailerId', () => expect(errorsOf({ retailerId: 'r-1' })).toEqual([]));
|
|
16
|
+
it('exige el retailerId', () => expect(errorsOf({})).toContain('retailerId'));
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe('PrivateLatestClosedPayoutResponse', () => {
|
|
20
|
+
it('sin corte cerrado el periodo viaja en null', () => {
|
|
21
|
+
const empty: PrivateLatestClosedPayoutResponse = { retailerId: 'r-1', period: null, sellers: [] };
|
|
22
|
+
const closed: PrivateLatestClosedPayoutResponse = {
|
|
23
|
+
retailerId: 'r-1',
|
|
24
|
+
period: { periodId: '2026-09-28', from: '2026-09-28', to: '2026-10-04' },
|
|
25
|
+
sellers: [{ retailUserId: 'u-1', amountCents: 12000 }],
|
|
26
|
+
};
|
|
27
|
+
expect([empty.period, closed.sellers[0].amountCents]).toEqual([null, 12000]);
|
|
28
|
+
});
|
|
29
|
+
});
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance, type ClassConstructor } from 'class-transformer';
|
|
3
|
+
import { validateSync } from 'class-validator';
|
|
4
|
+
import {
|
|
5
|
+
GoalTargetTypeEnum,
|
|
6
|
+
PrivateGoalListQuery,
|
|
7
|
+
PrivateSellerListQuery,
|
|
8
|
+
type PrivateGoalListResponse,
|
|
9
|
+
type PrivateSellerDto,
|
|
10
|
+
type StoreValidationDto,
|
|
11
|
+
} from '../../../../src/retailOrg';
|
|
12
|
+
|
|
13
|
+
const RETAILER = '01J9ZQ0000000000000000000A';
|
|
14
|
+
|
|
15
|
+
function errorsOf<T extends object>(cls: ClassConstructor<T>, payload: object): string[] {
|
|
16
|
+
return validateSync(plainToInstance(cls, payload, { excludeExtraneousValues: true }) as object).map(
|
|
17
|
+
(e) => e.property,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
describe('PrivateGoalListQuery', () => {
|
|
22
|
+
it('acepta retailer, periodo y tipo', () =>
|
|
23
|
+
expect(errorsOf(PrivateGoalListQuery, { retailerId: RETAILER, periodId: '2026-10', targetType: 'SELLER' })).toEqual([]));
|
|
24
|
+
it('acepta sin tipo', () => expect(errorsOf(PrivateGoalListQuery, { retailerId: RETAILER, periodId: '2026-10' })).toEqual([]));
|
|
25
|
+
it('rechaza un retailerId que no es ULID', () =>
|
|
26
|
+
expect(errorsOf(PrivateGoalListQuery, { retailerId: 'x', periodId: '2026-10' })).toContain('retailerId'));
|
|
27
|
+
it('rechaza el mes 13', () =>
|
|
28
|
+
expect(errorsOf(PrivateGoalListQuery, { retailerId: RETAILER, periodId: '2026-13' })).toContain('periodId'));
|
|
29
|
+
it('rechaza un tipo fuera del catálogo', () =>
|
|
30
|
+
expect(errorsOf(PrivateGoalListQuery, { retailerId: RETAILER, periodId: '2026-10', targetType: 'ZONE' })).toContain(
|
|
31
|
+
'targetType',
|
|
32
|
+
));
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('PrivateSellerListQuery.includePhone', () => {
|
|
36
|
+
it('lee "true" como verdadero', () => {
|
|
37
|
+
const q = plainToInstance(PrivateSellerListQuery, { retailerId: RETAILER, includePhone: 'true' }, { excludeExtraneousValues: true });
|
|
38
|
+
expect(q.includePhone).toBe(true);
|
|
39
|
+
expect(validateSync(q)).toEqual([]);
|
|
40
|
+
});
|
|
41
|
+
it('sin el parámetro queda en falso', () => {
|
|
42
|
+
const q = plainToInstance(PrivateSellerListQuery, { retailerId: RETAILER }, { excludeExtraneousValues: true });
|
|
43
|
+
expect(q.includePhone).toBe(false);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('shapes de los privados del padrón', () => {
|
|
48
|
+
it('la tienda publica a su encargado y el vendedor su teléfono opcional', () => {
|
|
49
|
+
const store: StoreValidationDto = {
|
|
50
|
+
storeId: 's', retailerId: RETAILER, zoneId: null, zoneName: null, code: 'C', name: 'N', status: 'ACTIVE' as never,
|
|
51
|
+
managerRetailUserId: 'u-1',
|
|
52
|
+
};
|
|
53
|
+
const seller: PrivateSellerDto = {
|
|
54
|
+
sellerId: 'u-1', displayName: null, homeStoreId: 's', commissionTier: 'seller', status: 'ACTIVE' as never, phone: null,
|
|
55
|
+
};
|
|
56
|
+
const goals: PrivateGoalListResponse = {
|
|
57
|
+
retailerId: RETAILER, periodId: '2026-10',
|
|
58
|
+
goals: [{ targetId: 'u-1', targetType: GoalTargetTypeEnum.SELLER, monthCents: 3000, weekCents: 750, dayCents: 107 }],
|
|
59
|
+
};
|
|
60
|
+
expect([store.managerRetailUserId, seller.phone, goals.goals.length]).toEqual(['u-1', null, 1]);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import {
|
|
3
|
+
SellerTableSourceStatusEnum,
|
|
4
|
+
type BackofficeSellerTableResponse,
|
|
5
|
+
} from '../../../src/retailWizard';
|
|
6
|
+
|
|
7
|
+
describe('BackofficeSellerTableResponse', () => {
|
|
8
|
+
it('declara las tres fuentes y una fila completa', () => {
|
|
9
|
+
const response: BackofficeSellerTableResponse = {
|
|
10
|
+
from: '2026-09-07T06:00:00.000Z',
|
|
11
|
+
to: '2026-10-07T05:59:59.999Z',
|
|
12
|
+
truncated: false,
|
|
13
|
+
sources: {
|
|
14
|
+
roster: SellerTableSourceStatusEnum.OK,
|
|
15
|
+
goals: SellerTableSourceStatusEnum.UNAVAILABLE,
|
|
16
|
+
commission: SellerTableSourceStatusEnum.OK,
|
|
17
|
+
},
|
|
18
|
+
commissionPeriod: { periodId: '2026-09-28', from: '2026-09-28', to: '2026-10-04' },
|
|
19
|
+
items: [
|
|
20
|
+
{
|
|
21
|
+
retailUserId: 'u-1',
|
|
22
|
+
name: 'Ana',
|
|
23
|
+
status: 'ACTIVE' as never,
|
|
24
|
+
phone: null,
|
|
25
|
+
storeId: null,
|
|
26
|
+
storeName: null,
|
|
27
|
+
zoneName: null,
|
|
28
|
+
isStoreAdmin: false,
|
|
29
|
+
salesCount: 0,
|
|
30
|
+
placedCents: 0,
|
|
31
|
+
averageTicketCents: null,
|
|
32
|
+
lastSaleAt: null,
|
|
33
|
+
weekOverWeekChangePct: null,
|
|
34
|
+
goalCents: null,
|
|
35
|
+
commissionCents: null,
|
|
36
|
+
npiM30Pct: null,
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
expect(Object.values(SellerTableSourceStatusEnum)).toEqual(['OK', 'UNAVAILABLE']);
|
|
41
|
+
expect(response.items[0].npiM30Pct).toBeNull();
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Query de `GET /private/retailers/{retailerId}/payouts/latest-closed`. */
|
|
2
|
+
export declare class PrivateLatestClosedPayoutQuery {
|
|
3
|
+
retailerId: string;
|
|
4
|
+
}
|
|
5
|
+
/** Lo que el corte le paga a un vendedor: liberado más ajustes, en centavos. */
|
|
6
|
+
export interface PrivateClosedPayoutSeller {
|
|
7
|
+
retailUserId: string;
|
|
8
|
+
amountCents: number;
|
|
9
|
+
}
|
|
10
|
+
/** El corte semanal; `from` y `to` son días locales `YYYY-MM-DD`, ambos incluidos. */
|
|
11
|
+
export interface PrivateClosedPayoutPeriod {
|
|
12
|
+
periodId: string;
|
|
13
|
+
from: string;
|
|
14
|
+
to: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Respuesta de `GET /private/retailers/{retailerId}/payouts/latest-closed`: el último corte semanal
|
|
18
|
+
* CERRADO de la cadena. Sin corte cerrado reciente, `period: null` y `sellers: []`.
|
|
19
|
+
*/
|
|
20
|
+
export interface PrivateLatestClosedPayoutResponse {
|
|
21
|
+
retailerId: string;
|
|
22
|
+
period: PrivateClosedPayoutPeriod | null;
|
|
23
|
+
sellers: PrivateClosedPayoutSeller[];
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.PrivateLatestClosedPayoutQuery = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
/** Query de `GET /private/retailers/{retailerId}/payouts/latest-closed`. */
|
|
16
|
+
class PrivateLatestClosedPayoutQuery {
|
|
17
|
+
}
|
|
18
|
+
exports.PrivateLatestClosedPayoutQuery = PrivateLatestClosedPayoutQuery;
|
|
19
|
+
__decorate([
|
|
20
|
+
(0, class_transformer_1.Expose)(),
|
|
21
|
+
(0, class_validator_1.IsString)(),
|
|
22
|
+
(0, class_validator_1.IsNotEmpty)(),
|
|
23
|
+
__metadata("design:type", String)
|
|
24
|
+
], PrivateLatestClosedPayoutQuery.prototype, "retailerId", void 0);
|
|
@@ -46,3 +46,4 @@ __exportStar(require("./dtos/CommissionAccrual"), exports);
|
|
|
46
46
|
__exportStar(require("./dtos/CommissionPayout"), exports);
|
|
47
47
|
// Contratos HTTP — uno por endpoint
|
|
48
48
|
__exportStar(require("./dtos/CommissionApi"), exports);
|
|
49
|
+
__exportStar(require("./dtos/PrivateLatestClosedPayout"), exports);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GoalTargetTypeEnum } from '../../enums/GoalTargetTypeEnum';
|
|
2
|
+
/**
|
|
3
|
+
* Query de `GET /private/retailers/{retailerId}/goals` — las metas de un periodo, M2M.
|
|
4
|
+
* El `retailerId` llega en el path; la seguridad del privado es de red, no de identidad.
|
|
5
|
+
*/
|
|
6
|
+
export declare class PrivateGoalListQuery {
|
|
7
|
+
retailerId: string;
|
|
8
|
+
/** Mes calendario `YYYY-MM` (mes 01-12). */
|
|
9
|
+
periodId: string;
|
|
10
|
+
/** Si falta, devuelve los dos tipos. */
|
|
11
|
+
targetType?: GoalTargetTypeEnum;
|
|
12
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
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.PrivateGoalListQuery = void 0;
|
|
13
|
+
const class_transformer_1 = require("class-transformer");
|
|
14
|
+
const class_validator_1 = require("class-validator");
|
|
15
|
+
const GoalTargetTypeEnum_1 = require("../../enums/GoalTargetTypeEnum");
|
|
16
|
+
/** ULID canónico: 26 chars Crockford base32, primer char 0-7. */
|
|
17
|
+
const ULID = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
18
|
+
/**
|
|
19
|
+
* Query de `GET /private/retailers/{retailerId}/goals` — las metas de un periodo, M2M.
|
|
20
|
+
* El `retailerId` llega en el path; la seguridad del privado es de red, no de identidad.
|
|
21
|
+
*/
|
|
22
|
+
class PrivateGoalListQuery {
|
|
23
|
+
}
|
|
24
|
+
exports.PrivateGoalListQuery = PrivateGoalListQuery;
|
|
25
|
+
__decorate([
|
|
26
|
+
(0, class_transformer_1.Expose)(),
|
|
27
|
+
(0, class_validator_1.Matches)(ULID, { message: 'retailerId debe ser un ULID' }),
|
|
28
|
+
__metadata("design:type", String)
|
|
29
|
+
], PrivateGoalListQuery.prototype, "retailerId", void 0);
|
|
30
|
+
__decorate([
|
|
31
|
+
(0, class_transformer_1.Expose)(),
|
|
32
|
+
(0, class_validator_1.Matches)(/^\d{4}-(0[1-9]|1[0-2])$/, { message: 'periodId debe tener formato YYYY-MM (mes 01-12)' }),
|
|
33
|
+
__metadata("design:type", String)
|
|
34
|
+
], PrivateGoalListQuery.prototype, "periodId", void 0);
|
|
35
|
+
__decorate([
|
|
36
|
+
(0, class_transformer_1.Expose)(),
|
|
37
|
+
(0, class_validator_1.IsOptional)(),
|
|
38
|
+
(0, class_validator_1.IsEnum)(GoalTargetTypeEnum_1.GoalTargetTypeEnum),
|
|
39
|
+
__metadata("design:type", String)
|
|
40
|
+
], PrivateGoalListQuery.prototype, "targetType", void 0);
|
|
@@ -43,3 +43,9 @@ __decorate([
|
|
|
43
43
|
(0, class_validator_1.Matches)(/^[a-z0-9-]{1,64}$/, { message: 'callerService debe ser el nombre del lambda (kebab-case)' }),
|
|
44
44
|
__metadata("design:type", String)
|
|
45
45
|
], PrivateSellerListQuery.prototype, "callerService", void 0);
|
|
46
|
+
__decorate([
|
|
47
|
+
(0, class_transformer_1.Expose)(),
|
|
48
|
+
(0, class_transformer_1.Transform)(({ value }) => value === true || value === 'true'),
|
|
49
|
+
(0, class_validator_1.IsBoolean)(),
|
|
50
|
+
__metadata("design:type", Boolean)
|
|
51
|
+
], PrivateSellerListQuery.prototype, "includePhone", void 0);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { GoalListResponse } from './GoalListResponse';
|
|
2
|
+
/**
|
|
3
|
+
* Respuesta de `GET /private/retailers/{retailerId}/goals`: las metas del periodo con las tres cifras
|
|
4
|
+
* derivadas. Un periodo sin metas devuelve `goals: []`, no un 404.
|
|
5
|
+
*/
|
|
6
|
+
export interface PrivateGoalListResponse extends GoalListResponse {
|
|
7
|
+
retailerId: string;
|
|
8
|
+
}
|
|
@@ -15,6 +15,8 @@ export interface PrivateSellerDto {
|
|
|
15
15
|
homeStoreId: string | null;
|
|
16
16
|
commissionTier: string;
|
|
17
17
|
status: RetailUserStatusEnum;
|
|
18
|
+
/** Teléfono del vendedor. Solo viaja si se pidió `includePhone=true`; `null` si no lo tiene. */
|
|
19
|
+
phone?: string | null;
|
|
18
20
|
}
|
|
19
21
|
/**
|
|
20
22
|
* Respuesta de `GET /private/sellers?retailerId=…` — el padrón de una cadena, para máquinas.
|
package/bin/retailOrg/index.d.ts
CHANGED
|
@@ -37,10 +37,12 @@ export * from './dtos/requests/TransferRetailUserRequest';
|
|
|
37
37
|
export * from './dtos/requests/GoalListQuery';
|
|
38
38
|
export * from './dtos/requests/GoalUpsertRequest';
|
|
39
39
|
export * from './dtos/requests/GoalPathParams';
|
|
40
|
+
export * from './dtos/requests/PrivateGoalListQuery';
|
|
40
41
|
export * from './dtos/requests/KpiQuery';
|
|
41
42
|
export * from './dtos/requests/PrivateSellerListQuery';
|
|
42
43
|
export * from './dtos/responses/RetailerHierarchyResponse';
|
|
43
44
|
export * from './dtos/responses/GoalListResponse';
|
|
44
45
|
export * from './dtos/responses/GoalUpsertResponse';
|
|
46
|
+
export * from './dtos/responses/PrivateGoalListResponse';
|
|
45
47
|
export * from './dtos/responses/StoreKpiResponse';
|
|
46
48
|
export * from './dtos/responses/SellerKpiResponse';
|
package/bin/retailOrg/index.js
CHANGED
|
@@ -59,11 +59,13 @@ __exportStar(require("./dtos/requests/TransferRetailUserRequest"), exports);
|
|
|
59
59
|
__exportStar(require("./dtos/requests/GoalListQuery"), exports);
|
|
60
60
|
__exportStar(require("./dtos/requests/GoalUpsertRequest"), exports);
|
|
61
61
|
__exportStar(require("./dtos/requests/GoalPathParams"), exports);
|
|
62
|
+
__exportStar(require("./dtos/requests/PrivateGoalListQuery"), exports);
|
|
62
63
|
__exportStar(require("./dtos/requests/KpiQuery"), exports);
|
|
63
64
|
__exportStar(require("./dtos/requests/PrivateSellerListQuery"), exports);
|
|
64
65
|
// Response DTOs
|
|
65
66
|
__exportStar(require("./dtos/responses/RetailerHierarchyResponse"), exports);
|
|
66
67
|
__exportStar(require("./dtos/responses/GoalListResponse"), exports);
|
|
67
68
|
__exportStar(require("./dtos/responses/GoalUpsertResponse"), exports);
|
|
69
|
+
__exportStar(require("./dtos/responses/PrivateGoalListResponse"), exports);
|
|
68
70
|
__exportStar(require("./dtos/responses/StoreKpiResponse"), exports);
|
|
69
71
|
__exportStar(require("./dtos/responses/SellerKpiResponse"), exports);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { RetailUserStatusEnum } from '../../../retailOrg/enums/RetailUserStatusEnum';
|
|
2
|
+
import type { SellerTableSourceStatusEnum } from '../../enums/SellerTableSourceStatusEnum';
|
|
3
|
+
/** Una fila de la tabla de Vendedores: padrón + ventas de la ventana + meta + comisión. */
|
|
4
|
+
export interface SellerTableRow {
|
|
5
|
+
retailUserId: string;
|
|
6
|
+
/** `null` si ni el padrón ni las ventas traen nombre. */
|
|
7
|
+
name: string | null;
|
|
8
|
+
/** `null` solo si el vendedor vendió pero ya no está en el padrón. */
|
|
9
|
+
status: RetailUserStatusEnum | null;
|
|
10
|
+
phone: string | null;
|
|
11
|
+
storeId: string | null;
|
|
12
|
+
storeName: string | null;
|
|
13
|
+
zoneName: string | null;
|
|
14
|
+
/** Es el encargado (`managerRetailUserId`) de su tienda. */
|
|
15
|
+
isStoreAdmin: boolean;
|
|
16
|
+
/** Sin ventas en la ventana viaja `0`: el barrido es exhaustivo. */
|
|
17
|
+
salesCount: number;
|
|
18
|
+
placedCents: number;
|
|
19
|
+
averageTicketCents: number | null;
|
|
20
|
+
lastSaleAt: string | null;
|
|
21
|
+
/** Δ % contra la misma ventana 7 días antes; `null` si la ventana pasa de 7 días o no hubo base. */
|
|
22
|
+
weekOverWeekChangePct: number | null;
|
|
23
|
+
/**
|
|
24
|
+
* Meta mensual (`monthCents` del mes de `to`, hora de CDMX) escalada a los días de la ventana:
|
|
25
|
+
* `round(monthCents * días / 30)`. `null` sin meta, con metas caídas o con ventana > 90 días.
|
|
26
|
+
*/
|
|
27
|
+
goalCents: number | null;
|
|
28
|
+
/** Lo que le pagó el último corte semanal CERRADO (`0` si no le pagó); `null` sin corte o con la fuente caída. */
|
|
29
|
+
commissionCents: number | null;
|
|
30
|
+
/** NPI M30: no lo calcula ningún lambda todavía. Siempre `null`. */
|
|
31
|
+
npiM30Pct: null;
|
|
32
|
+
}
|
|
33
|
+
/** Estado de cada fuente externa. Una fuente `UNAVAILABLE` deja sus campos en `null`, nunca en `0`. */
|
|
34
|
+
export interface SellerTableSources {
|
|
35
|
+
roster: SellerTableSourceStatusEnum;
|
|
36
|
+
goals: SellerTableSourceStatusEnum;
|
|
37
|
+
commission: SellerTableSourceStatusEnum;
|
|
38
|
+
}
|
|
39
|
+
/** Corte semanal del que sale `commissionCents`; días locales `YYYY-MM-DD`, ambos incluidos. */
|
|
40
|
+
export interface SellerTableCommissionPeriod {
|
|
41
|
+
periodId: string;
|
|
42
|
+
from: string;
|
|
43
|
+
to: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* `GET /backoffice/sellers/table?from&to&value` — la tabla completa de Vendedores del Portal Admin
|
|
47
|
+
* VL, sin paginación. Incluye a los vendedores del padrón sin ventas y a los inactivos.
|
|
48
|
+
*/
|
|
49
|
+
export interface BackofficeSellerTableResponse {
|
|
50
|
+
from: string;
|
|
51
|
+
to: string | null;
|
|
52
|
+
/** Las ventas de la ventana pasaron el tope de lectura: los números están recortados. */
|
|
53
|
+
truncated: boolean;
|
|
54
|
+
sources: SellerTableSources;
|
|
55
|
+
commissionPeriod: SellerTableCommissionPeriod | null;
|
|
56
|
+
items: SellerTableRow[];
|
|
57
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SellerTableSourceStatusEnum = void 0;
|
|
4
|
+
/** Si una fuente de la tabla de Vendedores contestó (`OK`) o falló (`UNAVAILABLE`). */
|
|
5
|
+
var SellerTableSourceStatusEnum;
|
|
6
|
+
(function (SellerTableSourceStatusEnum) {
|
|
7
|
+
SellerTableSourceStatusEnum["OK"] = "OK";
|
|
8
|
+
SellerTableSourceStatusEnum["UNAVAILABLE"] = "UNAVAILABLE";
|
|
9
|
+
})(SellerTableSourceStatusEnum || (exports.SellerTableSourceStatusEnum = SellerTableSourceStatusEnum = {}));
|
|
@@ -135,6 +135,8 @@ export * from './dtos/responses/BackofficeCustomersResponse';
|
|
|
135
135
|
export * from './dtos/responses/BackofficeCustomerPurchasesResponse';
|
|
136
136
|
export * from './dtos/responses/BackofficeStoreKpisResponse';
|
|
137
137
|
export * from './dtos/responses/BackofficeSellerKpisResponse';
|
|
138
|
+
export * from './enums/SellerTableSourceStatusEnum';
|
|
139
|
+
export * from './dtos/responses/BackofficeSellerTableResponse';
|
|
138
140
|
export * from './events/SaleCompletedV1';
|
|
139
141
|
export * from './events/SaleCancelledV1';
|
|
140
142
|
export * from './events/SaleCompletedV2';
|
|
@@ -168,6 +168,8 @@ __exportStar(require("./dtos/responses/BackofficeCustomersResponse"), exports);
|
|
|
168
168
|
__exportStar(require("./dtos/responses/BackofficeCustomerPurchasesResponse"), exports);
|
|
169
169
|
__exportStar(require("./dtos/responses/BackofficeStoreKpisResponse"), exports);
|
|
170
170
|
__exportStar(require("./dtos/responses/BackofficeSellerKpisResponse"), exports);
|
|
171
|
+
__exportStar(require("./enums/SellerTableSourceStatusEnum"), exports);
|
|
172
|
+
__exportStar(require("./dtos/responses/BackofficeSellerTableResponse"), exports);
|
|
171
173
|
// Contratos de eventos (PascalCase + sufijo V1)
|
|
172
174
|
__exportStar(require("./events/SaleCompletedV1"), exports);
|
|
173
175
|
__exportStar(require("./events/SaleCancelledV1"), exports);
|
package/package.json
CHANGED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsNotEmpty, IsString } from 'class-validator';
|
|
3
|
+
|
|
4
|
+
/** Query de `GET /private/retailers/{retailerId}/payouts/latest-closed`. */
|
|
5
|
+
export class PrivateLatestClosedPayoutQuery {
|
|
6
|
+
@Expose()
|
|
7
|
+
@IsString()
|
|
8
|
+
@IsNotEmpty()
|
|
9
|
+
retailerId!: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Lo que el corte le paga a un vendedor: liberado más ajustes, en centavos. */
|
|
13
|
+
export interface PrivateClosedPayoutSeller {
|
|
14
|
+
retailUserId: string;
|
|
15
|
+
amountCents: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** El corte semanal; `from` y `to` son días locales `YYYY-MM-DD`, ambos incluidos. */
|
|
19
|
+
export interface PrivateClosedPayoutPeriod {
|
|
20
|
+
periodId: string;
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Respuesta de `GET /private/retailers/{retailerId}/payouts/latest-closed`: el último corte semanal
|
|
27
|
+
* CERRADO de la cadena. Sin corte cerrado reciente, `period: null` y `sellers: []`.
|
|
28
|
+
*/
|
|
29
|
+
export interface PrivateLatestClosedPayoutResponse {
|
|
30
|
+
retailerId: string;
|
|
31
|
+
period: PrivateClosedPayoutPeriod | null;
|
|
32
|
+
sellers: PrivateClosedPayoutSeller[];
|
|
33
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Expose } from 'class-transformer';
|
|
2
|
+
import { IsEnum, IsOptional, Matches } from 'class-validator';
|
|
3
|
+
import { GoalTargetTypeEnum } from '../../enums/GoalTargetTypeEnum';
|
|
4
|
+
|
|
5
|
+
/** ULID canónico: 26 chars Crockford base32, primer char 0-7. */
|
|
6
|
+
const ULID = /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Query de `GET /private/retailers/{retailerId}/goals` — las metas de un periodo, M2M.
|
|
10
|
+
* El `retailerId` llega en el path; la seguridad del privado es de red, no de identidad.
|
|
11
|
+
*/
|
|
12
|
+
export class PrivateGoalListQuery {
|
|
13
|
+
@Expose()
|
|
14
|
+
@Matches(ULID, { message: 'retailerId debe ser un ULID' })
|
|
15
|
+
retailerId!: string;
|
|
16
|
+
|
|
17
|
+
/** Mes calendario `YYYY-MM` (mes 01-12). */
|
|
18
|
+
@Expose()
|
|
19
|
+
@Matches(/^\d{4}-(0[1-9]|1[0-2])$/, { message: 'periodId debe tener formato YYYY-MM (mes 01-12)' })
|
|
20
|
+
periodId!: string;
|
|
21
|
+
|
|
22
|
+
/** Si falta, devuelve los dos tipos. */
|
|
23
|
+
@Expose()
|
|
24
|
+
@IsOptional()
|
|
25
|
+
@IsEnum(GoalTargetTypeEnum)
|
|
26
|
+
targetType?: GoalTargetTypeEnum;
|
|
27
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Expose } from 'class-transformer';
|
|
2
|
-
import { IsEnum, IsOptional, Matches } from 'class-validator';
|
|
1
|
+
import { Expose, Transform } from 'class-transformer';
|
|
2
|
+
import { IsBoolean, IsEnum, IsOptional, Matches } from 'class-validator';
|
|
3
3
|
import { RetailUserStatusEnum } from '../../enums/RetailUserStatusEnum';
|
|
4
4
|
|
|
5
5
|
/** ULID canónico: 26 chars Crockford base32, primer char 0-7 (el timestamp cabe en 48 bits). */
|
|
@@ -40,4 +40,10 @@ export class PrivateSellerListQuery {
|
|
|
40
40
|
@IsOptional()
|
|
41
41
|
@Matches(/^[a-z0-9-]{1,64}$/, { message: 'callerService debe ser el nombre del lambda (kebab-case)' })
|
|
42
42
|
callerService?: string;
|
|
43
|
+
|
|
44
|
+
/** `true` agrega el teléfono de cada vendedor. Por defecto no viaja: es PII. */
|
|
45
|
+
@Expose()
|
|
46
|
+
@Transform(({ value }) => value === true || value === 'true')
|
|
47
|
+
@IsBoolean()
|
|
48
|
+
includePhone?: boolean;
|
|
43
49
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { GoalListResponse } from './GoalListResponse';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Respuesta de `GET /private/retailers/{retailerId}/goals`: las metas del periodo con las tres cifras
|
|
5
|
+
* derivadas. Un periodo sin metas devuelve `goals: []`, no un 404.
|
|
6
|
+
*/
|
|
7
|
+
export interface PrivateGoalListResponse extends GoalListResponse {
|
|
8
|
+
retailerId: string;
|
|
9
|
+
}
|
|
@@ -16,6 +16,8 @@ export interface PrivateSellerDto {
|
|
|
16
16
|
homeStoreId: string | null;
|
|
17
17
|
commissionTier: string;
|
|
18
18
|
status: RetailUserStatusEnum;
|
|
19
|
+
/** Teléfono del vendedor. Solo viaja si se pidió `includePhone=true`; `null` si no lo tiene. */
|
|
20
|
+
phone?: string | null;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
/**
|
package/src/retailOrg/index.ts
CHANGED
|
@@ -47,6 +47,7 @@ export * from './dtos/requests/TransferRetailUserRequest';
|
|
|
47
47
|
export * from './dtos/requests/GoalListQuery';
|
|
48
48
|
export * from './dtos/requests/GoalUpsertRequest';
|
|
49
49
|
export * from './dtos/requests/GoalPathParams';
|
|
50
|
+
export * from './dtos/requests/PrivateGoalListQuery';
|
|
50
51
|
export * from './dtos/requests/KpiQuery';
|
|
51
52
|
export * from './dtos/requests/PrivateSellerListQuery';
|
|
52
53
|
|
|
@@ -54,5 +55,6 @@ export * from './dtos/requests/PrivateSellerListQuery';
|
|
|
54
55
|
export * from './dtos/responses/RetailerHierarchyResponse';
|
|
55
56
|
export * from './dtos/responses/GoalListResponse';
|
|
56
57
|
export * from './dtos/responses/GoalUpsertResponse';
|
|
58
|
+
export * from './dtos/responses/PrivateGoalListResponse';
|
|
57
59
|
export * from './dtos/responses/StoreKpiResponse';
|
|
58
60
|
export * from './dtos/responses/SellerKpiResponse';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import type { RetailUserStatusEnum } from '../../../retailOrg/enums/RetailUserStatusEnum';
|
|
2
|
+
import type { SellerTableSourceStatusEnum } from '../../enums/SellerTableSourceStatusEnum';
|
|
3
|
+
|
|
4
|
+
/** Una fila de la tabla de Vendedores: padrón + ventas de la ventana + meta + comisión. */
|
|
5
|
+
export interface SellerTableRow {
|
|
6
|
+
retailUserId: string;
|
|
7
|
+
/** `null` si ni el padrón ni las ventas traen nombre. */
|
|
8
|
+
name: string | null;
|
|
9
|
+
/** `null` solo si el vendedor vendió pero ya no está en el padrón. */
|
|
10
|
+
status: RetailUserStatusEnum | null;
|
|
11
|
+
phone: string | null;
|
|
12
|
+
storeId: string | null;
|
|
13
|
+
storeName: string | null;
|
|
14
|
+
zoneName: string | null;
|
|
15
|
+
/** Es el encargado (`managerRetailUserId`) de su tienda. */
|
|
16
|
+
isStoreAdmin: boolean;
|
|
17
|
+
/** Sin ventas en la ventana viaja `0`: el barrido es exhaustivo. */
|
|
18
|
+
salesCount: number;
|
|
19
|
+
placedCents: number;
|
|
20
|
+
averageTicketCents: number | null;
|
|
21
|
+
lastSaleAt: string | null;
|
|
22
|
+
/** Δ % contra la misma ventana 7 días antes; `null` si la ventana pasa de 7 días o no hubo base. */
|
|
23
|
+
weekOverWeekChangePct: number | null;
|
|
24
|
+
/**
|
|
25
|
+
* Meta mensual (`monthCents` del mes de `to`, hora de CDMX) escalada a los días de la ventana:
|
|
26
|
+
* `round(monthCents * días / 30)`. `null` sin meta, con metas caídas o con ventana > 90 días.
|
|
27
|
+
*/
|
|
28
|
+
goalCents: number | null;
|
|
29
|
+
/** Lo que le pagó el último corte semanal CERRADO (`0` si no le pagó); `null` sin corte o con la fuente caída. */
|
|
30
|
+
commissionCents: number | null;
|
|
31
|
+
/** NPI M30: no lo calcula ningún lambda todavía. Siempre `null`. */
|
|
32
|
+
npiM30Pct: null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Estado de cada fuente externa. Una fuente `UNAVAILABLE` deja sus campos en `null`, nunca en `0`. */
|
|
36
|
+
export interface SellerTableSources {
|
|
37
|
+
roster: SellerTableSourceStatusEnum;
|
|
38
|
+
goals: SellerTableSourceStatusEnum;
|
|
39
|
+
commission: SellerTableSourceStatusEnum;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Corte semanal del que sale `commissionCents`; días locales `YYYY-MM-DD`, ambos incluidos. */
|
|
43
|
+
export interface SellerTableCommissionPeriod {
|
|
44
|
+
periodId: string;
|
|
45
|
+
from: string;
|
|
46
|
+
to: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `GET /backoffice/sellers/table?from&to&value` — la tabla completa de Vendedores del Portal Admin
|
|
51
|
+
* VL, sin paginación. Incluye a los vendedores del padrón sin ventas y a los inactivos.
|
|
52
|
+
*/
|
|
53
|
+
export interface BackofficeSellerTableResponse {
|
|
54
|
+
from: string;
|
|
55
|
+
to: string | null;
|
|
56
|
+
/** Las ventas de la ventana pasaron el tope de lectura: los números están recortados. */
|
|
57
|
+
truncated: boolean;
|
|
58
|
+
sources: SellerTableSources;
|
|
59
|
+
commissionPeriod: SellerTableCommissionPeriod | null;
|
|
60
|
+
items: SellerTableRow[];
|
|
61
|
+
}
|
|
@@ -160,6 +160,8 @@ export * from './dtos/responses/BackofficeCustomersResponse';
|
|
|
160
160
|
export * from './dtos/responses/BackofficeCustomerPurchasesResponse';
|
|
161
161
|
export * from './dtos/responses/BackofficeStoreKpisResponse';
|
|
162
162
|
export * from './dtos/responses/BackofficeSellerKpisResponse';
|
|
163
|
+
export * from './enums/SellerTableSourceStatusEnum';
|
|
164
|
+
export * from './dtos/responses/BackofficeSellerTableResponse';
|
|
163
165
|
|
|
164
166
|
// Contratos de eventos (PascalCase + sufijo V1)
|
|
165
167
|
export * from './events/SaleCompletedV1';
|