feat(api): módulo de consultas de solo lectura a la base de SAP (HANA con hdb): consultas registradas con parámetros con nombre, cola, auditoría y extensión por cliente

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-20 07:31:17 -05:00
1 parent 9118985d96
commit 3e27f370dc
21 files changed
+770 -2

No files matched your search

+32
View File
@@ -65,6 +65,29 @@ export const envSchema = z
.enum(['true', 'false'])
.default('true')
.transform((v) => v === 'true'),
// --- Base de datos de SAP B1 (consultas de solo lectura registradas): opcional; sin motor el módulo queda sin configurar ---
SAPDB_ENGINE: z.preprocess(emptyToUndefined, z.enum(['hana']).optional()),
SAPDB_HOST: z.preprocess(emptyToUndefined, z.string().optional()),
SAPDB_PORT: z.coerce.number().int().min(1).max(65535).default(30015),
SAPDB_USER: z.preprocess(emptyToUndefined, z.string().optional()),
SAPDB_PASSWORD: z.preprocess(emptyToUndefined, z.string().optional()),
// Esquema de la empresa (en HANA, el nombre de la base: `SBO_TAGUMEDICA_21`).
SAPDB_SCHEMA: z.preprocess(emptyToUndefined, z.string().regex(/^\w+$/, 'solo letras, dígitos y «_»').optional()),
SAPDB_TLS: z
.enum(['true', 'false'])
.default('false')
.transform((v) => v === 'true'),
SAPDB_CA_FILE: z.preprocess(emptyToUndefined, z.string().optional()),
SAPDB_VERIFY_SSL: z
.enum(['true', 'false'])
.default('true')
.transform((v) => v === 'true'),
// Espera máxima (segundos) de cada consulta.
SAPDB_TIMEOUT: z.coerce.number().positive().default(30),
// Consultas que se ejecutan a la vez; el resto espera su turno (la base de SAP no es para esto).
SAPDB_MAX_CONCURRENCY: z.coerce.number().int().positive().default(2),
// Tope de filas de cualquier consulta; lo que pase se recorta.
SAPDB_MAX_ROWS: z.coerce.number().int().positive().default(5000),
SAPB1_SL_VERIFY_SSL: z
.enum(['true', 'false'])
.default('true')
@@ -81,6 +104,15 @@ export const envSchema = z
if (env.APIGATEWAY_CA_FILE && !existsSync(resolve(env.APIGATEWAY_CA_FILE))) {
ctx.addIssue({ code: 'custom', path: ['APIGATEWAY_CA_FILE'], message: `no existe el archivo ${resolve(env.APIGATEWAY_CA_FILE)}` });
}
if (env.SAPDB_CA_FILE && !existsSync(resolve(env.SAPDB_CA_FILE))) {
ctx.addIssue({ code: 'custom', path: ['SAPDB_CA_FILE'], message: `no existe el archivo ${resolve(env.SAPDB_CA_FILE)}` });
}
if (env.SAPDB_ENGINE && !(env.SAPDB_HOST && env.SAPDB_USER && env.SAPDB_PASSWORD && env.SAPDB_SCHEMA)) {
ctx.addIssue({ code: 'custom', path: ['SAPDB_ENGINE'], message: 'con SAPDB_ENGINE hacen falta SAPDB_HOST, SAPDB_USER, SAPDB_PASSWORD y SAPDB_SCHEMA' });
}
if (env.NODE_ENV === 'production' && env.SAPDB_TLS && !env.SAPDB_VERIFY_SSL) {
ctx.addIssue({ code: 'custom', path: ['SAPDB_VERIFY_SSL'], message: 'no se permite desactivar la validación SSL en producción; use SAPDB_CA_FILE' });
}
if (env.APIGATEWAY_URL && !(env.APIGATEWAY_USER && env.APIGATEWAY_PASSWORD && env.APIGATEWAY_COMPANYDB)) {
ctx.addIssue({ code: 'custom', path: ['APIGATEWAY_URL'], message: 'con APIGATEWAY_URL hacen falta APIGATEWAY_USER, APIGATEWAY_PASSWORD y APIGATEWAY_COMPANYDB' });
}