@fiado/api-invoker 5.142.0 → 5.144.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/platformRbac/api/PlatformRbacBusinessApi.d.ts +1 -1
- package/bin/platformRbac/api/PlatformRbacBusinessApi.js +1 -1
- package/bin/platformRbac/api/interfaces/IPlatformRbacBusinessApi.d.ts +1 -1
- package/bin/retailCatalog/api/RetailCatalogBusinessApi.d.ts +2 -2
- package/bin/retailCatalog/api/RetailCatalogBusinessApi.js +3 -1
- package/bin/retailCatalog/api/interfaces/IRetailCatalogBusinessApi.d.ts +8 -7
- package/bin/retailCustomer/api/RetailCustomerBusinessApi.js +4 -0
- package/bin/retailCustomer/api/dtos/CustomersPage.d.ts +4 -0
- package/bin/retailCustomer/api/interfaces/IRetailCustomerBusinessApi.d.ts +3 -2
- package/bin/retailIntegration/api/RetailIntegrationConnectorApi.d.ts +5 -1
- package/bin/retailIntegration/api/RetailIntegrationConnectorApi.js +33 -7
- package/bin/retailIntegration/api/interfaces/IRetailIntegrationConnectorApi.d.ts +5 -1
- package/bin/retailOrg/api/RetailOrgBusinessApi.d.ts +5 -3
- package/bin/retailOrg/api/RetailOrgBusinessApi.js +13 -6
- package/bin/retailOrg/api/interfaces/IRetailOrgBusinessApi.d.ts +17 -3
- package/bin/retailOrg/api/interfaces/IRetailOrgBusinessApi.js +4 -1
- package/package.json +2 -2
- package/src/platformRbac/api/PlatformRbacBusinessApi.ts +1 -1
- package/src/platformRbac/api/interfaces/IPlatformRbacBusinessApi.ts +1 -1
- package/src/retailCatalog/api/RetailCatalogBusinessApi.ts +5 -3
- package/src/retailCatalog/api/interfaces/IRetailCatalogBusinessApi.ts +7 -6
- package/src/retailCustomer/api/RetailCustomerBusinessApi.ts +2 -0
- package/src/retailCustomer/api/dtos/CustomersPage.ts +4 -0
- package/src/retailCustomer/api/interfaces/IRetailCustomerBusinessApi.ts +3 -2
- package/src/retailIntegration/api/RetailIntegrationConnectorApi.ts +53 -7
- package/src/retailIntegration/api/interfaces/IRetailIntegrationConnectorApi.ts +14 -0
- package/src/retailOrg/api/RetailOrgBusinessApi.ts +14 -4
- package/src/retailOrg/api/interfaces/IRetailOrgBusinessApi.ts +21 -1
|
@@ -39,7 +39,7 @@ export default class PlatformRbacBusinessApi implements IPlatformRbacBusinessApi
|
|
|
39
39
|
listLevelEntities(tenantId: string, level: PermissionScope, parentId?: string): Promise<APIGatewayProxyResultBody<ListLevelEntitiesResponse>>;
|
|
40
40
|
/** GET /internal/tenants/{tenantId}/levels/{level}/entities/{id} — detalle de un grupo. */
|
|
41
41
|
getLevelEntity(tenantId: string, level: PermissionScope, id: string): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
|
|
42
|
-
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo
|
|
42
|
+
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo o lo mueve de padre con `parentId`. */
|
|
43
43
|
updateLevelEntity(tenantId: string, level: PermissionScope, id: string, input: UpdateLevelEntityRequest): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
|
|
44
44
|
/** DELETE /internal/tenants/{tenantId}/levels/{level}/entities/{id} — borra un grupo. El `actedBy` viaja en el cuerpo. */
|
|
45
45
|
deleteLevelEntity(tenantId: string, level: PermissionScope, id: string, input: DeleteLevelEntityRequest): Promise<APIGatewayProxyResultBody<DeleteLevelEntityResponse>>;
|
|
@@ -111,7 +111,7 @@ let PlatformRbacBusinessApi = class PlatformRbacBusinessApi {
|
|
|
111
111
|
const url = `${this._levelEntitiesUrl(tenantId, level)}/${encodeURIComponent(id)}`;
|
|
112
112
|
return await this.httpRequest.get(url);
|
|
113
113
|
}
|
|
114
|
-
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo
|
|
114
|
+
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo o lo mueve de padre con `parentId`. */
|
|
115
115
|
async updateLevelEntity(tenantId, level, id, input) {
|
|
116
116
|
const url = `${this._levelEntitiesUrl(tenantId, level)}/${encodeURIComponent(id)}`;
|
|
117
117
|
return await this.httpRequest.put(url, input);
|
|
@@ -82,7 +82,7 @@ export interface IPlatformRbacBusinessApi {
|
|
|
82
82
|
listLevelEntities(tenantId: string, level: PermissionScope, parentId?: string): Promise<APIGatewayProxyResultBody<ListLevelEntitiesResponse>>;
|
|
83
83
|
/** GET /internal/tenants/{tenantId}/levels/{level}/entities/{id} — detalle de un grupo. */
|
|
84
84
|
getLevelEntity(tenantId: string, level: PermissionScope, id: string): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
|
|
85
|
-
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo
|
|
85
|
+
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo o lo mueve de padre con `parentId`. */
|
|
86
86
|
updateLevelEntity(tenantId: string, level: PermissionScope, id: string, input: UpdateLevelEntityRequest): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
|
|
87
87
|
/** DELETE /internal/tenants/{tenantId}/levels/{level}/entities/{id} — borra un grupo. El `actedBy` viaja en el cuerpo. */
|
|
88
88
|
deleteLevelEntity(tenantId: string, level: PermissionScope, id: string, input: DeleteLevelEntityRequest): Promise<APIGatewayProxyResultBody<DeleteLevelEntityResponse>>;
|
|
@@ -3,7 +3,7 @@ import { StandardResponse } from "@fiado/gateway-adapter";
|
|
|
3
3
|
import type { GetStoreStockCatalogResponse, HoldStockRequest, HoldStockResponse, InventoryLensQuery, InventoryLensResponse, ReleaseStockRequest, ReleaseStockResponse, RenewReservationsRequest, RenewReservationsResponse, ReserveStockRequest, ReserveStockResponse, ReturnStockRequest, ReturnStockResponse, SellStockRequest, SellStockResponse, SuggestPiecesQuery, SuggestPiecesResponse, SyncInventoryRequest, SyncInventoryResponse, ValidateProductResponse, StoreCatalogItem as StockCatalogItem } from "@fiado/type-kit/bin/retailCatalog/index.js";
|
|
4
4
|
import type { PaginatedResult } from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
5
5
|
import type { ApplyInventoryEventRequest, ApplyInventoryEventResponse, ApplyProductEventRequest, ApplyProductEventResponse } from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
6
|
-
import { IRetailCatalogBusinessApi, ProductsByRetailersResponse, ReleaseReservationBody, ReserveInventoryBody, ReserveInventoryResult,
|
|
6
|
+
import { IRetailCatalogBusinessApi, ProductsByRetailersResponse, ReleaseReservationBody, ReserveInventoryBody, ReserveInventoryResult, SellInventoryInput, StoreCatalogItem } from "./interfaces/IRetailCatalogBusinessApi.js";
|
|
7
7
|
/**
|
|
8
8
|
* Publisher HTTP del lambda `retail-catalog-business` (SureKeep Fase 1, pista Retail) para sus
|
|
9
9
|
* endpoints privados del ciclo de venta del IMEI. Contrato y semántica completos →
|
|
@@ -26,7 +26,7 @@ export default class RetailCatalogBusinessApi implements IRetailCatalogBusinessA
|
|
|
26
26
|
validateProduct(retailerId: string, sku: string, issuer: string): Promise<StandardResponse<ValidateProductResponse>>;
|
|
27
27
|
getProductsByRetailers(retailerIds: string[], tenantId: string): Promise<StandardResponse<ProductsByRetailersResponse>>;
|
|
28
28
|
reserveInventory(imei: string, body: ReserveInventoryBody, issuer: string): Promise<StandardResponse<ReserveInventoryResult>>;
|
|
29
|
-
sellInventory(imei: string, body:
|
|
29
|
+
sellInventory(imei: string, body: SellInventoryInput, issuer: string): Promise<StandardResponse<void>>;
|
|
30
30
|
releaseInventory(imei: string, body: ReleaseReservationBody, issuer: string): Promise<StandardResponse<void>>;
|
|
31
31
|
returnInventory(imei: string, issuer: string): Promise<StandardResponse<void>>;
|
|
32
32
|
/** URL de una ruta de tienda con `tenantId` y los parámetros extra en query. */
|
|
@@ -60,7 +60,9 @@ let RetailCatalogBusinessApi = class RetailCatalogBusinessApi {
|
|
|
60
60
|
}
|
|
61
61
|
async sellInventory(imei, body, issuer) {
|
|
62
62
|
const url = `${this.baseUrl}/private/inventory/${encodeURIComponent(imei)}/sell`;
|
|
63
|
-
|
|
63
|
+
const { saleId, ...rest } = body;
|
|
64
|
+
const payload = saleId === undefined ? rest : { ...rest, saleId };
|
|
65
|
+
return await this.httpRequest.put(url, payload, this.tenantHeader(issuer));
|
|
64
66
|
}
|
|
65
67
|
async releaseInventory(imei, body, issuer) {
|
|
66
68
|
const url = `${this.baseUrl}/private/inventory/${encodeURIComponent(imei)}/release`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
2
|
-
import type { GetStoreStockCatalogResponse, HoldStockRequest, HoldStockResponse, InventoryLensQuery, InventoryLensResponse, MdmLockModeEnum, MdmProviderEnum, ReleaseStockRequest, ReleaseStockResponse, RenewReservationsRequest, RenewReservationsResponse, ReserveStockRequest, ReserveStockResponse, ReturnStockRequest, ReturnStockResponse, SellStockRequest, SellStockResponse, SuggestPiecesQuery, SuggestPiecesResponse, SyncInventoryRequest, StoreCatalogItem as StockCatalogItem, SyncInventoryResponse, ValidateProductResponse } from "@fiado/type-kit/bin/retailCatalog/index.js";
|
|
2
|
+
import type { GetStoreStockCatalogResponse, HoldStockRequest, HoldStockResponse, InventoryLensQuery, InventoryLensResponse, MdmLockModeEnum, MdmProviderEnum, ReleaseStockRequest, ReleaseStockResponse, RenewReservationsRequest, RenewReservationsResponse, ReserveStockRequest, ReserveStockResponse, ReturnStockRequest, ReturnStockResponse, SellStockRequest, SellStockResponse, SellInventoryRequest, SuggestPiecesQuery, SuggestPiecesResponse, SyncInventoryRequest, StoreCatalogItem as StockCatalogItem, SyncInventoryResponse, ValidateProductResponse } from "@fiado/type-kit/bin/retailCatalog/index.js";
|
|
3
3
|
import type { PaginatedResult } from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
4
4
|
import type { ApplyInventoryEventRequest, ApplyInventoryEventResponse, ApplyProductEventRequest, ApplyProductEventResponse } from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
5
5
|
/**
|
|
@@ -93,11 +93,12 @@ export interface ReserveInventoryBody {
|
|
|
93
93
|
sku: string;
|
|
94
94
|
sessionId: string;
|
|
95
95
|
}
|
|
96
|
-
/** Body de PUT `/private/inventory/{imei}/sell` (
|
|
97
|
-
export
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
/** Body de PUT `/private/inventory/{imei}/sell`; `saleId` opcional mientras el wizard de main no lo mande (catalog lo exige en runtime). */
|
|
97
|
+
export type SellInventoryInput = Omit<SellInventoryRequest, 'saleId'> & {
|
|
98
|
+
saleId?: string;
|
|
99
|
+
};
|
|
100
|
+
/** Alias de `SellInventoryInput`; se conserva por compatibilidad con consumidores. */
|
|
101
|
+
export type SellInventoryBody = SellInventoryInput;
|
|
101
102
|
/** Body de PUT `/private/inventory/{imei}/release` (DEC-018 del destino: verifica titularidad de la sesión). */
|
|
102
103
|
export interface ReleaseReservationBody {
|
|
103
104
|
sessionId: string;
|
|
@@ -149,7 +150,7 @@ export interface IRetailCatalogBusinessApi {
|
|
|
149
150
|
/** PUT `/private/inventory/{imei}/reserve` — reserva atómica del IMEI para una sesión (AVAILABLE → RESERVED). */
|
|
150
151
|
reserveInventory(imei: string, body: ReserveInventoryBody, issuer: string): Promise<StandardResponse<ReserveInventoryResult>>;
|
|
151
152
|
/** PUT `/private/inventory/{imei}/sell` — vende el IMEI (RESERVED → SOLD). */
|
|
152
|
-
sellInventory(imei: string, body:
|
|
153
|
+
sellInventory(imei: string, body: SellInventoryInput, issuer: string): Promise<StandardResponse<void>>;
|
|
153
154
|
/** PUT `/private/inventory/{imei}/release` — libera la reserva (RESERVED → AVAILABLE, titularidad de la sesión). */
|
|
154
155
|
releaseInventory(imei: string, body: ReleaseReservationBody, issuer: string): Promise<StandardResponse<void>>;
|
|
155
156
|
/** PUT `/private/inventory/{imei}/return` — devuelve el IMEI vendido al stock (SOLD → AVAILABLE, sin body). */
|
|
@@ -72,6 +72,10 @@ let RetailCustomerBusinessApi = class RetailCustomerBusinessApi {
|
|
|
72
72
|
// El cursor viaja tal cual lo entregó el destino: componerlo o re-codificarlo lo rompe.
|
|
73
73
|
if (query.nextToken)
|
|
74
74
|
params.set("nextToken", query.nextToken);
|
|
75
|
+
if (query.retailerId)
|
|
76
|
+
params.set("retailerId", query.retailerId);
|
|
77
|
+
if (query.originStoreId)
|
|
78
|
+
params.set("originStoreId", query.originStoreId);
|
|
75
79
|
const url = `${this.baseUrl}/private/customers?${params.toString()}`;
|
|
76
80
|
return await this.httpRequest.get(url);
|
|
77
81
|
}
|
|
@@ -8,6 +8,10 @@ export interface CustomersPageQuery {
|
|
|
8
8
|
limit?: number;
|
|
9
9
|
/** Cursor opaco de la página anterior. Ausente = primera página. */
|
|
10
10
|
nextToken?: string;
|
|
11
|
+
/** Solo los clientes de esa cadena. */
|
|
12
|
+
retailerId?: string;
|
|
13
|
+
/** Solo los clientes dados de alta en esa tienda; va junto con `retailerId`. */
|
|
14
|
+
originStoreId?: string;
|
|
11
15
|
}
|
|
12
16
|
/**
|
|
13
17
|
* Lo mínimo para pintar el renglón de un cliente. `fullName: null` significa que el cliente existe
|
|
@@ -146,8 +146,9 @@ export interface IRetailCustomerBusinessApi {
|
|
|
146
146
|
*/
|
|
147
147
|
getCustomersBatch(payload: CustomersBatchRequest, tenantId: string): Promise<StandardResponse<CustomersBatchResponse>>;
|
|
148
148
|
/**
|
|
149
|
-
* GET /private/customers?limit&nextToken&tenantId= — UNA página del
|
|
150
|
-
* tenant, del alta más reciente a la más vieja.
|
|
149
|
+
* GET /private/customers?limit&nextToken&retailerId&originStoreId&tenantId= — UNA página del
|
|
150
|
+
* padrón de clientes del tenant, del alta más reciente a la más vieja. `retailerId` y
|
|
151
|
+
* `originStoreId` son filtros opcionales; sin ellos es el padrón completo del tenant. Es el listado que alimenta las tablas de
|
|
151
152
|
* backoffice: una sola Query sobre el GSI de listado, sin fan-out por negocio.
|
|
152
153
|
*
|
|
153
154
|
* `nextToken` es OPACO: se pasea tal cual, no se compone ni se re-codifica. Ausente en la
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { IHttpRequest } from "@fiado/http-client";
|
|
2
2
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
3
|
-
import type { GetRetailInventoryRequest, GetRetailInventoryResponse, ListRetailCatalogRequest, ListRetailCatalogResponse, ListRetailStoresRequest, ListRetailStoresResponse, ListRetailUsersRequest, ListRetailUsersResponse, RegisterRetailSaleRequest, RegisterRetailSaleResponse, RetailSystemSale } from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
3
|
+
import type { CancelRetailSaleRequest, CancelRetailSaleResponse, CheckRetailInventoryRequest, CheckRetailInventoryResponse, GetRetailInventoryRequest, GetRetailInventoryResponse, ListRetailCatalogRequest, ListRetailCatalogResponse, ListRetailStoresRequest, ListRetailStoresResponse, ListRetailUsersRequest, ListRetailUsersResponse, RegisterRetailSaleRequest, RegisterRetailSaleResponse, RetailSystemSale, RetailTenantQuery } from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
4
4
|
import { IRetailIntegrationConnectorApi } from "./interfaces/IRetailIntegrationConnectorApi.js";
|
|
5
5
|
/** Publisher de la salida privada de `retail-integration-connector`. */
|
|
6
6
|
export default class RetailIntegrationConnectorApi implements IRetailIntegrationConnectorApi {
|
|
@@ -12,6 +12,10 @@ export default class RetailIntegrationConnectorApi implements IRetailIntegration
|
|
|
12
12
|
getRetailInventory(request: GetRetailInventoryRequest): Promise<StandardResponse<GetRetailInventoryResponse>>;
|
|
13
13
|
listRetailUsers(request: ListRetailUsersRequest): Promise<StandardResponse<ListRetailUsersResponse>>;
|
|
14
14
|
registerRetailSale(request: RegisterRetailSaleRequest, sale: RetailSystemSale): Promise<StandardResponse<RegisterRetailSaleResponse>>;
|
|
15
|
+
cancelRetailSale(query: RetailTenantQuery, cancellation: CancelRetailSaleRequest): Promise<StandardResponse<CancelRetailSaleResponse>>;
|
|
16
|
+
checkRetailInventory(request: CheckRetailInventoryRequest): Promise<StandardResponse<CheckRetailInventoryResponse>>;
|
|
15
17
|
private getWithTimeout;
|
|
18
|
+
private tenantQuery;
|
|
19
|
+
private listQuery;
|
|
16
20
|
private toQuery;
|
|
17
21
|
}
|
|
@@ -13,6 +13,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
|
13
13
|
import { inject, injectable } from "inversify";
|
|
14
14
|
/** Mayor que el Timeout de 10 s del connector, para no cortar una venta en vuelo. */
|
|
15
15
|
const RETAIL_INTEGRATION_CONNECTOR_TIMEOUT_MS = 12000;
|
|
16
|
+
/** Mayor que los 2.5 s del connector hacia el retailer; la consulta en vivo no debe frenar la venta. */
|
|
17
|
+
const RETAIL_LIVE_CHECK_TIMEOUT_MS = 3000;
|
|
16
18
|
/** Publisher de la salida privada de `retail-integration-connector`. */
|
|
17
19
|
let RetailIntegrationConnectorApi = class RetailIntegrationConnectorApi {
|
|
18
20
|
httpRequest;
|
|
@@ -22,42 +24,66 @@ let RetailIntegrationConnectorApi = class RetailIntegrationConnectorApi {
|
|
|
22
24
|
}
|
|
23
25
|
async listRetailStores(request) {
|
|
24
26
|
return await this.getWithTimeout("/private/retail/stores", {
|
|
25
|
-
|
|
27
|
+
...this.listQuery(request),
|
|
26
28
|
limit: request.limit,
|
|
27
29
|
nextToken: request.nextToken,
|
|
28
30
|
});
|
|
29
31
|
}
|
|
30
32
|
async listRetailCatalog(request) {
|
|
31
33
|
return await this.getWithTimeout("/private/retail/catalog", {
|
|
32
|
-
|
|
34
|
+
...this.listQuery(request),
|
|
33
35
|
limit: request.limit,
|
|
34
36
|
nextToken: request.nextToken,
|
|
35
37
|
});
|
|
36
38
|
}
|
|
37
39
|
async getRetailInventory(request) {
|
|
38
40
|
return await this.getWithTimeout("/private/retail/inventory", {
|
|
39
|
-
|
|
41
|
+
...this.tenantQuery(request),
|
|
40
42
|
storeId: request.storeId,
|
|
43
|
+
runId: request.runId,
|
|
41
44
|
});
|
|
42
45
|
}
|
|
43
46
|
async listRetailUsers(request) {
|
|
44
47
|
return await this.getWithTimeout("/private/retail/users", {
|
|
45
|
-
|
|
48
|
+
...this.tenantQuery(request),
|
|
46
49
|
storeId: request.storeId,
|
|
50
|
+
runId: request.runId,
|
|
47
51
|
limit: request.limit,
|
|
48
52
|
nextToken: request.nextToken,
|
|
49
53
|
});
|
|
50
54
|
}
|
|
51
55
|
async registerRetailSale(request, sale) {
|
|
52
|
-
const url = `${this.baseUrl}/private/retail/sales?${this.toQuery(
|
|
56
|
+
const url = `${this.baseUrl}/private/retail/sales?${this.toQuery(this.tenantQuery(request))}`;
|
|
53
57
|
return await this.httpRequest.post(url, sale, {}, undefined, false, {
|
|
54
58
|
timeout: RETAIL_INTEGRATION_CONNECTOR_TIMEOUT_MS,
|
|
55
59
|
});
|
|
56
60
|
}
|
|
61
|
+
async cancelRetailSale(query, cancellation) {
|
|
62
|
+
const url = `${this.baseUrl}/private/retail/sales/cancel?${this.toQuery(this.tenantQuery(query))}`;
|
|
63
|
+
return await this.httpRequest.post(url, cancellation, {}, undefined, false, {
|
|
64
|
+
timeout: RETAIL_INTEGRATION_CONNECTOR_TIMEOUT_MS,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
async checkRetailInventory(request) {
|
|
68
|
+
const fields = {
|
|
69
|
+
...this.tenantQuery(request),
|
|
70
|
+
storeId: request.storeId,
|
|
71
|
+
identifiers: request.identifiers.join(","),
|
|
72
|
+
sessionId: request.sessionId,
|
|
73
|
+
};
|
|
74
|
+
return await this.getWithTimeout("/private/retail/inventory/live-check", fields, RETAIL_LIVE_CHECK_TIMEOUT_MS);
|
|
75
|
+
}
|
|
57
76
|
// GET con timeout propio; nunca `enableTimeout`, que tomaría el timeout corto del consumidor.
|
|
58
|
-
async getWithTimeout(path, fields) {
|
|
77
|
+
async getWithTimeout(path, fields, timeout = RETAIL_INTEGRATION_CONNECTOR_TIMEOUT_MS) {
|
|
59
78
|
const url = `${this.baseUrl}${path}?${this.toQuery(fields)}`;
|
|
60
|
-
return await this.httpRequest.get(url, {}, {}, undefined, { timeout
|
|
79
|
+
return await this.httpRequest.get(url, {}, {}, undefined, { timeout }, false);
|
|
80
|
+
}
|
|
81
|
+
// El connector coteja tenantId y retailerId contra el secreto del tenant.
|
|
82
|
+
tenantQuery(query) {
|
|
83
|
+
return { tenantId: query.tenantId, retailerId: query.retailerId };
|
|
84
|
+
}
|
|
85
|
+
listQuery(query) {
|
|
86
|
+
return { ...this.tenantQuery(query), runId: query.runId };
|
|
61
87
|
}
|
|
62
88
|
toQuery(fields) {
|
|
63
89
|
const params = new URLSearchParams();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
2
|
-
import type { GetRetailInventoryRequest, GetRetailInventoryResponse, ListRetailCatalogRequest, ListRetailCatalogResponse, ListRetailStoresRequest, ListRetailStoresResponse, ListRetailUsersRequest, ListRetailUsersResponse, RegisterRetailSaleRequest, RegisterRetailSaleResponse, RetailSystemSale } from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
2
|
+
import type { CancelRetailSaleRequest, CancelRetailSaleResponse, CheckRetailInventoryRequest, CheckRetailInventoryResponse, GetRetailInventoryRequest, GetRetailInventoryResponse, ListRetailCatalogRequest, ListRetailCatalogResponse, ListRetailStoresRequest, ListRetailStoresResponse, ListRetailUsersRequest, ListRetailUsersResponse, RegisterRetailSaleRequest, RegisterRetailSaleResponse, RetailSystemSale, RetailTenantQuery } from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
3
3
|
/**
|
|
4
4
|
* Salida privada de `retail-integration-connector` hacia el sistema del retailer del tenant.
|
|
5
5
|
* Env var del consumidor: `RETAIL_INTEGRATION_CONNECTOR_URL: '{{resolve:ssm:retail-integration-connector}}'`.
|
|
@@ -15,4 +15,8 @@ export interface IRetailIntegrationConnectorApi {
|
|
|
15
15
|
listRetailUsers(request: ListRetailUsersRequest): Promise<StandardResponse<ListRetailUsersResponse>>;
|
|
16
16
|
/** `POST /private/retail/sales` — registra la venta; ante timeout o 502, reintenta con el mismo `saleId`. */
|
|
17
17
|
registerRetailSale(request: RegisterRetailSaleRequest, sale: RetailSystemSale): Promise<StandardResponse<RegisterRetailSaleResponse>>;
|
|
18
|
+
/** `POST /private/retail/sales/cancel` — cancela la venta con el mismo `saleId` del registro; 12 s. */
|
|
19
|
+
cancelRetailSale(query: RetailTenantQuery, cancellation: CancelRetailSaleRequest): Promise<StandardResponse<CancelRetailSaleResponse>>;
|
|
20
|
+
/** `GET /private/retail/inventory/live-check` — qué identificadores lista hoy la tienda; 3 s. */
|
|
21
|
+
checkRetailInventory(request: CheckRetailInventoryRequest): Promise<StandardResponse<CheckRetailInventoryResponse>>;
|
|
18
22
|
}
|
|
@@ -2,7 +2,7 @@ import type { IHttpRequest } from "@fiado/http-client";
|
|
|
2
2
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
3
3
|
import { RetailerValidationDto, StoreValidationDto, RetailUserValidationDto, CollectorValidationDto, PrivateSellerListResponse, PrivateGoalListResponse, GoalTargetTypeEnum, RetailUserStatusEnum, PrivateRetailUserWalletResponse } from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
4
4
|
import type { ApplyRetailUserEventRequest, ApplyRetailUserEventResponse, ApplyStoreEventRequest, ApplyStoreEventResponse } from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
5
|
-
import { IRetailOrgBusinessApi, RetailerRosterStatusFilter, StoreRosterStatusFilter } from "./interfaces/IRetailOrgBusinessApi.js";
|
|
5
|
+
import { IRetailOrgBusinessApi, RetailOrgRequestOptions, RetailerRosterStatusFilter, StoreRosterStatusFilter } from "./interfaces/IRetailOrgBusinessApi.js";
|
|
6
6
|
/**
|
|
7
7
|
* Publisher HTTP del lambda `retail-org-business` (componente 04 SureKeep Fase 1) para sus 9
|
|
8
8
|
* endpoints privados de validación. Contrato y semántica completos → `IRetailOrgBusinessApi`.
|
|
@@ -27,8 +27,10 @@ export default class RetailOrgBusinessApi implements IRetailOrgBusinessApi {
|
|
|
27
27
|
* qué `status` SÍ tiene default y por qué acá el estado es el CRUDO, sin cascada del padre)
|
|
28
28
|
* → `IRetailOrgBusinessApi.listRetailers`.
|
|
29
29
|
*/
|
|
30
|
-
listRetailers(tenantId: string, status?: RetailerRosterStatusFilter): Promise<StandardResponse<RetailerValidationDto[]>>;
|
|
31
|
-
getRetailer(retailerId: string, tenantId: string): Promise<StandardResponse<RetailerValidationDto>>;
|
|
30
|
+
listRetailers(tenantId: string, status?: RetailerRosterStatusFilter, integrated?: boolean, options?: RetailOrgRequestOptions): Promise<StandardResponse<RetailerValidationDto[]>>;
|
|
31
|
+
getRetailer(retailerId: string, tenantId: string, options?: RetailOrgRequestOptions): Promise<StandardResponse<RetailerValidationDto>>;
|
|
32
|
+
/** Aplica el timeout solo si el caller lo pide; sin él, el GET queda igual que siempre. */
|
|
33
|
+
private getWithOptionalTimeout;
|
|
32
34
|
getRetailerByStore(storeId: string, tenantId: string): Promise<StandardResponse<RetailerValidationDto>>;
|
|
33
35
|
getStore(retailerId: string, storeId: string, tenantId: string): Promise<StandardResponse<StoreValidationDto>>;
|
|
34
36
|
/**
|
|
@@ -37,17 +37,24 @@ let RetailOrgBusinessApi = class RetailOrgBusinessApi {
|
|
|
37
37
|
* qué `status` SÍ tiene default y por qué acá el estado es el CRUDO, sin cascada del padre)
|
|
38
38
|
* → `IRetailOrgBusinessApi.listRetailers`.
|
|
39
39
|
*/
|
|
40
|
-
async listRetailers(tenantId, status) {
|
|
41
|
-
// `URLSearchParams` en vez de concatenar: `status` es opcional y armar el `&status=` a mano
|
|
42
|
-
// deja un `&status=undefined` en cuanto alguien se distrae.
|
|
40
|
+
async listRetailers(tenantId, status, integrated, options) {
|
|
43
41
|
const query = new URLSearchParams({ tenantId });
|
|
44
42
|
if (status)
|
|
45
43
|
query.set("status", status);
|
|
46
|
-
|
|
44
|
+
if (integrated !== undefined)
|
|
45
|
+
query.set("integrated", String(integrated));
|
|
46
|
+
const url = `${this.baseUrl}/private/retailers?${query.toString()}`;
|
|
47
|
+
return await this.getWithOptionalTimeout(url, options);
|
|
47
48
|
}
|
|
48
|
-
async getRetailer(retailerId, tenantId) {
|
|
49
|
+
async getRetailer(retailerId, tenantId, options) {
|
|
49
50
|
const url = `${this.baseUrl}/private/retailers/${encodeURIComponent(retailerId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
50
|
-
return await this.
|
|
51
|
+
return await this.getWithOptionalTimeout(url, options);
|
|
52
|
+
}
|
|
53
|
+
/** Aplica el timeout solo si el caller lo pide; sin él, el GET queda igual que siempre. */
|
|
54
|
+
async getWithOptionalTimeout(url, options) {
|
|
55
|
+
if (options?.timeoutMs === undefined)
|
|
56
|
+
return await this.httpRequest.get(url);
|
|
57
|
+
return await this.httpRequest.get(url, undefined, undefined, undefined, { timeout: options.timeoutMs });
|
|
51
58
|
}
|
|
52
59
|
async getRetailerByStore(storeId, tenantId) {
|
|
53
60
|
const url = `${this.baseUrl}/private/retailers/by-store/${encodeURIComponent(storeId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
2
2
|
import { RetailerValidationDto, StoreValidationDto, RetailUserValidationDto, CollectorValidationDto, PrivateSellerListResponse, PrivateGoalListResponse, GoalTargetTypeEnum, RetailUserStatusEnum, RetailerStatusEnum, StoreStatusEnum, PrivateRetailUserWalletResponse } from "@fiado/type-kit/bin/retailOrg/index.js";
|
|
3
3
|
import type { ApplyRetailUserEventRequest, ApplyRetailUserEventResponse, ApplyStoreEventRequest, ApplyStoreEventResponse } from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
4
|
+
/** Timeout que el connector y el wizard pasan a `getRetailer`: cabe en los 3 s por evento del connector. */
|
|
5
|
+
export declare const RETAIL_ORG_GET_RETAILER_TIMEOUT_MS = 1500;
|
|
6
|
+
/** Timeout que el connector pasa a `listRetailers`: el padrón trae el árbol completo del silo. */
|
|
7
|
+
export declare const RETAIL_ORG_LIST_RETAILERS_TIMEOUT_MS = 5000;
|
|
8
|
+
/** Opciones por llamada. Sin `timeoutMs` no se aplica timeout propio. */
|
|
9
|
+
export interface RetailOrgRequestOptions {
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
}
|
|
4
12
|
/**
|
|
5
13
|
* Filtro de `listStoresByRetailer`. `"ALL"` no es un estado de tienda: es la ausencia de filtro, y
|
|
6
14
|
* va en el MISMO parámetro que los estados porque los dos hablan del mismo eje — un segundo flag
|
|
@@ -87,17 +95,23 @@ export interface IRetailOrgBusinessApi {
|
|
|
87
95
|
* Devuelve `[]` si ningún retailer pasa el filtro. **No hay 404**: el silo siempre existe — lo
|
|
88
96
|
* garantiza el `tenantId`, que es lo que resolvió el contexto del tenant.
|
|
89
97
|
*
|
|
98
|
+
* `integrated = true` deja solo los retailers con la bandera de integración prendida; cada
|
|
99
|
+
* retailer trae `integrationSystem` e `integrationActivatedAt` cuando la tiene. Timeout opt-in vía
|
|
100
|
+
* `options.timeoutMs` (ver `RETAIL_ORG_LIST_RETAILERS_TIMEOUT_MS`).
|
|
101
|
+
*
|
|
90
102
|
* @throws `400 RETAILER_STATUS_FILTER_INVALID` si `status` no es del catálogo ·
|
|
91
103
|
* `400 UNKNOWN_TENANT` sin `tenantId`.
|
|
92
104
|
*/
|
|
93
|
-
listRetailers(tenantId: string, status?: RetailerRosterStatusFilter): Promise<StandardResponse<RetailerValidationDto[]>>;
|
|
105
|
+
listRetailers(tenantId: string, status?: RetailerRosterStatusFilter, integrated?: boolean, options?: RetailOrgRequestOptions): Promise<StandardResponse<RetailerValidationDto[]>>;
|
|
94
106
|
/**
|
|
95
107
|
* GET /private/retailers/{retailerId} — valida que el retailer exista y devuelve su shape mínimo
|
|
96
|
-
* (id, name, type, status, parentId). `status` ya viene con la cascada
|
|
108
|
+
* (id, name, type, status, parentId) y la bandera de integración. `status` ya viene con la cascada
|
|
109
|
+
* aplicada (estado efectivo). Timeout opt-in vía `options.timeoutMs` (ver
|
|
110
|
+
* `RETAIL_ORG_GET_RETAILER_TIMEOUT_MS`).
|
|
97
111
|
*
|
|
98
112
|
* @throws si el retailer no existe (`404 RETAILER_NOT_FOUND`).
|
|
99
113
|
*/
|
|
100
|
-
getRetailer(retailerId: string, tenantId: string): Promise<StandardResponse<RetailerValidationDto>>;
|
|
114
|
+
getRetailer(retailerId: string, tenantId: string, options?: RetailOrgRequestOptions): Promise<StandardResponse<RetailerValidationDto>>;
|
|
101
115
|
/**
|
|
102
116
|
* GET /private/retailers/by-store/{storeId} — resuelve el retailer DUEÑO de una tienda teniendo
|
|
103
117
|
* SOLO el `storeId`, sin conocer el retailer. Es el único privado que no va anidado, porque es el
|
|
@@ -1 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
/** Timeout que el connector y el wizard pasan a `getRetailer`: cabe en los 3 s por evento del connector. */
|
|
2
|
+
export const RETAIL_ORG_GET_RETAILER_TIMEOUT_MS = 1500;
|
|
3
|
+
/** Timeout que el connector pasa a `listRetailers`: el padrón trae el árbol completo del silo. */
|
|
4
|
+
export const RETAIL_ORG_LIST_RETAILERS_TIMEOUT_MS = 5000;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fiado/api-invoker",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.144.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.14.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.579.0",
|
|
38
38
|
"dotenv": "^16.4.7"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
@@ -204,7 +204,7 @@ export default class PlatformRbacBusinessApi implements IPlatformRbacBusinessApi
|
|
|
204
204
|
return await this.httpRequest.get(url);
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo
|
|
207
|
+
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo o lo mueve de padre con `parentId`. */
|
|
208
208
|
async updateLevelEntity(
|
|
209
209
|
tenantId: string,
|
|
210
210
|
level: PermissionScope,
|
|
@@ -174,7 +174,7 @@ export interface IPlatformRbacBusinessApi {
|
|
|
174
174
|
id: string,
|
|
175
175
|
): Promise<APIGatewayProxyResultBody<LevelEntityResponse>>;
|
|
176
176
|
|
|
177
|
-
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo
|
|
177
|
+
/** PUT /internal/tenants/{tenantId}/levels/{level}/entities/{id} — renombra un grupo o lo mueve de padre con `parentId`. */
|
|
178
178
|
updateLevelEntity(
|
|
179
179
|
tenantId: string,
|
|
180
180
|
level: PermissionScope,
|
|
@@ -41,7 +41,7 @@ import {
|
|
|
41
41
|
ReserveInventoryBody,
|
|
42
42
|
ReserveInventoryResult,
|
|
43
43
|
RETAILER_PRODUCTS_BATCH_MAX,
|
|
44
|
-
|
|
44
|
+
SellInventoryInput,
|
|
45
45
|
StoreCatalogItem,
|
|
46
46
|
} from "./interfaces/IRetailCatalogBusinessApi.js";
|
|
47
47
|
|
|
@@ -114,9 +114,11 @@ export default class RetailCatalogBusinessApi implements IRetailCatalogBusinessA
|
|
|
114
114
|
return await this.httpRequest.put(url, body, this.tenantHeader(issuer));
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
async sellInventory(imei: string, body:
|
|
117
|
+
async sellInventory(imei: string, body: SellInventoryInput, issuer: string): Promise<StandardResponse<void>> {
|
|
118
118
|
const url = `${this.baseUrl}/private/inventory/${encodeURIComponent(imei)}/sell`;
|
|
119
|
-
|
|
119
|
+
const { saleId, ...rest } = body;
|
|
120
|
+
const payload = saleId === undefined ? rest : { ...rest, saleId };
|
|
121
|
+
return await this.httpRequest.put(url, payload, this.tenantHeader(issuer));
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
async releaseInventory(imei: string, body: ReleaseReservationBody, issuer: string): Promise<StandardResponse<void>> {
|
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
ReturnStockResponse,
|
|
18
18
|
SellStockRequest,
|
|
19
19
|
SellStockResponse,
|
|
20
|
+
SellInventoryRequest,
|
|
20
21
|
SuggestPiecesQuery,
|
|
21
22
|
SuggestPiecesResponse,
|
|
22
23
|
SyncInventoryRequest,
|
|
@@ -137,11 +138,11 @@ export interface ReserveInventoryBody {
|
|
|
137
138
|
sessionId: string;
|
|
138
139
|
}
|
|
139
140
|
|
|
140
|
-
/** Body de PUT `/private/inventory/{imei}/sell` (
|
|
141
|
-
export
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
141
|
+
/** Body de PUT `/private/inventory/{imei}/sell`; `saleId` opcional mientras el wizard de main no lo mande (catalog lo exige en runtime). */
|
|
142
|
+
export type SellInventoryInput = Omit<SellInventoryRequest, 'saleId'> & { saleId?: string };
|
|
143
|
+
|
|
144
|
+
/** Alias de `SellInventoryInput`; se conserva por compatibilidad con consumidores. */
|
|
145
|
+
export type SellInventoryBody = SellInventoryInput;
|
|
145
146
|
|
|
146
147
|
/** Body de PUT `/private/inventory/{imei}/release` (DEC-018 del destino: verifica titularidad de la sesión). */
|
|
147
148
|
export interface ReleaseReservationBody {
|
|
@@ -206,7 +207,7 @@ export interface IRetailCatalogBusinessApi {
|
|
|
206
207
|
reserveInventory(imei: string, body: ReserveInventoryBody, issuer: string): Promise<StandardResponse<ReserveInventoryResult>>;
|
|
207
208
|
|
|
208
209
|
/** PUT `/private/inventory/{imei}/sell` — vende el IMEI (RESERVED → SOLD). */
|
|
209
|
-
sellInventory(imei: string, body:
|
|
210
|
+
sellInventory(imei: string, body: SellInventoryInput, issuer: string): Promise<StandardResponse<void>>;
|
|
210
211
|
|
|
211
212
|
/** PUT `/private/inventory/{imei}/release` — libera la reserva (RESERVED → AVAILABLE, titularidad de la sesión). */
|
|
212
213
|
releaseInventory(imei: string, body: ReleaseReservationBody, issuer: string): Promise<StandardResponse<void>>;
|
|
@@ -124,6 +124,8 @@ export default class RetailCustomerBusinessApi implements IRetailCustomerBusines
|
|
|
124
124
|
if (query.limit !== undefined) params.set("limit", String(query.limit));
|
|
125
125
|
// El cursor viaja tal cual lo entregó el destino: componerlo o re-codificarlo lo rompe.
|
|
126
126
|
if (query.nextToken) params.set("nextToken", query.nextToken);
|
|
127
|
+
if (query.retailerId) params.set("retailerId", query.retailerId);
|
|
128
|
+
if (query.originStoreId) params.set("originStoreId", query.originStoreId);
|
|
127
129
|
const url = `${this.baseUrl}/private/customers?${params.toString()}`;
|
|
128
130
|
return await this.httpRequest.get(url);
|
|
129
131
|
}
|
|
@@ -9,6 +9,10 @@ export interface CustomersPageQuery {
|
|
|
9
9
|
limit?: number;
|
|
10
10
|
/** Cursor opaco de la página anterior. Ausente = primera página. */
|
|
11
11
|
nextToken?: string;
|
|
12
|
+
/** Solo los clientes de esa cadena. */
|
|
13
|
+
retailerId?: string;
|
|
14
|
+
/** Solo los clientes dados de alta en esa tienda; va junto con `retailerId`. */
|
|
15
|
+
originStoreId?: string;
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
/**
|
|
@@ -202,8 +202,9 @@ export interface IRetailCustomerBusinessApi {
|
|
|
202
202
|
): Promise<StandardResponse<CustomersBatchResponse>>;
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
|
-
* GET /private/customers?limit&nextToken&tenantId= — UNA página del
|
|
206
|
-
* tenant, del alta más reciente a la más vieja.
|
|
205
|
+
* GET /private/customers?limit&nextToken&retailerId&originStoreId&tenantId= — UNA página del
|
|
206
|
+
* padrón de clientes del tenant, del alta más reciente a la más vieja. `retailerId` y
|
|
207
|
+
* `originStoreId` son filtros opcionales; sin ellos es el padrón completo del tenant. Es el listado que alimenta las tablas de
|
|
207
208
|
* backoffice: una sola Query sobre el GSI de listado, sin fan-out por negocio.
|
|
208
209
|
*
|
|
209
210
|
* `nextToken` es OPACO: se pasea tal cual, no se compone ni se re-codifica. Ausente en la
|
|
@@ -2,6 +2,10 @@ import { inject, injectable } from "inversify";
|
|
|
2
2
|
import type { IHttpRequest } from "@fiado/http-client";
|
|
3
3
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
4
4
|
import type {
|
|
5
|
+
CancelRetailSaleRequest,
|
|
6
|
+
CancelRetailSaleResponse,
|
|
7
|
+
CheckRetailInventoryRequest,
|
|
8
|
+
CheckRetailInventoryResponse,
|
|
5
9
|
GetRetailInventoryRequest,
|
|
6
10
|
GetRetailInventoryResponse,
|
|
7
11
|
ListRetailCatalogRequest,
|
|
@@ -12,13 +16,18 @@ import type {
|
|
|
12
16
|
ListRetailUsersResponse,
|
|
13
17
|
RegisterRetailSaleRequest,
|
|
14
18
|
RegisterRetailSaleResponse,
|
|
19
|
+
RetailListQuery,
|
|
15
20
|
RetailSystemSale,
|
|
21
|
+
RetailTenantQuery,
|
|
16
22
|
} from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
17
23
|
import { IRetailIntegrationConnectorApi } from "./interfaces/IRetailIntegrationConnectorApi.js";
|
|
18
24
|
|
|
19
25
|
/** Mayor que el Timeout de 10 s del connector, para no cortar una venta en vuelo. */
|
|
20
26
|
const RETAIL_INTEGRATION_CONNECTOR_TIMEOUT_MS = 12000;
|
|
21
27
|
|
|
28
|
+
/** Mayor que los 2.5 s del connector hacia el retailer; la consulta en vivo no debe frenar la venta. */
|
|
29
|
+
const RETAIL_LIVE_CHECK_TIMEOUT_MS = 3000;
|
|
30
|
+
|
|
22
31
|
type QueryFields = Record<string, string | number | undefined>;
|
|
23
32
|
|
|
24
33
|
/** Publisher de la salida privada de `retail-integration-connector`. */
|
|
@@ -30,7 +39,7 @@ export default class RetailIntegrationConnectorApi implements IRetailIntegration
|
|
|
30
39
|
|
|
31
40
|
async listRetailStores(request: ListRetailStoresRequest): Promise<StandardResponse<ListRetailStoresResponse>> {
|
|
32
41
|
return await this.getWithTimeout("/private/retail/stores", {
|
|
33
|
-
|
|
42
|
+
...this.listQuery(request),
|
|
34
43
|
limit: request.limit,
|
|
35
44
|
nextToken: request.nextToken,
|
|
36
45
|
});
|
|
@@ -38,7 +47,7 @@ export default class RetailIntegrationConnectorApi implements IRetailIntegration
|
|
|
38
47
|
|
|
39
48
|
async listRetailCatalog(request: ListRetailCatalogRequest): Promise<StandardResponse<ListRetailCatalogResponse>> {
|
|
40
49
|
return await this.getWithTimeout("/private/retail/catalog", {
|
|
41
|
-
|
|
50
|
+
...this.listQuery(request),
|
|
42
51
|
limit: request.limit,
|
|
43
52
|
nextToken: request.nextToken,
|
|
44
53
|
});
|
|
@@ -46,15 +55,17 @@ export default class RetailIntegrationConnectorApi implements IRetailIntegration
|
|
|
46
55
|
|
|
47
56
|
async getRetailInventory(request: GetRetailInventoryRequest): Promise<StandardResponse<GetRetailInventoryResponse>> {
|
|
48
57
|
return await this.getWithTimeout("/private/retail/inventory", {
|
|
49
|
-
|
|
58
|
+
...this.tenantQuery(request),
|
|
50
59
|
storeId: request.storeId,
|
|
60
|
+
runId: request.runId,
|
|
51
61
|
});
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
async listRetailUsers(request: ListRetailUsersRequest): Promise<StandardResponse<ListRetailUsersResponse>> {
|
|
55
65
|
return await this.getWithTimeout("/private/retail/users", {
|
|
56
|
-
|
|
66
|
+
...this.tenantQuery(request),
|
|
57
67
|
storeId: request.storeId,
|
|
68
|
+
runId: request.runId,
|
|
58
69
|
limit: request.limit,
|
|
59
70
|
nextToken: request.nextToken,
|
|
60
71
|
});
|
|
@@ -64,16 +75,51 @@ export default class RetailIntegrationConnectorApi implements IRetailIntegration
|
|
|
64
75
|
request: RegisterRetailSaleRequest,
|
|
65
76
|
sale: RetailSystemSale,
|
|
66
77
|
): Promise<StandardResponse<RegisterRetailSaleResponse>> {
|
|
67
|
-
const url = `${this.baseUrl}/private/retail/sales?${this.toQuery(
|
|
78
|
+
const url = `${this.baseUrl}/private/retail/sales?${this.toQuery(this.tenantQuery(request))}`;
|
|
68
79
|
return await this.httpRequest.post(url, sale, {}, undefined, false, {
|
|
69
80
|
timeout: RETAIL_INTEGRATION_CONNECTOR_TIMEOUT_MS,
|
|
70
81
|
});
|
|
71
82
|
}
|
|
72
83
|
|
|
84
|
+
async cancelRetailSale(
|
|
85
|
+
query: RetailTenantQuery,
|
|
86
|
+
cancellation: CancelRetailSaleRequest,
|
|
87
|
+
): Promise<StandardResponse<CancelRetailSaleResponse>> {
|
|
88
|
+
const url = `${this.baseUrl}/private/retail/sales/cancel?${this.toQuery(this.tenantQuery(query))}`;
|
|
89
|
+
return await this.httpRequest.post(url, cancellation, {}, undefined, false, {
|
|
90
|
+
timeout: RETAIL_INTEGRATION_CONNECTOR_TIMEOUT_MS,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async checkRetailInventory(
|
|
95
|
+
request: CheckRetailInventoryRequest,
|
|
96
|
+
): Promise<StandardResponse<CheckRetailInventoryResponse>> {
|
|
97
|
+
const fields = {
|
|
98
|
+
...this.tenantQuery(request),
|
|
99
|
+
storeId: request.storeId,
|
|
100
|
+
identifiers: request.identifiers.join(","),
|
|
101
|
+
sessionId: request.sessionId,
|
|
102
|
+
};
|
|
103
|
+
return await this.getWithTimeout("/private/retail/inventory/live-check", fields, RETAIL_LIVE_CHECK_TIMEOUT_MS);
|
|
104
|
+
}
|
|
105
|
+
|
|
73
106
|
// GET con timeout propio; nunca `enableTimeout`, que tomaría el timeout corto del consumidor.
|
|
74
|
-
private async getWithTimeout<T>(
|
|
107
|
+
private async getWithTimeout<T>(
|
|
108
|
+
path: string,
|
|
109
|
+
fields: QueryFields,
|
|
110
|
+
timeout = RETAIL_INTEGRATION_CONNECTOR_TIMEOUT_MS,
|
|
111
|
+
): Promise<StandardResponse<T>> {
|
|
75
112
|
const url = `${this.baseUrl}${path}?${this.toQuery(fields)}`;
|
|
76
|
-
return await this.httpRequest.get(url, {}, {}, undefined, { timeout
|
|
113
|
+
return await this.httpRequest.get(url, {}, {}, undefined, { timeout }, false);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// El connector coteja tenantId y retailerId contra el secreto del tenant.
|
|
117
|
+
private tenantQuery(query: RetailTenantQuery): QueryFields {
|
|
118
|
+
return { tenantId: query.tenantId, retailerId: query.retailerId };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private listQuery(query: RetailListQuery): QueryFields {
|
|
122
|
+
return { ...this.tenantQuery(query), runId: query.runId };
|
|
77
123
|
}
|
|
78
124
|
|
|
79
125
|
private toQuery(fields: QueryFields): string {
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { StandardResponse } from "@fiado/gateway-adapter";
|
|
2
2
|
import type {
|
|
3
|
+
CancelRetailSaleRequest,
|
|
4
|
+
CancelRetailSaleResponse,
|
|
5
|
+
CheckRetailInventoryRequest,
|
|
6
|
+
CheckRetailInventoryResponse,
|
|
3
7
|
GetRetailInventoryRequest,
|
|
4
8
|
GetRetailInventoryResponse,
|
|
5
9
|
ListRetailCatalogRequest,
|
|
@@ -11,6 +15,7 @@ import type {
|
|
|
11
15
|
RegisterRetailSaleRequest,
|
|
12
16
|
RegisterRetailSaleResponse,
|
|
13
17
|
RetailSystemSale,
|
|
18
|
+
RetailTenantQuery,
|
|
14
19
|
} from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
15
20
|
|
|
16
21
|
/**
|
|
@@ -35,4 +40,13 @@ export interface IRetailIntegrationConnectorApi {
|
|
|
35
40
|
request: RegisterRetailSaleRequest,
|
|
36
41
|
sale: RetailSystemSale,
|
|
37
42
|
): Promise<StandardResponse<RegisterRetailSaleResponse>>;
|
|
43
|
+
|
|
44
|
+
/** `POST /private/retail/sales/cancel` — cancela la venta con el mismo `saleId` del registro; 12 s. */
|
|
45
|
+
cancelRetailSale(
|
|
46
|
+
query: RetailTenantQuery,
|
|
47
|
+
cancellation: CancelRetailSaleRequest,
|
|
48
|
+
): Promise<StandardResponse<CancelRetailSaleResponse>>;
|
|
49
|
+
|
|
50
|
+
/** `GET /private/retail/inventory/live-check` — qué identificadores lista hoy la tienda; 3 s. */
|
|
51
|
+
checkRetailInventory(request: CheckRetailInventoryRequest): Promise<StandardResponse<CheckRetailInventoryResponse>>;
|
|
38
52
|
}
|
|
@@ -22,6 +22,7 @@ import type {
|
|
|
22
22
|
} from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
23
23
|
import {
|
|
24
24
|
IRetailOrgBusinessApi,
|
|
25
|
+
RetailOrgRequestOptions,
|
|
25
26
|
RetailerRosterStatusFilter,
|
|
26
27
|
StoreRosterStatusFilter,
|
|
27
28
|
} from "./interfaces/IRetailOrgBusinessApi.js";
|
|
@@ -55,20 +56,29 @@ export default class RetailOrgBusinessApi implements IRetailOrgBusinessApi {
|
|
|
55
56
|
async listRetailers(
|
|
56
57
|
tenantId: string,
|
|
57
58
|
status?: RetailerRosterStatusFilter,
|
|
59
|
+
integrated?: boolean,
|
|
60
|
+
options?: RetailOrgRequestOptions,
|
|
58
61
|
): Promise<StandardResponse<RetailerValidationDto[]>> {
|
|
59
|
-
// `URLSearchParams` en vez de concatenar: `status` es opcional y armar el `&status=` a mano
|
|
60
|
-
// deja un `&status=undefined` en cuanto alguien se distrae.
|
|
61
62
|
const query = new URLSearchParams({ tenantId });
|
|
62
63
|
if (status) query.set("status", status);
|
|
63
|
-
|
|
64
|
+
if (integrated !== undefined) query.set("integrated", String(integrated));
|
|
65
|
+
const url = `${this.baseUrl}/private/retailers?${query.toString()}`;
|
|
66
|
+
return await this.getWithOptionalTimeout(url, options);
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
async getRetailer(
|
|
67
70
|
retailerId: string,
|
|
68
71
|
tenantId: string,
|
|
72
|
+
options?: RetailOrgRequestOptions,
|
|
69
73
|
): Promise<StandardResponse<RetailerValidationDto>> {
|
|
70
74
|
const url = `${this.baseUrl}/private/retailers/${encodeURIComponent(retailerId)}?tenantId=${encodeURIComponent(tenantId)}`;
|
|
71
|
-
return await this.
|
|
75
|
+
return await this.getWithOptionalTimeout(url, options);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Aplica el timeout solo si el caller lo pide; sin él, el GET queda igual que siempre. */
|
|
79
|
+
private async getWithOptionalTimeout<T>(url: string, options?: RetailOrgRequestOptions): Promise<StandardResponse<T>> {
|
|
80
|
+
if (options?.timeoutMs === undefined) return await this.httpRequest.get(url);
|
|
81
|
+
return await this.httpRequest.get(url, undefined, undefined, undefined, { timeout: options.timeoutMs });
|
|
72
82
|
}
|
|
73
83
|
|
|
74
84
|
async getRetailerByStore(
|
|
@@ -19,6 +19,17 @@ import type {
|
|
|
19
19
|
ApplyStoreEventResponse,
|
|
20
20
|
} from "@fiado/type-kit/bin/retailIntegration/index.js";
|
|
21
21
|
|
|
22
|
+
/** Timeout que el connector y el wizard pasan a `getRetailer`: cabe en los 3 s por evento del connector. */
|
|
23
|
+
export const RETAIL_ORG_GET_RETAILER_TIMEOUT_MS = 1500;
|
|
24
|
+
|
|
25
|
+
/** Timeout que el connector pasa a `listRetailers`: el padrón trae el árbol completo del silo. */
|
|
26
|
+
export const RETAIL_ORG_LIST_RETAILERS_TIMEOUT_MS = 5000;
|
|
27
|
+
|
|
28
|
+
/** Opciones por llamada. Sin `timeoutMs` no se aplica timeout propio. */
|
|
29
|
+
export interface RetailOrgRequestOptions {
|
|
30
|
+
timeoutMs?: number;
|
|
31
|
+
}
|
|
32
|
+
|
|
22
33
|
/**
|
|
23
34
|
* Filtro de `listStoresByRetailer`. `"ALL"` no es un estado de tienda: es la ausencia de filtro, y
|
|
24
35
|
* va en el MISMO parámetro que los estados porque los dos hablan del mismo eje — un segundo flag
|
|
@@ -107,23 +118,32 @@ export interface IRetailOrgBusinessApi {
|
|
|
107
118
|
* Devuelve `[]` si ningún retailer pasa el filtro. **No hay 404**: el silo siempre existe — lo
|
|
108
119
|
* garantiza el `tenantId`, que es lo que resolvió el contexto del tenant.
|
|
109
120
|
*
|
|
121
|
+
* `integrated = true` deja solo los retailers con la bandera de integración prendida; cada
|
|
122
|
+
* retailer trae `integrationSystem` e `integrationActivatedAt` cuando la tiene. Timeout opt-in vía
|
|
123
|
+
* `options.timeoutMs` (ver `RETAIL_ORG_LIST_RETAILERS_TIMEOUT_MS`).
|
|
124
|
+
*
|
|
110
125
|
* @throws `400 RETAILER_STATUS_FILTER_INVALID` si `status` no es del catálogo ·
|
|
111
126
|
* `400 UNKNOWN_TENANT` sin `tenantId`.
|
|
112
127
|
*/
|
|
113
128
|
listRetailers(
|
|
114
129
|
tenantId: string,
|
|
115
130
|
status?: RetailerRosterStatusFilter,
|
|
131
|
+
integrated?: boolean,
|
|
132
|
+
options?: RetailOrgRequestOptions,
|
|
116
133
|
): Promise<StandardResponse<RetailerValidationDto[]>>;
|
|
117
134
|
|
|
118
135
|
/**
|
|
119
136
|
* GET /private/retailers/{retailerId} — valida que el retailer exista y devuelve su shape mínimo
|
|
120
|
-
* (id, name, type, status, parentId). `status` ya viene con la cascada
|
|
137
|
+
* (id, name, type, status, parentId) y la bandera de integración. `status` ya viene con la cascada
|
|
138
|
+
* aplicada (estado efectivo). Timeout opt-in vía `options.timeoutMs` (ver
|
|
139
|
+
* `RETAIL_ORG_GET_RETAILER_TIMEOUT_MS`).
|
|
121
140
|
*
|
|
122
141
|
* @throws si el retailer no existe (`404 RETAILER_NOT_FOUND`).
|
|
123
142
|
*/
|
|
124
143
|
getRetailer(
|
|
125
144
|
retailerId: string,
|
|
126
145
|
tenantId: string,
|
|
146
|
+
options?: RetailOrgRequestOptions,
|
|
127
147
|
): Promise<StandardResponse<RetailerValidationDto>>;
|
|
128
148
|
|
|
129
149
|
/**
|