@fiado/api-invoker 5.23.0 → 5.25.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/bin/contacts-business/api/ContactsBusinessApi.d.ts +2 -1
- package/bin/contacts-business/api/ContactsBusinessApi.js +4 -0
- package/bin/contacts-business/api/interfaces/IContactsBusinessApi.d.ts +6 -1
- package/bin/membership/MembershipApi.d.ts +12 -0
- package/bin/membership/MembershipApi.js +32 -0
- package/bin/membership/index.d.ts +2 -0
- package/bin/membership/index.js +2 -0
- package/bin/membership/interfaces/IMembershipApi.d.ts +15 -0
- package/bin/membership/interfaces/IMembershipApi.js +1 -0
- package/bin/notificationWebsockets/NotificationWebsocketApi.d.ts +12 -0
- package/bin/notificationWebsockets/NotificationWebsocketApi.js +32 -0
- package/bin/notificationWebsockets/interfaces/INotificationWebsocketApi.d.ts +15 -0
- package/bin/notificationWebsockets/interfaces/INotificationWebsocketApi.js +1 -0
- package/bin/performance-profile/PerformanceProfileApi.d.ts +12 -0
- package/bin/performance-profile/PerformanceProfileApi.js +32 -0
- package/bin/performance-profile/index.d.ts +2 -0
- package/bin/performance-profile/index.js +2 -0
- package/bin/performance-profile/interfaces/IPerformanceProfileApi.d.ts +15 -0
- package/bin/performance-profile/interfaces/IPerformanceProfileApi.js +1 -0
- package/bin/platformRbac/resolver/ApiInvokerPermissionResolver.js +12 -1
- package/bin/presence-websocket/PresenceWebsocketApi.d.ts +12 -0
- package/bin/presence-websocket/PresenceWebsocketApi.js +32 -0
- package/bin/presence-websocket/index.d.ts +2 -0
- package/bin/presence-websocket/index.js +2 -0
- package/bin/presence-websocket/interfaces/IPresenceWebsocketApi.d.ts +15 -0
- package/bin/presence-websocket/interfaces/IPresenceWebsocketApi.js +1 -0
- package/bin/retailOrg/api/RetailOrgBusinessApi.d.ts +9 -2
- package/bin/retailOrg/api/RetailOrgBusinessApi.js +16 -1
- package/bin/retailOrg/api/interfaces/IRetailOrgBusinessApi.d.ts +45 -3
- package/package.json +2 -2
- package/src/contacts-business/api/ContactsBusinessApi.ts +6 -1
- package/src/contacts-business/api/interfaces/IContactsBusinessApi.ts +7 -1
- package/src/platformRbac/resolver/ApiInvokerPermissionResolver.ts +12 -1
- package/src/retailOrg/api/RetailOrgBusinessApi.ts +24 -2
- package/src/retailOrg/api/interfaces/IRetailOrgBusinessApi.ts +51 -2
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { IHttpRequest } from "@fiado/http-client";
|
|
2
2
|
import type { ApiGatewayResponse } from "@fiado/gateway-adapter";
|
|
3
|
-
import type { PrimaryEmailByDirectoryRequest, PrimaryEmailResponse } from "@fiado/type-kit/bin/emailVerification/index.js";
|
|
3
|
+
import type { PrimaryEmailByDirectoryRequest, PrimaryEmailResponse, EmailStartByDirectoryRequest, EmailStartByDirectoryResponse } from "@fiado/type-kit/bin/emailVerification/index.js";
|
|
4
4
|
import type { IContactsBusinessApi } from "./interfaces/IContactsBusinessApi.js";
|
|
5
5
|
export default class ContactsBusinessApi implements IContactsBusinessApi {
|
|
6
6
|
private httpRequest;
|
|
7
7
|
private readonly baseUrl;
|
|
8
8
|
constructor(httpRequest: IHttpRequest);
|
|
9
9
|
getPrimaryEmail(request: PrimaryEmailByDirectoryRequest): Promise<ApiGatewayResponse<PrimaryEmailResponse>>;
|
|
10
|
+
startVerification(request: EmailStartByDirectoryRequest): Promise<ApiGatewayResponse<EmailStartByDirectoryResponse>>;
|
|
10
11
|
}
|
|
@@ -21,6 +21,10 @@ let ContactsBusinessApi = class ContactsBusinessApi {
|
|
|
21
21
|
const url = `${this.baseUrl}/internal/email/primary`;
|
|
22
22
|
return await this.httpRequest.get(url, { directoryId: request.directoryId });
|
|
23
23
|
}
|
|
24
|
+
async startVerification(request) {
|
|
25
|
+
const url = `${this.baseUrl}/internal/email/start-verification`;
|
|
26
|
+
return await this.httpRequest.post(url, request);
|
|
27
|
+
}
|
|
24
28
|
};
|
|
25
29
|
ContactsBusinessApi = __decorate([
|
|
26
30
|
injectable(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiGatewayResponse } from "@fiado/gateway-adapter";
|
|
2
|
-
import type { PrimaryEmailByDirectoryRequest, PrimaryEmailResponse } from "@fiado/type-kit/bin/emailVerification/index.js";
|
|
2
|
+
import type { PrimaryEmailByDirectoryRequest, PrimaryEmailResponse, EmailStartByDirectoryRequest, EmailStartByDirectoryResponse } from "@fiado/type-kit/bin/emailVerification/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Cliente del lambda contacts-business (fuente de verdad de correos verificados).
|
|
5
5
|
* Lo consume benefits-marketplace-business en el gate de onboarding de remesas (F2).
|
|
@@ -11,4 +11,9 @@ export interface IContactsBusinessApi {
|
|
|
11
11
|
* `email` es null si el directorio no tiene un correo verificado marcado oficial.
|
|
12
12
|
*/
|
|
13
13
|
getPrimaryEmail(request: PrimaryEmailByDirectoryRequest): Promise<ApiGatewayResponse<PrimaryEmailResponse>>;
|
|
14
|
+
/**
|
|
15
|
+
* Registra un correo del directorio y dispara su verificación.
|
|
16
|
+
* Backend: POST /internal/email/start-verification (API privada/VPC).
|
|
17
|
+
*/
|
|
18
|
+
startVerification(request: EmailStartByDirectoryRequest): Promise<ApiGatewayResponse<EmailStartByDirectoryResponse>>;
|
|
14
19
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IHttpRequest } from "@fiado/http-client";
|
|
2
|
+
import { IMembershipApi } from "./interfaces/IMembershipApi.js";
|
|
3
|
+
type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
|
|
4
|
+
export declare class MembershipApi implements IMembershipApi {
|
|
5
|
+
private httpRequest;
|
|
6
|
+
private readonly baseUrl;
|
|
7
|
+
constructor(httpRequest: IHttpRequest);
|
|
8
|
+
deleteByDirectoryId(directoryId: string): Promise<FiadoApiResponse<{
|
|
9
|
+
deletedCount: number;
|
|
10
|
+
}>>;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { inject, injectable } from "inversify";
|
|
14
|
+
import dotenv from 'dotenv';
|
|
15
|
+
dotenv.config();
|
|
16
|
+
let MembershipApi = class MembershipApi {
|
|
17
|
+
httpRequest;
|
|
18
|
+
baseUrl = process.env.MEMBERSHIP_BUSINESS_LAMBDA_URL || "";
|
|
19
|
+
constructor(httpRequest) {
|
|
20
|
+
this.httpRequest = httpRequest;
|
|
21
|
+
}
|
|
22
|
+
async deleteByDirectoryId(directoryId) {
|
|
23
|
+
const url = `${this.baseUrl}private/directory/${directoryId}`;
|
|
24
|
+
return await this.httpRequest.delete(url);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
MembershipApi = __decorate([
|
|
28
|
+
injectable(),
|
|
29
|
+
__param(0, inject("IHttpRequest")),
|
|
30
|
+
__metadata("design:paramtypes", [Object])
|
|
31
|
+
], MembershipApi);
|
|
32
|
+
export { MembershipApi };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
|
|
2
|
+
/**
|
|
3
|
+
* Interfaz para el servicio Membership (membership-business).
|
|
4
|
+
*/
|
|
5
|
+
export interface IMembershipApi {
|
|
6
|
+
/**
|
|
7
|
+
* Borra en cascada las membresías asociadas a un directoryId.
|
|
8
|
+
* @param directoryId ID del directorio.
|
|
9
|
+
* @throws {Error} Lanza un error si los parámetros de entrada son inválidos.
|
|
10
|
+
*/
|
|
11
|
+
deleteByDirectoryId(directoryId: string): Promise<FiadoApiResponse<{
|
|
12
|
+
deletedCount: number;
|
|
13
|
+
}>>;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IHttpRequest } from "@fiado/http-client";
|
|
2
|
+
import { INotificationWebsocketApi } from "./interfaces/INotificationWebsocketApi.js";
|
|
3
|
+
type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
|
|
4
|
+
export declare class NotificationWebsocketApi implements INotificationWebsocketApi {
|
|
5
|
+
private httpRequest;
|
|
6
|
+
private readonly baseUrl;
|
|
7
|
+
constructor(httpRequest: IHttpRequest);
|
|
8
|
+
deleteByDirectoryId(directoryId: string): Promise<FiadoApiResponse<{
|
|
9
|
+
deletedCount: number;
|
|
10
|
+
}>>;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { inject, injectable } from "inversify";
|
|
14
|
+
import dotenv from 'dotenv';
|
|
15
|
+
dotenv.config();
|
|
16
|
+
let NotificationWebsocketApi = class NotificationWebsocketApi {
|
|
17
|
+
httpRequest;
|
|
18
|
+
baseUrl = process.env.NOTIFICATIONS_WEBSOCKET_LAMBDA_URL || "";
|
|
19
|
+
constructor(httpRequest) {
|
|
20
|
+
this.httpRequest = httpRequest;
|
|
21
|
+
}
|
|
22
|
+
async deleteByDirectoryId(directoryId) {
|
|
23
|
+
const url = `${this.baseUrl}private/directory/${directoryId}`;
|
|
24
|
+
return await this.httpRequest.delete(url);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
NotificationWebsocketApi = __decorate([
|
|
28
|
+
injectable(),
|
|
29
|
+
__param(0, inject("IHttpRequest")),
|
|
30
|
+
__metadata("design:paramtypes", [Object])
|
|
31
|
+
], NotificationWebsocketApi);
|
|
32
|
+
export { NotificationWebsocketApi };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
|
|
2
|
+
/**
|
|
3
|
+
* Interfaz para el servicio Notifications Websocket (notifications-websocket).
|
|
4
|
+
*/
|
|
5
|
+
export interface INotificationWebsocketApi {
|
|
6
|
+
/**
|
|
7
|
+
* Borra en cascada las conexiones/notificaciones WS asociadas a un directoryId.
|
|
8
|
+
* @param directoryId ID del directorio.
|
|
9
|
+
* @throws {Error} Lanza un error si los parámetros de entrada son inválidos.
|
|
10
|
+
*/
|
|
11
|
+
deleteByDirectoryId(directoryId: string): Promise<FiadoApiResponse<{
|
|
12
|
+
deletedCount: number;
|
|
13
|
+
}>>;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IHttpRequest } from "@fiado/http-client";
|
|
2
|
+
import { IPerformanceProfileApi } from "./interfaces/IPerformanceProfileApi.js";
|
|
3
|
+
type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
|
|
4
|
+
export declare class PerformanceProfileApi implements IPerformanceProfileApi {
|
|
5
|
+
private httpRequest;
|
|
6
|
+
private readonly baseUrl;
|
|
7
|
+
constructor(httpRequest: IHttpRequest);
|
|
8
|
+
deleteByDirectoryId(directoryId: string): Promise<FiadoApiResponse<{
|
|
9
|
+
deletedCount: number;
|
|
10
|
+
}>>;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { inject, injectable } from "inversify";
|
|
14
|
+
import dotenv from 'dotenv';
|
|
15
|
+
dotenv.config();
|
|
16
|
+
let PerformanceProfileApi = class PerformanceProfileApi {
|
|
17
|
+
httpRequest;
|
|
18
|
+
baseUrl = process.env.PERFORMANCE_PROFILE_BUSINESS_LAMBDA_URL || "";
|
|
19
|
+
constructor(httpRequest) {
|
|
20
|
+
this.httpRequest = httpRequest;
|
|
21
|
+
}
|
|
22
|
+
async deleteByDirectoryId(directoryId) {
|
|
23
|
+
const url = `${this.baseUrl}private/directory/${directoryId}`;
|
|
24
|
+
return await this.httpRequest.delete(url);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
PerformanceProfileApi = __decorate([
|
|
28
|
+
injectable(),
|
|
29
|
+
__param(0, inject("IHttpRequest")),
|
|
30
|
+
__metadata("design:paramtypes", [Object])
|
|
31
|
+
], PerformanceProfileApi);
|
|
32
|
+
export { PerformanceProfileApi };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
|
|
2
|
+
/**
|
|
3
|
+
* Interfaz para el servicio Performance Profile (performance-profile-business).
|
|
4
|
+
*/
|
|
5
|
+
export interface IPerformanceProfileApi {
|
|
6
|
+
/**
|
|
7
|
+
* Borra en cascada los perfiles de desempeño asociados a un directoryId.
|
|
8
|
+
* @param directoryId ID del directorio.
|
|
9
|
+
* @throws {Error} Lanza un error si los parámetros de entrada son inválidos.
|
|
10
|
+
*/
|
|
11
|
+
deleteByDirectoryId(directoryId: string): Promise<FiadoApiResponse<{
|
|
12
|
+
deletedCount: number;
|
|
13
|
+
}>>;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -38,7 +38,18 @@ let ApiInvokerPermissionResolver = class ApiInvokerPermissionResolver {
|
|
|
38
38
|
}
|
|
39
39
|
async resolve(input) {
|
|
40
40
|
const cacheable = input.roleAssignmentsFromToken === undefined;
|
|
41
|
-
|
|
41
|
+
// DEC-RBAC-124: el tipo de principal entra en la cache key. NO es defensa contra colisión
|
|
42
|
+
// —los subs de integración llevan prefijo `INT#` y no chocan con un UUID de Cognito— sino
|
|
43
|
+
// para que el canal quede explícito y un cambio futuro de formato no cause aliasing
|
|
44
|
+
// silencioso entre un usuario y una integración.
|
|
45
|
+
//
|
|
46
|
+
// Se lee con cast en vez de tiparlo desde `ResolveInput` A PROPÓSITO: `principalType` recién
|
|
47
|
+
// existe en `@fiado/gateway-adapter` 4.x, y esta lib la consume toda la flota. Atarla al
|
|
48
|
+
// prerelease obligaría a todos a subir de major. Así compila igual contra 3.x y 4.x, y el
|
|
49
|
+
// reenvío al endpoint privado funciona en runtime porque `resolvePermissions(input)` manda
|
|
50
|
+
// el objeto entero sin filtrar campos.
|
|
51
|
+
const principalType = input.principalType ?? "USER";
|
|
52
|
+
const key = `${principalType}#${input.issuer ?? ""}#${input.cognitoSub}`;
|
|
42
53
|
if (cacheable) {
|
|
43
54
|
const hit = this._cache.get(key);
|
|
44
55
|
if (hit)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IHttpRequest } from "@fiado/http-client";
|
|
2
|
+
import { IPresenceWebsocketApi } from "./interfaces/IPresenceWebsocketApi.js";
|
|
3
|
+
type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
|
|
4
|
+
export declare class PresenceWebsocketApi implements IPresenceWebsocketApi {
|
|
5
|
+
private httpRequest;
|
|
6
|
+
private readonly baseUrl;
|
|
7
|
+
constructor(httpRequest: IHttpRequest);
|
|
8
|
+
deleteByDirectoryId(directoryId: string): Promise<FiadoApiResponse<{
|
|
9
|
+
deletedCount: number;
|
|
10
|
+
}>>;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
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;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { inject, injectable } from "inversify";
|
|
14
|
+
import dotenv from 'dotenv';
|
|
15
|
+
dotenv.config();
|
|
16
|
+
let PresenceWebsocketApi = class PresenceWebsocketApi {
|
|
17
|
+
httpRequest;
|
|
18
|
+
baseUrl = process.env.PRESENCE_WEBSOCKET_LAMBDA_URL || "";
|
|
19
|
+
constructor(httpRequest) {
|
|
20
|
+
this.httpRequest = httpRequest;
|
|
21
|
+
}
|
|
22
|
+
async deleteByDirectoryId(directoryId) {
|
|
23
|
+
const url = `${this.baseUrl}private/directory/${directoryId}`;
|
|
24
|
+
return await this.httpRequest.delete(url);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
PresenceWebsocketApi = __decorate([
|
|
28
|
+
injectable(),
|
|
29
|
+
__param(0, inject("IHttpRequest")),
|
|
30
|
+
__metadata("design:paramtypes", [Object])
|
|
31
|
+
], PresenceWebsocketApi);
|
|
32
|
+
export { PresenceWebsocketApi };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
type FiadoApiResponse<T> = import("@fiado/type-kit/bin/apiResponse/dtos/FiadoApiResponse.js").default<T>;
|
|
2
|
+
/**
|
|
3
|
+
* Interfaz para el servicio Presence Websocket (presence-websocket).
|
|
4
|
+
*/
|
|
5
|
+
export interface IPresenceWebsocketApi {
|
|
6
|
+
/**
|
|
7
|
+
* Borra en cascada los registros de presencia asociados a un directoryId.
|
|
8
|
+
* @param directoryId ID del directorio.
|
|
9
|
+
* @throws {Error} Lanza un error si los parámetros de entrada son inválidos.
|
|
10
|
+
*/
|
|
11
|
+
deleteByDirectoryId(directoryId: string): Promise<FiadoApiResponse<{
|
|
12
|
+
deletedCount: number;
|
|
13
|
+
}>>;
|
|
14
|
+
}
|
|
15
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { IHttpRequest } from "@fiado/http-client";
|
|
2
2
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
3
3
|
import { RetailerValidationDto, StoreValidationDto, RetailUserValidationDto, CollectorValidationDto, PrivateSellerListResponse, RetailUserStatusEnum } from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
4
|
-
import { IRetailOrgBusinessApi } from "./interfaces/IRetailOrgBusinessApi.js";
|
|
4
|
+
import { IRetailOrgBusinessApi, StoreRosterStatusFilter } from "./interfaces/IRetailOrgBusinessApi.js";
|
|
5
5
|
/**
|
|
6
|
-
* Publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1) para sus
|
|
6
|
+
* Publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1) para sus 8
|
|
7
7
|
* endpoints privados de validación. Contrato y semántica completos → `IRetailOrgBusinessApi`.
|
|
8
8
|
*
|
|
9
9
|
* Los paths y el `?tenantId=` fueron verificados contra dev (200 + negativos 400/404) el
|
|
@@ -23,6 +23,13 @@ export default class RetailOrgBusinessApi implements IRetailOrgBusinessApi {
|
|
|
23
23
|
getRetailer(retailerId: string, tenantId: string): Promise<StandardResponse<RetailerValidationDto>>;
|
|
24
24
|
getRetailerByStore(storeId: string, tenantId: string): Promise<StandardResponse<RetailerValidationDto>>;
|
|
25
25
|
getStore(retailerId: string, storeId: string, tenantId: string): Promise<StandardResponse<StoreValidationDto>>;
|
|
26
|
+
/**
|
|
27
|
+
* SureKeep F3 — el padrón de tiendas que le faltaba al tablero de cohorte de «Análisis de
|
|
28
|
+
* ventas»: sin él, la tienda que lleva 60 días sin vender no existe para el tablero. Contrato y
|
|
29
|
+
* semántica completos (incluido por qué acá `status` SÍ tiene default y en `listSellers` no)
|
|
30
|
+
* → `IRetailOrgBusinessApi.listStoresByRetailer`.
|
|
31
|
+
*/
|
|
32
|
+
listStoresByRetailer(retailerId: string, tenantId: string, status?: StoreRosterStatusFilter): Promise<StandardResponse<StoreValidationDto[]>>;
|
|
26
33
|
getStoreUsers(retailerId: string, storeId: string, tenantId: string): Promise<StandardResponse<RetailUserValidationDto[]>>;
|
|
27
34
|
getUserByCognitoSub(cognitoSub: string, tenantId: string): Promise<StandardResponse<RetailUserValidationDto>>;
|
|
28
35
|
listActiveCollectorsByRetailer(retailerId: string, tenantId: string): Promise<StandardResponse<CollectorValidationDto[]>>;
|
|
@@ -12,7 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
12
12
|
};
|
|
13
13
|
import { inject, injectable } from "inversify";
|
|
14
14
|
/**
|
|
15
|
-
* Publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1) para sus
|
|
15
|
+
* Publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1) para sus 8
|
|
16
16
|
* endpoints privados de validación. Contrato y semántica completos → `IRetailOrgBusinessApi`.
|
|
17
17
|
*
|
|
18
18
|
* Los paths y el `?tenantId=` fueron verificados contra dev (200 + negativos 400/404) el
|
|
@@ -43,6 +43,21 @@ let RetailOrgBusinessApi = class RetailOrgBusinessApi {
|
|
|
43
43
|
const url = `${this.baseUrl}/private/retailers/${encodeURIComponent(retailerId)}/stores/${encodeURIComponent(storeId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
44
44
|
return await this.httpRequest.get(url);
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* SureKeep F3 — el padrón de tiendas que le faltaba al tablero de cohorte de «Análisis de
|
|
48
|
+
* ventas»: sin él, la tienda que lleva 60 días sin vender no existe para el tablero. Contrato y
|
|
49
|
+
* semántica completos (incluido por qué acá `status` SÍ tiene default y en `listSellers` no)
|
|
50
|
+
* → `IRetailOrgBusinessApi.listStoresByRetailer`.
|
|
51
|
+
*/
|
|
52
|
+
async listStoresByRetailer(retailerId, tenantId, status) {
|
|
53
|
+
// `URLSearchParams` en vez de concatenar: `status` es opcional y armar el `&status=` a mano
|
|
54
|
+
// deja un `&status=undefined` en cuanto alguien se distrae.
|
|
55
|
+
const query = new URLSearchParams({ tenantId });
|
|
56
|
+
if (status)
|
|
57
|
+
query.set("status", status);
|
|
58
|
+
const path = `/private/retailers/${encodeURIComponent(retailerId)}/stores`;
|
|
59
|
+
return await this.httpRequest.get(`${this.baseUrl}${path}?${query.toString()}`);
|
|
60
|
+
}
|
|
46
61
|
async getStoreUsers(retailerId, storeId, tenantId) {
|
|
47
62
|
const url = `${this.baseUrl}/private/retailers/${encodeURIComponent(retailerId)}/users/by-store/${encodeURIComponent(storeId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
48
63
|
return await this.httpRequest.get(url);
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
2
|
-
import { RetailerValidationDto, StoreValidationDto, RetailUserValidationDto, CollectorValidationDto, PrivateSellerListResponse, RetailUserStatusEnum } from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
2
|
+
import { RetailerValidationDto, StoreValidationDto, RetailUserValidationDto, CollectorValidationDto, PrivateSellerListResponse, RetailUserStatusEnum, StoreStatusEnum } from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
3
|
+
/**
|
|
4
|
+
* Filtro de `listStoresByRetailer`. `"ALL"` no es un estado de tienda: es la ausencia de filtro, y
|
|
5
|
+
* va en el MISMO parámetro que los estados porque los dos hablan del mismo eje — un segundo flag
|
|
6
|
+
* tipo `includeInactive` admitiría combinaciones sin sentido que alguien tendría que resolver.
|
|
7
|
+
*/
|
|
8
|
+
export type StoreRosterStatusFilter = StoreStatusEnum | "ALL";
|
|
3
9
|
/**
|
|
4
10
|
* Contrato del publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1)
|
|
5
|
-
* para sus
|
|
11
|
+
* para sus 8 endpoints privados de VALIDACIÓN (service-to-service, VPC-only).
|
|
6
12
|
*
|
|
7
13
|
* Consumidores previstos (regla R5 — cruces entre lambdas son SOLO lecturas de validación;
|
|
8
14
|
* ningún lambda escribe en tabla ajena):
|
|
@@ -12,7 +18,7 @@ import { RetailerValidationDto, StoreValidationDto, RetailUserValidationDto, Col
|
|
|
12
18
|
* - `loan-collector-assignment-business` → lista cobradores ACTIVE del retailer para asignar cartera
|
|
13
19
|
*
|
|
14
20
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
15
|
-
* `tenantId` es OBLIGATORIO en los
|
|
21
|
+
* `tenantId` es OBLIGATORIO en TODOS los métodos — no es un detalle de firma.
|
|
16
22
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
17
23
|
* Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC),
|
|
18
24
|
* así que el lambda destino no tiene `AuthContext.issuer` y NO puede inferir el silo. El caller
|
|
@@ -75,6 +81,42 @@ export interface IRetailOrgBusinessApi {
|
|
|
75
81
|
* @throws si la tienda no existe o es de OTRO retailer (`404 STORE_NOT_FOUND` — verificado en dev).
|
|
76
82
|
*/
|
|
77
83
|
getStore(retailerId: string, storeId: string, tenantId: string): Promise<StandardResponse<StoreValidationDto>>;
|
|
84
|
+
/**
|
|
85
|
+
* `GET /private/retailers/{retailerId}/stores` (SureKeep F3) — el **padrón de tiendas** de una
|
|
86
|
+
* cadena.
|
|
87
|
+
*
|
|
88
|
+
* ── 🔴 Por qué este método existe ────────────────────────────────────────────────────────────
|
|
89
|
+
* Lo consume el tablero de cohorte de «Análisis de ventas» (`retail-wizard-business`), que arma
|
|
90
|
+
* la lista de tiendas a partir de las VENTAS que leyó. Con eso, **la tienda que lleva 60 días sin
|
|
91
|
+
* vender no existe para el tablero** — y es exactamente la que hay que mirar. Este es el único
|
|
92
|
+
* endpoint que sirve el padrón completo: `getStore` resuelve UNA tienda y `publicListStores` va
|
|
93
|
+
* detrás del `W4Authorizer` (token de usuario, no invocable entre lambdas).
|
|
94
|
+
*
|
|
95
|
+
* NO se deriva de `listSellers`: ese endpoint escribe en `SharedPiiAccessLog_GT` y esa bitácora
|
|
96
|
+
* es la única traza de una exportación masiva de datos de empleados. Pedirle ids de tienda la
|
|
97
|
+
* llenaría de filas con una intención falsa.
|
|
98
|
+
*
|
|
99
|
+
* Devuelve el mismo `StoreValidationDto` que `getStore` — `storeId`, `retailerId`, `zoneId`,
|
|
100
|
+
* `zoneName`, `code`, `name`, `status` — con el `status` EFECTIVO (cascada del retailer padre ya
|
|
101
|
+
* aplicada). El `zoneName` sale de la tabla de zonas del propio retail-org: el consumidor no
|
|
102
|
+
* puede resolver un `zoneId` de otro dominio, y hoy lo saca de un snapshot congelado en la venta,
|
|
103
|
+
* así que una tienda re-zonificada muestra la zona vieja.
|
|
104
|
+
*
|
|
105
|
+
* ── ⚠️ `status` SÍ tiene default, al revés que `listSellers` ─────────────────────────────────
|
|
106
|
+
* Omitirlo devuelve **solo las `ACTIVE`**. La asimetría es deliberada: allá un vendedor dado de
|
|
107
|
+
* baja el día 20 sí tiene comisión por lo que vendió hasta el 19, así que filtrar lo perdería.
|
|
108
|
+
* Acá el consumidor cruza este padrón con ventas que YA leyó, o sea que la tienda cerrada que
|
|
109
|
+
* vendió dentro de la ventana entra igual por el lado de las ventas — filtrar no puede perder
|
|
110
|
+
* una tienda que vendió, solo evita agregar un cero permanente a un tablero cuyo trabajo es que
|
|
111
|
+
* las filas en cero llamen la atención. Pasa `"ALL"` para el padrón completo.
|
|
112
|
+
*
|
|
113
|
+
* @throws `404 RETAILER_NOT_FOUND` si el retailer no existe en ese silo. Un `[]` no distinguiría
|
|
114
|
+
* "esta cadena no tiene tiendas" de "preguntaste por una cadena que no existe", y lo segundo
|
|
115
|
+
* dejaría el tablero mudo sin que nadie sospeche del request.
|
|
116
|
+
* @throws `400 STORE_STATUS_FILTER_INVALID` si `status` no es del catálogo · `400 UNKNOWN_TENANT`
|
|
117
|
+
* sin `tenantId`.
|
|
118
|
+
*/
|
|
119
|
+
listStoresByRetailer(retailerId: string, tenantId: string, status?: StoreRosterStatusFilter): Promise<StandardResponse<StoreValidationDto[]>>;
|
|
78
120
|
/**
|
|
79
121
|
* GET /private/retailers/{retailerId}/users/by-store/{storeId} — usuarios retail cuya tienda base
|
|
80
122
|
* (`homeStoreId`) es esa. Devuelve `[]` (no 404) si la tienda no tiene usuarios asignados.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fiado/api-invoker",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.25.0",
|
|
4
4
|
"description": "Sirve como un puente entre diferentes funciones lambda, facilitando la comunicación entre ellas a través de invocaciones http",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "bin/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@fiado/gateway-adapter": "^3.9.0",
|
|
35
35
|
"@fiado/http-client": "^2.0.1",
|
|
36
36
|
"@fiado/logger": "^1.1.3",
|
|
37
|
-
"@fiado/type-kit": "^3.
|
|
37
|
+
"@fiado/type-kit": "^3.295.0",
|
|
38
38
|
"dotenv": "^16.4.7"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { inject, injectable } from "inversify";
|
|
2
2
|
import type { IHttpRequest } from "@fiado/http-client";
|
|
3
3
|
import type { ApiGatewayResponse } from "@fiado/gateway-adapter";
|
|
4
|
-
import type { PrimaryEmailByDirectoryRequest, PrimaryEmailResponse } from "@fiado/type-kit/bin/emailVerification/index.js";
|
|
4
|
+
import type { PrimaryEmailByDirectoryRequest, PrimaryEmailResponse, EmailStartByDirectoryRequest, EmailStartByDirectoryResponse } from "@fiado/type-kit/bin/emailVerification/index.js";
|
|
5
5
|
import type { IContactsBusinessApi } from "./interfaces/IContactsBusinessApi.js";
|
|
6
6
|
|
|
7
7
|
@injectable()
|
|
@@ -14,4 +14,9 @@ export default class ContactsBusinessApi implements IContactsBusinessApi {
|
|
|
14
14
|
const url = `${this.baseUrl}/internal/email/primary`;
|
|
15
15
|
return await this.httpRequest.get(url, { directoryId: request.directoryId });
|
|
16
16
|
}
|
|
17
|
+
|
|
18
|
+
async startVerification(request: EmailStartByDirectoryRequest): Promise<ApiGatewayResponse<EmailStartByDirectoryResponse>> {
|
|
19
|
+
const url = `${this.baseUrl}/internal/email/start-verification`;
|
|
20
|
+
return await this.httpRequest.post(url, request);
|
|
21
|
+
}
|
|
17
22
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ApiGatewayResponse } from "@fiado/gateway-adapter";
|
|
2
|
-
import type { PrimaryEmailByDirectoryRequest, PrimaryEmailResponse } from "@fiado/type-kit/bin/emailVerification/index.js";
|
|
2
|
+
import type { PrimaryEmailByDirectoryRequest, PrimaryEmailResponse, EmailStartByDirectoryRequest, EmailStartByDirectoryResponse } from "@fiado/type-kit/bin/emailVerification/index.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Cliente del lambda contacts-business (fuente de verdad de correos verificados).
|
|
@@ -12,4 +12,10 @@ export interface IContactsBusinessApi {
|
|
|
12
12
|
* `email` es null si el directorio no tiene un correo verificado marcado oficial.
|
|
13
13
|
*/
|
|
14
14
|
getPrimaryEmail(request: PrimaryEmailByDirectoryRequest): Promise<ApiGatewayResponse<PrimaryEmailResponse>>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Registra un correo del directorio y dispara su verificación.
|
|
18
|
+
* Backend: POST /internal/email/start-verification (API privada/VPC).
|
|
19
|
+
*/
|
|
20
|
+
startVerification(request: EmailStartByDirectoryRequest): Promise<ApiGatewayResponse<EmailStartByDirectoryResponse>>;
|
|
15
21
|
}
|
|
@@ -31,7 +31,18 @@ export class ApiInvokerPermissionResolver {
|
|
|
31
31
|
}
|
|
32
32
|
async resolve(input: ResolveInput): Promise<ResolvedPermissions> {
|
|
33
33
|
const cacheable = input.roleAssignmentsFromToken === undefined;
|
|
34
|
-
|
|
34
|
+
// DEC-RBAC-124: el tipo de principal entra en la cache key. NO es defensa contra colisión
|
|
35
|
+
// —los subs de integración llevan prefijo `INT#` y no chocan con un UUID de Cognito— sino
|
|
36
|
+
// para que el canal quede explícito y un cambio futuro de formato no cause aliasing
|
|
37
|
+
// silencioso entre un usuario y una integración.
|
|
38
|
+
//
|
|
39
|
+
// Se lee con cast en vez de tiparlo desde `ResolveInput` A PROPÓSITO: `principalType` recién
|
|
40
|
+
// existe en `@fiado/gateway-adapter` 4.x, y esta lib la consume toda la flota. Atarla al
|
|
41
|
+
// prerelease obligaría a todos a subir de major. Así compila igual contra 3.x y 4.x, y el
|
|
42
|
+
// reenvío al endpoint privado funciona en runtime porque `resolvePermissions(input)` manda
|
|
43
|
+
// el objeto entero sin filtrar campos.
|
|
44
|
+
const principalType = (input as { principalType?: string }).principalType ?? "USER";
|
|
45
|
+
const key = `${principalType}#${input.issuer ?? ""}#${input.cognitoSub}`;
|
|
35
46
|
if (cacheable) {
|
|
36
47
|
const hit = this._cache.get(key);
|
|
37
48
|
if (hit) return hit;
|
|
@@ -9,10 +9,13 @@ import {
|
|
|
9
9
|
PrivateSellerListResponse,
|
|
10
10
|
RetailUserStatusEnum,
|
|
11
11
|
} from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
IRetailOrgBusinessApi,
|
|
14
|
+
StoreRosterStatusFilter,
|
|
15
|
+
} from "./interfaces/IRetailOrgBusinessApi.js";
|
|
13
16
|
|
|
14
17
|
/**
|
|
15
|
-
* Publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1) para sus
|
|
18
|
+
* Publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1) para sus 8
|
|
16
19
|
* endpoints privados de validación. Contrato y semántica completos → `IRetailOrgBusinessApi`.
|
|
17
20
|
*
|
|
18
21
|
* Los paths y el `?tenantId=` fueron verificados contra dev (200 + negativos 400/404) el
|
|
@@ -56,6 +59,25 @@ export default class RetailOrgBusinessApi implements IRetailOrgBusinessApi {
|
|
|
56
59
|
return await this.httpRequest.get(url);
|
|
57
60
|
}
|
|
58
61
|
|
|
62
|
+
/**
|
|
63
|
+
* SureKeep F3 — el padrón de tiendas que le faltaba al tablero de cohorte de «Análisis de
|
|
64
|
+
* ventas»: sin él, la tienda que lleva 60 días sin vender no existe para el tablero. Contrato y
|
|
65
|
+
* semántica completos (incluido por qué acá `status` SÍ tiene default y en `listSellers` no)
|
|
66
|
+
* → `IRetailOrgBusinessApi.listStoresByRetailer`.
|
|
67
|
+
*/
|
|
68
|
+
async listStoresByRetailer(
|
|
69
|
+
retailerId: string,
|
|
70
|
+
tenantId: string,
|
|
71
|
+
status?: StoreRosterStatusFilter,
|
|
72
|
+
): Promise<StandardResponse<StoreValidationDto[]>> {
|
|
73
|
+
// `URLSearchParams` en vez de concatenar: `status` es opcional y armar el `&status=` a mano
|
|
74
|
+
// deja un `&status=undefined` en cuanto alguien se distrae.
|
|
75
|
+
const query = new URLSearchParams({ tenantId });
|
|
76
|
+
if (status) query.set("status", status);
|
|
77
|
+
const path = `/private/retailers/${encodeURIComponent(retailerId)}/stores`;
|
|
78
|
+
return await this.httpRequest.get(`${this.baseUrl}${path}?${query.toString()}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
async getStoreUsers(
|
|
60
82
|
retailerId: string,
|
|
61
83
|
storeId: string,
|
|
@@ -6,11 +6,19 @@ import {
|
|
|
6
6
|
CollectorValidationDto,
|
|
7
7
|
PrivateSellerListResponse,
|
|
8
8
|
RetailUserStatusEnum,
|
|
9
|
+
StoreStatusEnum,
|
|
9
10
|
} from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Filtro de `listStoresByRetailer`. `"ALL"` no es un estado de tienda: es la ausencia de filtro, y
|
|
14
|
+
* va en el MISMO parámetro que los estados porque los dos hablan del mismo eje — un segundo flag
|
|
15
|
+
* tipo `includeInactive` admitiría combinaciones sin sentido que alguien tendría que resolver.
|
|
16
|
+
*/
|
|
17
|
+
export type StoreRosterStatusFilter = StoreStatusEnum | "ALL";
|
|
18
|
+
|
|
11
19
|
/**
|
|
12
20
|
* Contrato del publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1)
|
|
13
|
-
* para sus
|
|
21
|
+
* para sus 8 endpoints privados de VALIDACIÓN (service-to-service, VPC-only).
|
|
14
22
|
*
|
|
15
23
|
* Consumidores previstos (regla R5 — cruces entre lambdas son SOLO lecturas de validación;
|
|
16
24
|
* ningún lambda escribe en tabla ajena):
|
|
@@ -20,7 +28,7 @@ import {
|
|
|
20
28
|
* - `loan-collector-assignment-business` → lista cobradores ACTIVE del retailer para asignar cartera
|
|
21
29
|
*
|
|
22
30
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
-
* `tenantId` es OBLIGATORIO en los
|
|
31
|
+
* `tenantId` es OBLIGATORIO en TODOS los métodos — no es un detalle de firma.
|
|
24
32
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
25
33
|
* Los privados NO llevan token de usuario (`Feature.ANONIMUS`; la protección es la red VPC),
|
|
26
34
|
* así que el lambda destino no tiene `AuthContext.issuer` y NO puede inferir el silo. El caller
|
|
@@ -96,6 +104,47 @@ export interface IRetailOrgBusinessApi {
|
|
|
96
104
|
tenantId: string,
|
|
97
105
|
): Promise<StandardResponse<StoreValidationDto>>;
|
|
98
106
|
|
|
107
|
+
/**
|
|
108
|
+
* `GET /private/retailers/{retailerId}/stores` (SureKeep F3) — el **padrón de tiendas** de una
|
|
109
|
+
* cadena.
|
|
110
|
+
*
|
|
111
|
+
* ── 🔴 Por qué este método existe ────────────────────────────────────────────────────────────
|
|
112
|
+
* Lo consume el tablero de cohorte de «Análisis de ventas» (`retail-wizard-business`), que arma
|
|
113
|
+
* la lista de tiendas a partir de las VENTAS que leyó. Con eso, **la tienda que lleva 60 días sin
|
|
114
|
+
* vender no existe para el tablero** — y es exactamente la que hay que mirar. Este es el único
|
|
115
|
+
* endpoint que sirve el padrón completo: `getStore` resuelve UNA tienda y `publicListStores` va
|
|
116
|
+
* detrás del `W4Authorizer` (token de usuario, no invocable entre lambdas).
|
|
117
|
+
*
|
|
118
|
+
* NO se deriva de `listSellers`: ese endpoint escribe en `SharedPiiAccessLog_GT` y esa bitácora
|
|
119
|
+
* es la única traza de una exportación masiva de datos de empleados. Pedirle ids de tienda la
|
|
120
|
+
* llenaría de filas con una intención falsa.
|
|
121
|
+
*
|
|
122
|
+
* Devuelve el mismo `StoreValidationDto` que `getStore` — `storeId`, `retailerId`, `zoneId`,
|
|
123
|
+
* `zoneName`, `code`, `name`, `status` — con el `status` EFECTIVO (cascada del retailer padre ya
|
|
124
|
+
* aplicada). El `zoneName` sale de la tabla de zonas del propio retail-org: el consumidor no
|
|
125
|
+
* puede resolver un `zoneId` de otro dominio, y hoy lo saca de un snapshot congelado en la venta,
|
|
126
|
+
* así que una tienda re-zonificada muestra la zona vieja.
|
|
127
|
+
*
|
|
128
|
+
* ── ⚠️ `status` SÍ tiene default, al revés que `listSellers` ─────────────────────────────────
|
|
129
|
+
* Omitirlo devuelve **solo las `ACTIVE`**. La asimetría es deliberada: allá un vendedor dado de
|
|
130
|
+
* baja el día 20 sí tiene comisión por lo que vendió hasta el 19, así que filtrar lo perdería.
|
|
131
|
+
* Acá el consumidor cruza este padrón con ventas que YA leyó, o sea que la tienda cerrada que
|
|
132
|
+
* vendió dentro de la ventana entra igual por el lado de las ventas — filtrar no puede perder
|
|
133
|
+
* una tienda que vendió, solo evita agregar un cero permanente a un tablero cuyo trabajo es que
|
|
134
|
+
* las filas en cero llamen la atención. Pasa `"ALL"` para el padrón completo.
|
|
135
|
+
*
|
|
136
|
+
* @throws `404 RETAILER_NOT_FOUND` si el retailer no existe en ese silo. Un `[]` no distinguiría
|
|
137
|
+
* "esta cadena no tiene tiendas" de "preguntaste por una cadena que no existe", y lo segundo
|
|
138
|
+
* dejaría el tablero mudo sin que nadie sospeche del request.
|
|
139
|
+
* @throws `400 STORE_STATUS_FILTER_INVALID` si `status` no es del catálogo · `400 UNKNOWN_TENANT`
|
|
140
|
+
* sin `tenantId`.
|
|
141
|
+
*/
|
|
142
|
+
listStoresByRetailer(
|
|
143
|
+
retailerId: string,
|
|
144
|
+
tenantId: string,
|
|
145
|
+
status?: StoreRosterStatusFilter,
|
|
146
|
+
): Promise<StandardResponse<StoreValidationDto[]>>;
|
|
147
|
+
|
|
99
148
|
/**
|
|
100
149
|
* GET /private/retailers/{retailerId}/users/by-store/{storeId} — usuarios retail cuya tienda base
|
|
101
150
|
* (`homeStoreId`) es esa. Devuelve `[]` (no 404) si la tienda no tiene usuarios asignados.
|