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; `null` = cualquier sesión (acciones de solo consulta). */ write: RequiredPath | null; /** Colecciones permitidas en `$expand` (por defecto ninguna). */ expand?: string[]; /** Acciones sobre un registro (`POST Entidad(clave)/Accion`) que se pueden invocar, p. ej. `Cancel`. Requieren el permiso de escritura. */ actions?: readonly string[]; } /** * Documento de marketing o de pagos. `alsoRead` suma pantallas que solo pueden consultarlo (los pagos leen las * facturas pendientes del socio sin poder modificarlas). */ const document = (name: string, path: RequiredPath, alsoRead: RequiredPath = []): SlResource => ({ name, key: 'number', methods: ['GET', 'POST', 'PATCH'], read: [path, alsoRead].flat(), write: path, }); const catalog = (name: string, key: 'number' | 'string', writePath?: RequiredPath): SlResource => ({ name, key, methods: writePath ? ['GET', 'POST', 'PATCH'] : ['GET'], read: null, write: writePath ?? [], }); /** * Acción del Service Layer que solo consulta (se invoca con POST y no escribe nada): cualquier sesión. * El nombre es el de la acción (`SeriesService_GetDocumentSeries`), no el de una entidad. */ const queryAction = (name: string): SlResource => ({ name, key: 'string', methods: ['POST'], read: null, write: null }); /** * Ú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'), // Boletas (`DocumentSubType = bod_Bill`) y facturas de reserva (`ReserveInvoice = tYES`) son facturas: mismo recurso, cuatro pantallas. document('Invoices', ['/ventas/facturas', '/ventas/boletas', '/ventas/facturas-reserva', '/ventas/boletas-reserva'], '/bancos/pagos-recibidos'), document('Returns', '/ventas/devoluciones'), document('CreditNotes', '/ventas/notas-credito', '/bancos/pagos-recibidos'), // Compras document('PurchaseRequests', '/compras/solicitudes'), document('PurchaseQuotations', '/compras/ofertas'), document('PurchaseOrders', '/compras/ordenes'), document('PurchaseDeliveryNotes', '/compras/recepcion'), document('PurchaseInvoices', '/compras/facturas', '/bancos/pagos-efectuados'), document('PurchaseReturns', '/compras/devoluciones'), document('PurchaseCreditNotes', '/compras/notas-credito', '/bancos/pagos-efectuados'), // Inventario document('StockTransfers', '/inventario/transferencias'), document('InventoryTransferRequests', '/inventario/solicitudes-traslado'), document('InventoryGenEntries', '/inventario/entradas'), document('InventoryGenExits', '/inventario/salidas'), // Bancos: pagos recibidos y efectuados. Se pueden anular (`Cancel`) pero no modificar. { ...document('IncomingPayments', '/bancos/pagos-recibidos'), methods: ['GET', 'POST'], actions: ['Cancel'] }, { ...document('VendorPayments', '/bancos/pagos-efectuados'), methods: ['GET', 'POST'], actions: ['Cancel'] }, // Finanzas: los asientos manuales se crean y se cancelan (`Cancel` genera el asiento de reverso), no se modifican. { ...document('JournalEntries', '/finanzas/asientos'), methods: ['GET', 'POST'], actions: ['Cancel'] }, // 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'), // Grupos de los maestros (para elegirlos y filtrar las listas de clientes, proveedores y artículos). catalog('BusinessPartnerGroups', 'number'), catalog('ItemGroups', 'number'), catalog('Banks', 'string'), catalog('CreditCards', 'number'), // Dimensiones, proyectos y cuentas de los documentos (para elegirlos en cabecera y líneas). // Indicadores de los documentos (tabla OIDC; en la localización chilena, el tipo de documento: 33 factura, 39 boleta). catalog('FactoringIndicators', 'string'), catalog('DistributionRules', 'string'), catalog('Projects', 'string'), // Plan de cuentas: se consulta desde cualquier documento y se mantiene en Finanzas. catalog('ChartOfAccounts', 'string', '/finanzas/plan-de-cuentas'), // Series de numeración válidas de un tipo de documento. queryAction('SeriesService_GetDocumentSeries'), // Gastos adicionales de un documento (el flete): se leen para elegir el código de gasto. catalog('AdditionalExpenses', 'number'), ]; export const SL_RESOURCE_MAP: ReadonlyMap = new Map(SL_RESOURCES.map((r) => [r.name, r]));