feat(api): proxy del Service Layer con registro de recursos
El frontend envía parámetros OData y cuerpo; el backend valida y ejecuta. - GET lista/por clave, POST y PATCH sobre /api/sl/:recurso, solo para recursos registrados (ventas, compras, inventario y maestros estándar); EmployeesInfo no se registra nunca (contiene U_WEB_PASS). - Permisos de menú por recurso (lectura/escritura); catálogos de consulta abiertos a cualquier sesión. Evaluador de patrones compartible (/inventario/* ya no habilita /inventario-x). - Parámetros OData validados con lista cerrada, $top máx. 500, $expand solo si el recurso lo declara, claves validadas y escapadas por tipo, cabeceras B1S-* con lista blanca. $inlinecount y B1S-PageSize automáticos. - configureApp() compartido entre main.ts y e2e (prefijo y límite de 5 mb). - Verificado contra SAP real: los 27 recursos existen; listado con total, filtro, paginación y claves. InventoryRequests no existe en el SL: se registra InventoryTransferRequests. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
73fffee2f7
commit
c0990ca83e
15 files changed
+683
-6
No files matched your search
@@ -0,0 +1,79 @@
|
||||
export type SlMethod = 'GET' | 'POST' | 'PATCH';
|
||||
|
||||
/** Ruta(s) de menú que el usuario debe tener permitidas (basta con una). */
|
||||
export type RequiredPath = string | string[];
|
||||
|
||||
export interface SlResource {
|
||||
/** Nombre de la entidad en el Service Layer (sensible a mayúsculas). */
|
||||
name: string;
|
||||
/** Tipo de la clave primaria: se valida y se escapa al armar `Entidad(clave)`. */
|
||||
key: 'number' | 'string';
|
||||
methods: SlMethod[];
|
||||
/** Ruta de menú requerida para leer; `null` = cualquier sesión (catálogos de consulta). */
|
||||
read: RequiredPath | null;
|
||||
/** Ruta de menú requerida para crear/modificar. */
|
||||
write: RequiredPath;
|
||||
/** Colecciones permitidas en `$expand` (por defecto ninguna). */
|
||||
expand?: string[];
|
||||
}
|
||||
|
||||
const document = (name: string, path: string): SlResource => ({
|
||||
name,
|
||||
key: 'number',
|
||||
methods: ['GET', 'POST', 'PATCH'],
|
||||
read: path,
|
||||
write: path,
|
||||
});
|
||||
|
||||
const catalog = (name: string, key: 'number' | 'string', writePath?: RequiredPath): SlResource => ({
|
||||
name,
|
||||
key,
|
||||
methods: writePath ? ['GET', 'POST', 'PATCH'] : ['GET'],
|
||||
read: null,
|
||||
write: writePath ?? [],
|
||||
});
|
||||
|
||||
/**
|
||||
* Único lugar donde se declara qué puede tocar el frontend. Lo que no esté aquí
|
||||
* no se puede consultar (404). Nunca registrar `EmployeesInfo`: contiene U_WEB_PASS.
|
||||
*
|
||||
* Las rutas de menú son las mismas que usará el frontend (permisos por pantalla).
|
||||
*/
|
||||
export const SL_RESOURCES: readonly SlResource[] = [
|
||||
// Ventas
|
||||
document('Quotations', '/ventas/ofertas'),
|
||||
document('Orders', '/ventas/ordenes'),
|
||||
document('DeliveryNotes', '/ventas/entrega'),
|
||||
document('Invoices', '/ventas/facturas'),
|
||||
document('Returns', '/ventas/devoluciones'),
|
||||
document('CreditNotes', '/ventas/notas-credito'),
|
||||
|
||||
// Compras
|
||||
document('PurchaseRequests', '/compras/solicitudes'),
|
||||
document('PurchaseQuotations', '/compras/ofertas'),
|
||||
document('PurchaseOrders', '/compras/ordenes'),
|
||||
document('PurchaseDeliveryNotes', '/compras/recepcion'),
|
||||
document('PurchaseInvoices', '/compras/facturas'),
|
||||
document('PurchaseReturns', '/compras/devoluciones'),
|
||||
document('PurchaseCreditNotes', '/compras/notas-credito'),
|
||||
|
||||
// Inventario
|
||||
document('StockTransfers', '/inventario/transferencias'),
|
||||
document('InventoryTransferRequests', '/inventario/solicitudes-traslado'),
|
||||
document('InventoryGenEntries', '/inventario/entradas'),
|
||||
document('InventoryGenExits', '/inventario/salidas'),
|
||||
|
||||
// Maestros (consulta para cualquier sesión; escritura según el módulo)
|
||||
catalog('BusinessPartners', 'string', ['/socios/clientes', '/socios/proveedores']),
|
||||
catalog('Items', 'string', '/inventario/articulos'),
|
||||
catalog('Warehouses', 'string'),
|
||||
catalog('Currencies', 'string'),
|
||||
catalog('SalesTaxCodes', 'string'),
|
||||
catalog('VatGroups', 'string'),
|
||||
catalog('PaymentTermsTypes', 'number'),
|
||||
catalog('SalesPersons', 'number'),
|
||||
catalog('PriceLists', 'number'),
|
||||
catalog('UnitOfMeasurements', 'number'),
|
||||
];
|
||||
|
||||
export const SL_RESOURCE_MAP: ReadonlyMap<string, SlResource> = new Map(SL_RESOURCES.map((r) => [r.name, r]));
|
||||
Reference in new issue
Block a user