@fiado/type-kit 3.507.0 → 3.509.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/platformRbac/dtos/roleAssignmentsByScopeRefsDtos.test.ts +49 -0
- package/_test_/unit/retailOrg/dtos/sellerTableSources.test.ts +17 -0
- package/_test_/unit/retailWizard/sellerTableShapes.test.ts +9 -2
- package/_test_/unit/retailWizard/storeTableShapes.test.ts +47 -0
- package/bin/platformRbac/dtos/RoleAssignmentsByScopeRefsRequest.d.ts +4 -0
- package/bin/platformRbac/dtos/RoleAssignmentsByScopeRefsRequest.js +25 -0
- package/bin/platformRbac/dtos/RoleAssignmentsByScopeRefsResponse.d.ts +16 -0
- package/bin/platformRbac/dtos/RoleAssignmentsByScopeRefsResponse.js +2 -0
- package/bin/platformRbac/enums/ScopeRefLookupStatusEnum.d.ts +5 -0
- package/bin/platformRbac/enums/ScopeRefLookupStatusEnum.js +9 -0
- package/bin/platformRbac/index.d.ts +3 -0
- package/bin/platformRbac/index.js +3 -0
- package/bin/retailOrg/dtos/validation/PrivateSellerListResponse.d.ts +5 -1
- package/bin/retailWizard/dtos/responses/BackofficeSellerTableResponse.d.ts +21 -2
- package/bin/retailWizard/dtos/responses/BackofficeStoreDetailResponse.d.ts +27 -0
- package/bin/retailWizard/dtos/responses/BackofficeStoreDetailResponse.js +2 -0
- package/bin/retailWizard/dtos/responses/BackofficeStoreTableResponse.d.ts +55 -0
- package/bin/retailWizard/dtos/responses/BackofficeStoreTableResponse.js +2 -0
- package/bin/retailWizard/enums/SellerTableSourceStatusEnum.d.ts +3 -2
- package/bin/retailWizard/enums/SellerTableSourceStatusEnum.js +2 -1
- package/bin/retailWizard/enums/StoreKindEnum.d.ts +5 -0
- package/bin/retailWizard/enums/StoreKindEnum.js +9 -0
- package/bin/retailWizard/index.d.ts +3 -0
- package/bin/retailWizard/index.js +3 -0
- package/package.json +1 -1
- package/src/platformRbac/dtos/RoleAssignmentsByScopeRefsRequest.ts +12 -0
- package/src/platformRbac/dtos/RoleAssignmentsByScopeRefsResponse.ts +22 -0
- package/src/platformRbac/enums/ScopeRefLookupStatusEnum.ts +5 -0
- package/src/platformRbac/index.ts +9 -0
- package/src/retailOrg/dtos/validation/PrivateSellerListResponse.ts +5 -1
- package/src/retailWizard/dtos/responses/BackofficeSellerTableResponse.ts +22 -2
- package/src/retailWizard/dtos/responses/BackofficeStoreDetailResponse.ts +30 -0
- package/src/retailWizard/dtos/responses/BackofficeStoreTableResponse.ts +58 -0
- package/src/retailWizard/enums/SellerTableSourceStatusEnum.ts +2 -1
- package/src/retailWizard/enums/StoreKindEnum.ts +5 -0
- package/src/retailWizard/index.ts +3 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { plainToInstance } from 'class-transformer';
|
|
3
|
+
import { validate } from 'class-validator';
|
|
4
|
+
import {
|
|
5
|
+
PermissionScope,
|
|
6
|
+
RoleAssignmentsByScopeRefsRequest,
|
|
7
|
+
ROLE_ASSIGNMENTS_BY_SCOPE_REFS_MAX_BATCH,
|
|
8
|
+
ScopeRefLookupStatusEnum,
|
|
9
|
+
} from '../../../../src/platformRbac';
|
|
10
|
+
import type { RoleAssignmentsByScopeRefsResponse } from '../../../../src/platformRbac';
|
|
11
|
+
|
|
12
|
+
describe('RoleAssignmentsByScopeRefsRequest', () => {
|
|
13
|
+
it('el tope del lote es 100', () => {
|
|
14
|
+
expect(ROLE_ASSIGNMENTS_BY_SCOPE_REFS_MAX_BATCH).toBe(100);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('acepta una lista de scopeRefs y la vacía', async () => {
|
|
18
|
+
expect(await validate(plainToInstance(RoleAssignmentsByScopeRefsRequest, { scopeRefs: ['st-1'] }))).toEqual([]);
|
|
19
|
+
expect(await validate(plainToInstance(RoleAssignmentsByScopeRefsRequest, { scopeRefs: [] }))).toEqual([]);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('rechaza 101 scopeRefs con arrayMaxSize', async () => {
|
|
23
|
+
const scopeRefs = Array.from({ length: 101 }, (_, i) => `st-${i}`);
|
|
24
|
+
const errors = await validate(plainToInstance(RoleAssignmentsByScopeRefsRequest, { scopeRefs }));
|
|
25
|
+
expect(errors[0].constraints?.arrayMaxSize).toBeDefined();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('rechaza elementos que no son string', async () => {
|
|
29
|
+
const errors = await validate(plainToInstance(RoleAssignmentsByScopeRefsRequest, { scopeRefs: [7] }));
|
|
30
|
+
expect(errors[0].constraints?.isString).toBeDefined();
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
describe('RoleAssignmentsByScopeRefsResponse', () => {
|
|
35
|
+
it('lleva un item por scopeRef con su estado y asignaciones', () => {
|
|
36
|
+
const response: RoleAssignmentsByScopeRefsResponse = {
|
|
37
|
+
items: [
|
|
38
|
+
{
|
|
39
|
+
scopeRef: 'st-1',
|
|
40
|
+
status: ScopeRefLookupStatusEnum.OK,
|
|
41
|
+
assignments: [{ cognitoSub: 'sub-1', roleId: 'store_manager', roleName: 'Encargado', scope: PermissionScope.LEVEL_3 }],
|
|
42
|
+
},
|
|
43
|
+
{ scopeRef: 'st-2', status: ScopeRefLookupStatusEnum.UNAVAILABLE, assignments: [] },
|
|
44
|
+
],
|
|
45
|
+
};
|
|
46
|
+
expect(Object.values(ScopeRefLookupStatusEnum)).toEqual(['OK', 'UNAVAILABLE']);
|
|
47
|
+
expect(response.items).toHaveLength(2);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
@@ -60,3 +60,20 @@ describe('shapes de los privados del padrón', () => {
|
|
|
60
60
|
expect([store.managerRetailUserId, seller.phone, goals.goals.length]).toEqual(['u-1', null, 1]);
|
|
61
61
|
});
|
|
62
62
|
});
|
|
63
|
+
|
|
64
|
+
describe('PrivateSellerDto.cognitoSub y createdAt', () => {
|
|
65
|
+
it('lleva la cuenta de RBAC y la fecha de alta, ambas nulables', () => {
|
|
66
|
+
const seller: PrivateSellerDto = {
|
|
67
|
+
sellerId: 'u-1',
|
|
68
|
+
displayName: 'Ana',
|
|
69
|
+
homeStoreId: null,
|
|
70
|
+
commissionTier: 'BASE',
|
|
71
|
+
status: 'ACTIVE' as never,
|
|
72
|
+
cognitoSub: 'sub-1',
|
|
73
|
+
createdAt: '2026-01-02T03:04:05.000Z',
|
|
74
|
+
};
|
|
75
|
+
const orphan: PrivateSellerDto = { ...seller, cognitoSub: null, createdAt: null };
|
|
76
|
+
expect(seller.cognitoSub).toBe('sub-1');
|
|
77
|
+
expect(orphan.createdAt).toBeNull();
|
|
78
|
+
});
|
|
79
|
+
});
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from '../../../src/retailWizard';
|
|
6
6
|
|
|
7
7
|
describe('BackofficeSellerTableResponse', () => {
|
|
8
|
-
it('declara las
|
|
8
|
+
it('declara las cinco fuentes y una fila completa', () => {
|
|
9
9
|
const response: BackofficeSellerTableResponse = {
|
|
10
10
|
from: '2026-09-07T06:00:00.000Z',
|
|
11
11
|
to: '2026-10-07T05:59:59.999Z',
|
|
@@ -14,6 +14,8 @@ describe('BackofficeSellerTableResponse', () => {
|
|
|
14
14
|
roster: SellerTableSourceStatusEnum.OK,
|
|
15
15
|
goals: SellerTableSourceStatusEnum.UNAVAILABLE,
|
|
16
16
|
commission: SellerTableSourceStatusEnum.OK,
|
|
17
|
+
rbac: SellerTableSourceStatusEnum.UNAVAILABLE,
|
|
18
|
+
lake: SellerTableSourceStatusEnum.DISABLED,
|
|
17
19
|
},
|
|
18
20
|
commissionPeriod: { periodId: '2026-09-28', from: '2026-09-28', to: '2026-10-04' },
|
|
19
21
|
items: [
|
|
@@ -34,10 +36,15 @@ describe('BackofficeSellerTableResponse', () => {
|
|
|
34
36
|
goalCents: null,
|
|
35
37
|
commissionCents: null,
|
|
36
38
|
npiM30Pct: null,
|
|
39
|
+
roles: [{ key: 'store_manager', name: 'Encargado de tienda' }],
|
|
40
|
+
email: null,
|
|
41
|
+
customersServed: 0,
|
|
42
|
+
memberSince: '2026-01-02T03:04:05.000Z',
|
|
43
|
+
weeklyPlacedCents: null,
|
|
37
44
|
},
|
|
38
45
|
],
|
|
39
46
|
};
|
|
40
|
-
expect(Object.values(SellerTableSourceStatusEnum)).toEqual(['OK', 'UNAVAILABLE']);
|
|
47
|
+
expect(Object.values(SellerTableSourceStatusEnum)).toEqual(['OK', 'UNAVAILABLE', 'DISABLED']);
|
|
41
48
|
expect(response.items[0].npiM30Pct).toBeNull();
|
|
42
49
|
});
|
|
43
50
|
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { ProductCategoryEnum } from '../../../src/retailCatalog/enums/ProductCategoryEnum';
|
|
3
|
+
import { StoreStatusEnum } from '../../../src/retailOrg/enums/StoreStatusEnum';
|
|
4
|
+
import {
|
|
5
|
+
SellerTableSourceStatusEnum,
|
|
6
|
+
StoreKindEnum,
|
|
7
|
+
type BackofficeStoreDetailResponse,
|
|
8
|
+
type BackofficeStoreTableResponse,
|
|
9
|
+
} from '../../../src/retailWizard';
|
|
10
|
+
|
|
11
|
+
describe('BackofficeStoreTableResponse', () => {
|
|
12
|
+
it('declara las fuentes y una fila completa', () => {
|
|
13
|
+
const response: BackofficeStoreTableResponse = {
|
|
14
|
+
from: '2026-09-30T06:00:00.000Z',
|
|
15
|
+
to: '2026-10-07T05:59:59.999Z',
|
|
16
|
+
truncated: false,
|
|
17
|
+
sources: { roster: SellerTableSourceStatusEnum.OK, team: SellerTableSourceStatusEnum.OK, goals: SellerTableSourceStatusEnum.UNAVAILABLE },
|
|
18
|
+
items: [
|
|
19
|
+
{
|
|
20
|
+
storeId: 'ST-1', code: 'CEN', name: 'Centro', zoneId: 'Z-1', zoneName: 'Norte',
|
|
21
|
+
status: StoreStatusEnum.ACTIVE, kind: null,
|
|
22
|
+
managerRetailUserId: 'V-1', managerName: 'Karla',
|
|
23
|
+
teamActiveCount: 3, teamTotalCount: 4,
|
|
24
|
+
salesCount: 2, placedCents: 200_000, averageTicketCents: 100_000, customersServed: 2,
|
|
25
|
+
lastSaleAt: '2026-10-05T18:00:00.000Z', weekOverWeekChangePct: 12.5,
|
|
26
|
+
goalCents: null, networkSharePct: 40, npiM30Pct: null,
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
};
|
|
30
|
+
expect(response.items[0].status).toBe('ACTIVE');
|
|
31
|
+
expect(StoreKindEnum.SUBDISTRIBUTOR).toBe('SUBDISTRIBUTOR');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe('BackofficeStoreDetailResponse', () => {
|
|
36
|
+
it('declara la serie semanal y el mix por categoría', () => {
|
|
37
|
+
const response: BackofficeStoreDetailResponse = {
|
|
38
|
+
storeId: 'ST-1',
|
|
39
|
+
from: '2026-09-30T06:00:00.000Z',
|
|
40
|
+
to: '2026-10-07T05:59:59.999Z',
|
|
41
|
+
truncated: false,
|
|
42
|
+
weeklyPlacement: [{ from: '2026-09-30T06:00:00.000Z', to: '2026-10-07T05:59:59.999Z', salesCount: 1, placedCents: 100_000 }],
|
|
43
|
+
categoryMix: [{ category: ProductCategoryEnum.PHONE, units: 1, placedCents: 100_000 }, { category: null, units: 1, placedCents: 5_000 }],
|
|
44
|
+
};
|
|
45
|
+
expect(response.categoryMix[1].category).toBeNull();
|
|
46
|
+
});
|
|
47
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
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.RoleAssignmentsByScopeRefsRequest = exports.ROLE_ASSIGNMENTS_BY_SCOPE_REFS_MAX_BATCH = void 0;
|
|
13
|
+
const class_validator_1 = require("class-validator");
|
|
14
|
+
// Tope de scopeRefs por request del endpoint batch de asignaciones por destino.
|
|
15
|
+
exports.ROLE_ASSIGNMENTS_BY_SCOPE_REFS_MAX_BATCH = 100;
|
|
16
|
+
// Body de POST /internal/tenants/{tenantId}/role-assignments/by-scope-refs; la lista vacía responde sin items.
|
|
17
|
+
class RoleAssignmentsByScopeRefsRequest {
|
|
18
|
+
}
|
|
19
|
+
exports.RoleAssignmentsByScopeRefsRequest = RoleAssignmentsByScopeRefsRequest;
|
|
20
|
+
__decorate([
|
|
21
|
+
(0, class_validator_1.IsArray)(),
|
|
22
|
+
(0, class_validator_1.ArrayMaxSize)(exports.ROLE_ASSIGNMENTS_BY_SCOPE_REFS_MAX_BATCH),
|
|
23
|
+
(0, class_validator_1.IsString)({ each: true }),
|
|
24
|
+
__metadata("design:type", Array)
|
|
25
|
+
], RoleAssignmentsByScopeRefsRequest.prototype, "scopeRefs", void 0);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { PermissionScope } from '../enums/PermissionScope';
|
|
2
|
+
import type { ScopeRefLookupStatusEnum } from '../enums/ScopeRefLookupStatusEnum';
|
|
3
|
+
export interface ScopeRefRoleAssignment {
|
|
4
|
+
cognitoSub: string;
|
|
5
|
+
roleId: string;
|
|
6
|
+
roleName: string | null;
|
|
7
|
+
scope: PermissionScope;
|
|
8
|
+
}
|
|
9
|
+
export interface ScopeRefRoleAssignments {
|
|
10
|
+
scopeRef: string;
|
|
11
|
+
status: ScopeRefLookupStatusEnum;
|
|
12
|
+
assignments: ScopeRefRoleAssignment[];
|
|
13
|
+
}
|
|
14
|
+
export interface RoleAssignmentsByScopeRefsResponse {
|
|
15
|
+
items: ScopeRefRoleAssignments[];
|
|
16
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ScopeRefLookupStatusEnum = void 0;
|
|
4
|
+
/** Si la lectura de asignaciones de un destino contestó (`OK`) o falló (`UNAVAILABLE`). */
|
|
5
|
+
var ScopeRefLookupStatusEnum;
|
|
6
|
+
(function (ScopeRefLookupStatusEnum) {
|
|
7
|
+
ScopeRefLookupStatusEnum["OK"] = "OK";
|
|
8
|
+
ScopeRefLookupStatusEnum["UNAVAILABLE"] = "UNAVAILABLE";
|
|
9
|
+
})(ScopeRefLookupStatusEnum || (exports.ScopeRefLookupStatusEnum = ScopeRefLookupStatusEnum = {}));
|
|
@@ -87,6 +87,9 @@ export * from './dtos/RevokeTenantRoleRequest';
|
|
|
87
87
|
export type { RevokeTenantRoleResponse } from './dtos/RevokeTenantRoleResponse';
|
|
88
88
|
export * from './dtos/TenantUsersBySubsRequest';
|
|
89
89
|
export type { TenantUserBySubItem, TenantUsersBySubsResponse } from './dtos/TenantUsersBySubsResponse';
|
|
90
|
+
export * from './dtos/RoleAssignmentsByScopeRefsRequest';
|
|
91
|
+
export * from './enums/ScopeRefLookupStatusEnum';
|
|
92
|
+
export type { ScopeRefRoleAssignment, ScopeRefRoleAssignments, RoleAssignmentsByScopeRefsResponse, } from './dtos/RoleAssignmentsByScopeRefsResponse';
|
|
90
93
|
export * from './apiUser/ApiLoginRequest';
|
|
91
94
|
export * from './apiUser/ApiLoginResponse';
|
|
92
95
|
export * from './apiUser/CreateApiUserRequest';
|
|
@@ -129,6 +129,9 @@ __exportStar(require("./dtos/AssignTenantRoleRequest"), exports);
|
|
|
129
129
|
__exportStar(require("./dtos/RevokeTenantRoleRequest"), exports);
|
|
130
130
|
// Batch privado de usuarios del tenant por cognitoSub (hub de miembros de group-business).
|
|
131
131
|
__exportStar(require("./dtos/TenantUsersBySubsRequest"), exports);
|
|
132
|
+
// Batch privado de asignaciones de rol por destino (scopeRef), para la tabla de Vendedores.
|
|
133
|
+
__exportStar(require("./dtos/RoleAssignmentsByScopeRefsRequest"), exports);
|
|
134
|
+
__exportStar(require("./enums/ScopeRefLookupStatusEnum"), exports);
|
|
132
135
|
// Usuarios de API: login por Bearer, alta, rotación de secreto y diagnóstico del W5.
|
|
133
136
|
__exportStar(require("./apiUser/ApiLoginRequest"), exports);
|
|
134
137
|
__exportStar(require("./apiUser/ApiLoginResponse"), exports);
|
|
@@ -3,7 +3,7 @@ import type { RetailUserStatusEnum } from '../../enums/RetailUserStatusEnum';
|
|
|
3
3
|
* Shape mínimo de un vendedor para el motor de comisiones (F3b): a quién pagarle, de qué tienda es y
|
|
4
4
|
* en qué tier va.
|
|
5
5
|
*
|
|
6
|
-
* **Sin PII** —
|
|
6
|
+
* **Sin PII** — el teléfono solo viaja a pedido. `displayName` es el rótulo de conveniencia con el
|
|
7
7
|
* que el motor arma su reporte de devengo; no es identidad (la identidad vive en RBAC).
|
|
8
8
|
*
|
|
9
9
|
* `commissionTier` no es adorno: es lo que el motor usa para resolver CUÁNTO le toca a cada vendedor
|
|
@@ -17,6 +17,10 @@ export interface PrivateSellerDto {
|
|
|
17
17
|
status: RetailUserStatusEnum;
|
|
18
18
|
/** Teléfono del vendedor. Solo viaja si se pidió `includePhone=true`; `null` si no lo tiene. */
|
|
19
19
|
phone?: string | null;
|
|
20
|
+
/** Cuenta del vendedor en RBAC; `null` si todavía no tiene usuario. */
|
|
21
|
+
cognitoSub?: string | null;
|
|
22
|
+
/** Alta del vendedor en el padrón (ISO); `null` si la fila no la trae. */
|
|
23
|
+
createdAt?: string | null;
|
|
20
24
|
}
|
|
21
25
|
/**
|
|
22
26
|
* Respuesta de `GET /private/sellers?retailerId=…` — el padrón de una cadena, para máquinas.
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import type { RetailUserStatusEnum } from '../../../retailOrg/enums/RetailUserStatusEnum';
|
|
2
2
|
import type { SellerTableSourceStatusEnum } from '../../enums/SellerTableSourceStatusEnum';
|
|
3
|
+
/** Rol del vendedor en RBAC: `key` es el `roleId` y `name` su nombre legible. */
|
|
4
|
+
export interface SellerTableRole {
|
|
5
|
+
key: string;
|
|
6
|
+
name: string;
|
|
7
|
+
}
|
|
3
8
|
/** Una fila de la tabla de Vendedores: padrón + ventas de la ventana + meta + comisión. */
|
|
4
9
|
export interface SellerTableRow {
|
|
5
10
|
retailUserId: string;
|
|
@@ -11,15 +16,25 @@ export interface SellerTableRow {
|
|
|
11
16
|
storeId: string | null;
|
|
12
17
|
storeName: string | null;
|
|
13
18
|
zoneName: string | null;
|
|
14
|
-
/**
|
|
19
|
+
/** Tiene el rol `store_manager`; si RBAC cae, es el encargado (`managerRetailUserId`) de su tienda. */
|
|
15
20
|
isStoreAdmin: boolean;
|
|
21
|
+
/** Roles de RBAC en la cadena, sus zonas y tiendas; `null` si RBAC no contestó, `[]` sin cuenta o sin roles. */
|
|
22
|
+
roles: SellerTableRole[] | null;
|
|
23
|
+
/** Correo de su cuenta de RBAC; `null` sin cuenta, sin correo o con RBAC caído. */
|
|
24
|
+
email: string | null;
|
|
16
25
|
/** Sin ventas en la ventana viaja `0`: el barrido es exhaustivo. */
|
|
17
26
|
salesCount: number;
|
|
18
27
|
placedCents: number;
|
|
19
28
|
averageTicketCents: number | null;
|
|
20
29
|
lastSaleAt: string | null;
|
|
21
|
-
/**
|
|
30
|
+
/** Clientes distintos de la ventana, sin canceladas; `null` si los totales vinieron del lake. */
|
|
31
|
+
customersServed: number | null;
|
|
32
|
+
/** Alta del vendedor en el padrón (ISO); `null` si no está en el padrón. */
|
|
33
|
+
memberSince: string | null;
|
|
34
|
+
/** Δ % de los últimos 7 días (al cierre de la ventana) contra los 7 anteriores; `null` si la semana base vendió 0. */
|
|
22
35
|
weekOverWeekChangePct: number | null;
|
|
36
|
+
/** Colocación de las últimas 8 semanas, de la más vieja a la actual; `null` sin lake. */
|
|
37
|
+
weeklyPlacedCents: number[] | null;
|
|
23
38
|
/**
|
|
24
39
|
* Meta mensual (`monthCents` del mes de `to`, hora de CDMX) escalada a los días de la ventana:
|
|
25
40
|
* `round(monthCents * días / 30)`. `null` sin meta, con metas caídas o con ventana > 90 días.
|
|
@@ -35,6 +50,10 @@ export interface SellerTableSources {
|
|
|
35
50
|
roster: SellerTableSourceStatusEnum;
|
|
36
51
|
goals: SellerTableSourceStatusEnum;
|
|
37
52
|
commission: SellerTableSourceStatusEnum;
|
|
53
|
+
/** Roles y correo. */
|
|
54
|
+
rbac: SellerTableSourceStatusEnum;
|
|
55
|
+
/** «Todo» y la tendencia de 8 semanas; `DISABLED` con el flag del lake apagado. */
|
|
56
|
+
lake: SellerTableSourceStatusEnum;
|
|
38
57
|
}
|
|
39
58
|
/** Corte semanal del que sale `commissionCents`; días locales `YYYY-MM-DD`, ambos incluidos. */
|
|
40
59
|
export interface SellerTableCommissionPeriod {
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ProductCategoryEnum } from '../../../retailCatalog/enums/ProductCategoryEnum';
|
|
2
|
+
/** Colocación de una semana de 7 días; ISO, ambos extremos incluidos. */
|
|
3
|
+
export interface StoreWeeklyPlacement {
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
salesCount: number;
|
|
7
|
+
placedCents: number;
|
|
8
|
+
}
|
|
9
|
+
/** Lo vendido de una categoría en la ventana. `category: null` = venta sin líneas de producto. */
|
|
10
|
+
export interface StoreCategoryMixEntry {
|
|
11
|
+
category: ProductCategoryEnum | null;
|
|
12
|
+
units: number;
|
|
13
|
+
placedCents: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* `GET /backoffice/stores/{storeId}/detail?from&to` — el cajón de una tienda: colocación de las 8
|
|
17
|
+
* semanas que terminan en `to` (de la más vieja a la más nueva) y mix por categoría de `[from, to]`.
|
|
18
|
+
*/
|
|
19
|
+
export interface BackofficeStoreDetailResponse {
|
|
20
|
+
storeId: string;
|
|
21
|
+
from: string;
|
|
22
|
+
to: string;
|
|
23
|
+
truncated: boolean;
|
|
24
|
+
weeklyPlacement: StoreWeeklyPlacement[];
|
|
25
|
+
/** De mayor a menor colocación. */
|
|
26
|
+
categoryMix: StoreCategoryMixEntry[];
|
|
27
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { StoreStatusEnum } from '../../../retailOrg/enums/StoreStatusEnum';
|
|
2
|
+
import type { SellerTableSourceStatusEnum } from '../../enums/SellerTableSourceStatusEnum';
|
|
3
|
+
import type { StoreKindEnum } from '../../enums/StoreKindEnum';
|
|
4
|
+
/** Una fila de la tabla de Tiendas: padrón + equipo + ventas de la ventana + meta. */
|
|
5
|
+
export interface StoreTableRow {
|
|
6
|
+
storeId: string;
|
|
7
|
+
/** `null` si la tienda vendió pero ya no está en el padrón. */
|
|
8
|
+
code: string | null;
|
|
9
|
+
name: string | null;
|
|
10
|
+
zoneId: string | null;
|
|
11
|
+
zoneName: string | null;
|
|
12
|
+
status: StoreStatusEnum | null;
|
|
13
|
+
/** Propia o subdistribuidor; `null` mientras ninguna fuente lo sepa. */
|
|
14
|
+
kind: StoreKindEnum | null;
|
|
15
|
+
managerRetailUserId: string | null;
|
|
16
|
+
/** `null` sin encargado o con el equipo sin leer. */
|
|
17
|
+
managerName: string | null;
|
|
18
|
+
/** Vendedores activos con esa tienda de casa; `null` con el equipo sin leer. */
|
|
19
|
+
teamActiveCount: number | null;
|
|
20
|
+
teamTotalCount: number | null;
|
|
21
|
+
/** Sin ventas en la ventana viaja `0`: el barrido es exhaustivo. */
|
|
22
|
+
salesCount: number;
|
|
23
|
+
placedCents: number;
|
|
24
|
+
averageTicketCents: number | null;
|
|
25
|
+
/** Clientes distintos que compraron en la ventana. */
|
|
26
|
+
customersServed: number | null;
|
|
27
|
+
lastSaleAt: string | null;
|
|
28
|
+
/** Δ % contra la misma ventana 7 días antes; `null` si la ventana pasa de 7 días o no hubo base. */
|
|
29
|
+
weekOverWeekChangePct: number | null;
|
|
30
|
+
/** Meta mensual de la tienda escalada a los días de la ventana; `null` sin meta, con metas caídas o ventana > 90 días. */
|
|
31
|
+
goalCents: number | null;
|
|
32
|
+
/** % de la colocación de la cadena en la ventana, a un decimal; `null` si la cadena no colocó. */
|
|
33
|
+
networkSharePct: number | null;
|
|
34
|
+
/** NPI M30: no lo calcula ningún lambda todavía. Siempre `null`. */
|
|
35
|
+
npiM30Pct: null;
|
|
36
|
+
}
|
|
37
|
+
/** Estado de cada fuente. Una fuente `UNAVAILABLE` deja sus campos en `null`, nunca en `0`. */
|
|
38
|
+
export interface StoreTableSources {
|
|
39
|
+
roster: SellerTableSourceStatusEnum;
|
|
40
|
+
/** Vendedores de la cadena: equipo y nombre del encargado. */
|
|
41
|
+
team: SellerTableSourceStatusEnum;
|
|
42
|
+
goals: SellerTableSourceStatusEnum;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* `GET /backoffice/stores/table?from&to&value` — la tabla completa de Tiendas del Portal Admin VL,
|
|
46
|
+
* sin paginación. Incluye las tiendas del padrón sin ventas y las inactivas.
|
|
47
|
+
*/
|
|
48
|
+
export interface BackofficeStoreTableResponse {
|
|
49
|
+
from: string;
|
|
50
|
+
to: string;
|
|
51
|
+
/** Las ventas de la ventana pasaron el tope de lectura: los números están recortados. */
|
|
52
|
+
truncated: boolean;
|
|
53
|
+
sources: StoreTableSources;
|
|
54
|
+
items: StoreTableRow[];
|
|
55
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
/** Si una fuente de la tabla
|
|
1
|
+
/** Si una fuente de la tabla contestó (`OK`), falló (`UNAVAILABLE`) o está apagada por flag (`DISABLED`). */
|
|
2
2
|
export declare enum SellerTableSourceStatusEnum {
|
|
3
3
|
OK = "OK",
|
|
4
|
-
UNAVAILABLE = "UNAVAILABLE"
|
|
4
|
+
UNAVAILABLE = "UNAVAILABLE",
|
|
5
|
+
DISABLED = "DISABLED"
|
|
5
6
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SellerTableSourceStatusEnum = void 0;
|
|
4
|
-
/** Si una fuente de la tabla
|
|
4
|
+
/** Si una fuente de la tabla contestó (`OK`), falló (`UNAVAILABLE`) o está apagada por flag (`DISABLED`). */
|
|
5
5
|
var SellerTableSourceStatusEnum;
|
|
6
6
|
(function (SellerTableSourceStatusEnum) {
|
|
7
7
|
SellerTableSourceStatusEnum["OK"] = "OK";
|
|
8
8
|
SellerTableSourceStatusEnum["UNAVAILABLE"] = "UNAVAILABLE";
|
|
9
|
+
SellerTableSourceStatusEnum["DISABLED"] = "DISABLED";
|
|
9
10
|
})(SellerTableSourceStatusEnum || (exports.SellerTableSourceStatusEnum = SellerTableSourceStatusEnum = {}));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StoreKindEnum = void 0;
|
|
4
|
+
/** Si la tienda es propia de la cadena o de un subdistribuidor. */
|
|
5
|
+
var StoreKindEnum;
|
|
6
|
+
(function (StoreKindEnum) {
|
|
7
|
+
StoreKindEnum["OWN"] = "OWN";
|
|
8
|
+
StoreKindEnum["SUBDISTRIBUTOR"] = "SUBDISTRIBUTOR";
|
|
9
|
+
})(StoreKindEnum || (exports.StoreKindEnum = StoreKindEnum = {}));
|
|
@@ -138,6 +138,9 @@ export * from './dtos/responses/BackofficeSellerKpisResponse';
|
|
|
138
138
|
export * from './enums/SellerTableSourceStatusEnum';
|
|
139
139
|
export * from './dtos/responses/BackofficeSellerTableResponse';
|
|
140
140
|
export * from './dtos/responses/BackofficeCustomerTableResponse';
|
|
141
|
+
export * from './enums/StoreKindEnum';
|
|
142
|
+
export * from './dtos/responses/BackofficeStoreTableResponse';
|
|
143
|
+
export * from './dtos/responses/BackofficeStoreDetailResponse';
|
|
141
144
|
export * from './events/SaleCompletedV1';
|
|
142
145
|
export * from './events/SaleCancelledV1';
|
|
143
146
|
export * from './events/SaleCompletedV2';
|
|
@@ -171,6 +171,9 @@ __exportStar(require("./dtos/responses/BackofficeSellerKpisResponse"), exports);
|
|
|
171
171
|
__exportStar(require("./enums/SellerTableSourceStatusEnum"), exports);
|
|
172
172
|
__exportStar(require("./dtos/responses/BackofficeSellerTableResponse"), exports);
|
|
173
173
|
__exportStar(require("./dtos/responses/BackofficeCustomerTableResponse"), exports);
|
|
174
|
+
__exportStar(require("./enums/StoreKindEnum"), exports);
|
|
175
|
+
__exportStar(require("./dtos/responses/BackofficeStoreTableResponse"), exports);
|
|
176
|
+
__exportStar(require("./dtos/responses/BackofficeStoreDetailResponse"), exports);
|
|
174
177
|
// Contratos de eventos (PascalCase + sufijo V1)
|
|
175
178
|
__exportStar(require("./events/SaleCompletedV1"), exports);
|
|
176
179
|
__exportStar(require("./events/SaleCancelledV1"), exports);
|
package/package.json
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ArrayMaxSize, IsArray, IsString } from "class-validator";
|
|
2
|
+
|
|
3
|
+
// Tope de scopeRefs por request del endpoint batch de asignaciones por destino.
|
|
4
|
+
export const ROLE_ASSIGNMENTS_BY_SCOPE_REFS_MAX_BATCH = 100;
|
|
5
|
+
|
|
6
|
+
// Body de POST /internal/tenants/{tenantId}/role-assignments/by-scope-refs; la lista vacía responde sin items.
|
|
7
|
+
export class RoleAssignmentsByScopeRefsRequest {
|
|
8
|
+
@IsArray()
|
|
9
|
+
@ArrayMaxSize(ROLE_ASSIGNMENTS_BY_SCOPE_REFS_MAX_BATCH)
|
|
10
|
+
@IsString({ each: true })
|
|
11
|
+
scopeRefs!: string[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PermissionScope } from '../enums/PermissionScope';
|
|
2
|
+
import type { ScopeRefLookupStatusEnum } from '../enums/ScopeRefLookupStatusEnum';
|
|
3
|
+
|
|
4
|
+
// Asignación vigente de un usuario en el destino; `roleId` es la clave del rol y `roleName` su displayName.
|
|
5
|
+
export interface ScopeRefRoleAssignment {
|
|
6
|
+
cognitoSub: string;
|
|
7
|
+
roleId: string;
|
|
8
|
+
roleName: string | null;
|
|
9
|
+
scope: PermissionScope;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Asignaciones de un destino; con `UNAVAILABLE` la lista viene vacía y no significa «sin roles».
|
|
13
|
+
export interface ScopeRefRoleAssignments {
|
|
14
|
+
scopeRef: string;
|
|
15
|
+
status: ScopeRefLookupStatusEnum;
|
|
16
|
+
assignments: ScopeRefRoleAssignment[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Respuesta de POST /internal/tenants/{tenantId}/role-assignments/by-scope-refs; un item por scopeRef pedido.
|
|
20
|
+
export interface RoleAssignmentsByScopeRefsResponse {
|
|
21
|
+
items: ScopeRefRoleAssignments[];
|
|
22
|
+
}
|
|
@@ -184,6 +184,15 @@ export type { RevokeTenantRoleResponse } from './dtos/RevokeTenantRoleResponse';
|
|
|
184
184
|
export * from './dtos/TenantUsersBySubsRequest';
|
|
185
185
|
export type { TenantUserBySubItem, TenantUsersBySubsResponse } from './dtos/TenantUsersBySubsResponse';
|
|
186
186
|
|
|
187
|
+
// Batch privado de asignaciones de rol por destino (scopeRef), para la tabla de Vendedores.
|
|
188
|
+
export * from './dtos/RoleAssignmentsByScopeRefsRequest';
|
|
189
|
+
export * from './enums/ScopeRefLookupStatusEnum';
|
|
190
|
+
export type {
|
|
191
|
+
ScopeRefRoleAssignment,
|
|
192
|
+
ScopeRefRoleAssignments,
|
|
193
|
+
RoleAssignmentsByScopeRefsResponse,
|
|
194
|
+
} from './dtos/RoleAssignmentsByScopeRefsResponse';
|
|
195
|
+
|
|
187
196
|
// Usuarios de API: login por Bearer, alta, rotación de secreto y diagnóstico del W5.
|
|
188
197
|
export * from './apiUser/ApiLoginRequest';
|
|
189
198
|
export * from './apiUser/ApiLoginResponse';
|
|
@@ -4,7 +4,7 @@ import type { RetailUserStatusEnum } from '../../enums/RetailUserStatusEnum';
|
|
|
4
4
|
* Shape mínimo de un vendedor para el motor de comisiones (F3b): a quién pagarle, de qué tienda es y
|
|
5
5
|
* en qué tier va.
|
|
6
6
|
*
|
|
7
|
-
* **Sin PII** —
|
|
7
|
+
* **Sin PII** — el teléfono solo viaja a pedido. `displayName` es el rótulo de conveniencia con el
|
|
8
8
|
* que el motor arma su reporte de devengo; no es identidad (la identidad vive en RBAC).
|
|
9
9
|
*
|
|
10
10
|
* `commissionTier` no es adorno: es lo que el motor usa para resolver CUÁNTO le toca a cada vendedor
|
|
@@ -18,6 +18,10 @@ export interface PrivateSellerDto {
|
|
|
18
18
|
status: RetailUserStatusEnum;
|
|
19
19
|
/** Teléfono del vendedor. Solo viaja si se pidió `includePhone=true`; `null` si no lo tiene. */
|
|
20
20
|
phone?: string | null;
|
|
21
|
+
/** Cuenta del vendedor en RBAC; `null` si todavía no tiene usuario. */
|
|
22
|
+
cognitoSub?: string | null;
|
|
23
|
+
/** Alta del vendedor en el padrón (ISO); `null` si la fila no la trae. */
|
|
24
|
+
createdAt?: string | null;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
/**
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import type { RetailUserStatusEnum } from '../../../retailOrg/enums/RetailUserStatusEnum';
|
|
2
2
|
import type { SellerTableSourceStatusEnum } from '../../enums/SellerTableSourceStatusEnum';
|
|
3
3
|
|
|
4
|
+
/** Rol del vendedor en RBAC: `key` es el `roleId` y `name` su nombre legible. */
|
|
5
|
+
export interface SellerTableRole {
|
|
6
|
+
key: string;
|
|
7
|
+
name: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
4
10
|
/** Una fila de la tabla de Vendedores: padrón + ventas de la ventana + meta + comisión. */
|
|
5
11
|
export interface SellerTableRow {
|
|
6
12
|
retailUserId: string;
|
|
@@ -12,15 +18,25 @@ export interface SellerTableRow {
|
|
|
12
18
|
storeId: string | null;
|
|
13
19
|
storeName: string | null;
|
|
14
20
|
zoneName: string | null;
|
|
15
|
-
/**
|
|
21
|
+
/** Tiene el rol `store_manager`; si RBAC cae, es el encargado (`managerRetailUserId`) de su tienda. */
|
|
16
22
|
isStoreAdmin: boolean;
|
|
23
|
+
/** Roles de RBAC en la cadena, sus zonas y tiendas; `null` si RBAC no contestó, `[]` sin cuenta o sin roles. */
|
|
24
|
+
roles: SellerTableRole[] | null;
|
|
25
|
+
/** Correo de su cuenta de RBAC; `null` sin cuenta, sin correo o con RBAC caído. */
|
|
26
|
+
email: string | null;
|
|
17
27
|
/** Sin ventas en la ventana viaja `0`: el barrido es exhaustivo. */
|
|
18
28
|
salesCount: number;
|
|
19
29
|
placedCents: number;
|
|
20
30
|
averageTicketCents: number | null;
|
|
21
31
|
lastSaleAt: string | null;
|
|
22
|
-
/**
|
|
32
|
+
/** Clientes distintos de la ventana, sin canceladas; `null` si los totales vinieron del lake. */
|
|
33
|
+
customersServed: number | null;
|
|
34
|
+
/** Alta del vendedor en el padrón (ISO); `null` si no está en el padrón. */
|
|
35
|
+
memberSince: string | null;
|
|
36
|
+
/** Δ % de los últimos 7 días (al cierre de la ventana) contra los 7 anteriores; `null` si la semana base vendió 0. */
|
|
23
37
|
weekOverWeekChangePct: number | null;
|
|
38
|
+
/** Colocación de las últimas 8 semanas, de la más vieja a la actual; `null` sin lake. */
|
|
39
|
+
weeklyPlacedCents: number[] | null;
|
|
24
40
|
/**
|
|
25
41
|
* Meta mensual (`monthCents` del mes de `to`, hora de CDMX) escalada a los días de la ventana:
|
|
26
42
|
* `round(monthCents * días / 30)`. `null` sin meta, con metas caídas o con ventana > 90 días.
|
|
@@ -37,6 +53,10 @@ export interface SellerTableSources {
|
|
|
37
53
|
roster: SellerTableSourceStatusEnum;
|
|
38
54
|
goals: SellerTableSourceStatusEnum;
|
|
39
55
|
commission: SellerTableSourceStatusEnum;
|
|
56
|
+
/** Roles y correo. */
|
|
57
|
+
rbac: SellerTableSourceStatusEnum;
|
|
58
|
+
/** «Todo» y la tendencia de 8 semanas; `DISABLED` con el flag del lake apagado. */
|
|
59
|
+
lake: SellerTableSourceStatusEnum;
|
|
40
60
|
}
|
|
41
61
|
|
|
42
62
|
/** Corte semanal del que sale `commissionCents`; días locales `YYYY-MM-DD`, ambos incluidos. */
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ProductCategoryEnum } from '../../../retailCatalog/enums/ProductCategoryEnum';
|
|
2
|
+
|
|
3
|
+
/** Colocación de una semana de 7 días; ISO, ambos extremos incluidos. */
|
|
4
|
+
export interface StoreWeeklyPlacement {
|
|
5
|
+
from: string;
|
|
6
|
+
to: string;
|
|
7
|
+
salesCount: number;
|
|
8
|
+
placedCents: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** Lo vendido de una categoría en la ventana. `category: null` = venta sin líneas de producto. */
|
|
12
|
+
export interface StoreCategoryMixEntry {
|
|
13
|
+
category: ProductCategoryEnum | null;
|
|
14
|
+
units: number;
|
|
15
|
+
placedCents: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* `GET /backoffice/stores/{storeId}/detail?from&to` — el cajón de una tienda: colocación de las 8
|
|
20
|
+
* semanas que terminan en `to` (de la más vieja a la más nueva) y mix por categoría de `[from, to]`.
|
|
21
|
+
*/
|
|
22
|
+
export interface BackofficeStoreDetailResponse {
|
|
23
|
+
storeId: string;
|
|
24
|
+
from: string;
|
|
25
|
+
to: string;
|
|
26
|
+
truncated: boolean;
|
|
27
|
+
weeklyPlacement: StoreWeeklyPlacement[];
|
|
28
|
+
/** De mayor a menor colocación. */
|
|
29
|
+
categoryMix: StoreCategoryMixEntry[];
|
|
30
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { StoreStatusEnum } from '../../../retailOrg/enums/StoreStatusEnum';
|
|
2
|
+
import type { SellerTableSourceStatusEnum } from '../../enums/SellerTableSourceStatusEnum';
|
|
3
|
+
import type { StoreKindEnum } from '../../enums/StoreKindEnum';
|
|
4
|
+
|
|
5
|
+
/** Una fila de la tabla de Tiendas: padrón + equipo + ventas de la ventana + meta. */
|
|
6
|
+
export interface StoreTableRow {
|
|
7
|
+
storeId: string;
|
|
8
|
+
/** `null` si la tienda vendió pero ya no está en el padrón. */
|
|
9
|
+
code: string | null;
|
|
10
|
+
name: string | null;
|
|
11
|
+
zoneId: string | null;
|
|
12
|
+
zoneName: string | null;
|
|
13
|
+
status: StoreStatusEnum | null;
|
|
14
|
+
/** Propia o subdistribuidor; `null` mientras ninguna fuente lo sepa. */
|
|
15
|
+
kind: StoreKindEnum | null;
|
|
16
|
+
managerRetailUserId: string | null;
|
|
17
|
+
/** `null` sin encargado o con el equipo sin leer. */
|
|
18
|
+
managerName: string | null;
|
|
19
|
+
/** Vendedores activos con esa tienda de casa; `null` con el equipo sin leer. */
|
|
20
|
+
teamActiveCount: number | null;
|
|
21
|
+
teamTotalCount: number | null;
|
|
22
|
+
/** Sin ventas en la ventana viaja `0`: el barrido es exhaustivo. */
|
|
23
|
+
salesCount: number;
|
|
24
|
+
placedCents: number;
|
|
25
|
+
averageTicketCents: number | null;
|
|
26
|
+
/** Clientes distintos que compraron en la ventana. */
|
|
27
|
+
customersServed: number | null;
|
|
28
|
+
lastSaleAt: string | null;
|
|
29
|
+
/** Δ % contra la misma ventana 7 días antes; `null` si la ventana pasa de 7 días o no hubo base. */
|
|
30
|
+
weekOverWeekChangePct: number | null;
|
|
31
|
+
/** Meta mensual de la tienda escalada a los días de la ventana; `null` sin meta, con metas caídas o ventana > 90 días. */
|
|
32
|
+
goalCents: number | null;
|
|
33
|
+
/** % de la colocación de la cadena en la ventana, a un decimal; `null` si la cadena no colocó. */
|
|
34
|
+
networkSharePct: number | null;
|
|
35
|
+
/** NPI M30: no lo calcula ningún lambda todavía. Siempre `null`. */
|
|
36
|
+
npiM30Pct: null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Estado de cada fuente. Una fuente `UNAVAILABLE` deja sus campos en `null`, nunca en `0`. */
|
|
40
|
+
export interface StoreTableSources {
|
|
41
|
+
roster: SellerTableSourceStatusEnum;
|
|
42
|
+
/** Vendedores de la cadena: equipo y nombre del encargado. */
|
|
43
|
+
team: SellerTableSourceStatusEnum;
|
|
44
|
+
goals: SellerTableSourceStatusEnum;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* `GET /backoffice/stores/table?from&to&value` — la tabla completa de Tiendas del Portal Admin VL,
|
|
49
|
+
* sin paginación. Incluye las tiendas del padrón sin ventas y las inactivas.
|
|
50
|
+
*/
|
|
51
|
+
export interface BackofficeStoreTableResponse {
|
|
52
|
+
from: string;
|
|
53
|
+
to: string;
|
|
54
|
+
/** Las ventas de la ventana pasaron el tope de lectura: los números están recortados. */
|
|
55
|
+
truncated: boolean;
|
|
56
|
+
sources: StoreTableSources;
|
|
57
|
+
items: StoreTableRow[];
|
|
58
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
/** Si una fuente de la tabla
|
|
1
|
+
/** Si una fuente de la tabla contestó (`OK`), falló (`UNAVAILABLE`) o está apagada por flag (`DISABLED`). */
|
|
2
2
|
export enum SellerTableSourceStatusEnum {
|
|
3
3
|
OK = 'OK',
|
|
4
4
|
UNAVAILABLE = 'UNAVAILABLE',
|
|
5
|
+
DISABLED = 'DISABLED',
|
|
5
6
|
}
|
|
@@ -163,6 +163,9 @@ export * from './dtos/responses/BackofficeSellerKpisResponse';
|
|
|
163
163
|
export * from './enums/SellerTableSourceStatusEnum';
|
|
164
164
|
export * from './dtos/responses/BackofficeSellerTableResponse';
|
|
165
165
|
export * from './dtos/responses/BackofficeCustomerTableResponse';
|
|
166
|
+
export * from './enums/StoreKindEnum';
|
|
167
|
+
export * from './dtos/responses/BackofficeStoreTableResponse';
|
|
168
|
+
export * from './dtos/responses/BackofficeStoreDetailResponse';
|
|
166
169
|
|
|
167
170
|
// Contratos de eventos (PascalCase + sufijo V1)
|
|
168
171
|
export * from './events/SaleCompletedV1';
|