Reemplaza al addon .NET Framework (SolucionLibros). Genera Devoluciones de mercancías enlazadas a sus Entradas por compra a partir de un listado pegado desde Excel. - libs/shared (@dp/shared): modelos y lógica de dominio pura (FIFO, consolidación por proveedor, parseo del portapapeles), portada del addon. - apps/api (NestJS): cliente del Service Layer con cola por sesión, login con la sesión de SAP, metadatos (UDT/UDF/UDO) y botón Reconstruir, catálogos, planificaciones (pegar, procesar, reprocesar, marcar líneas, crear Devoluciones, cerrar), listado paginado con filtros y descarga de PDF de la Guía de despacho desde BES. Sirve también la web compilada, con HTTPS opcional. - apps/web (Angular): login, Configuración → Metadatos y Planificaciones (listado, nueva, detalle). - deploy/windows y scripts/publicar.mjs: despliegue como servicio de Windows con WinSW. Verificado contra el Service Layer de SQL Server. Sin probar aún: SAP HANA y la instalación del servicio en Windows (ver CLAUDE.md, sección "Sin verificar"). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
83 lines
2.9 KiB
TypeScript
83 lines
2.9 KiB
TypeScript
import { existsSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
|
|
/** Rutas de los archivos de certificado (se leen al arrancar). Con `pfx` o con `key` + `cert`. */
|
|
export interface HttpsConfig {
|
|
pfxPath?: string;
|
|
passphrase?: string;
|
|
keyPath?: string;
|
|
certPath?: string;
|
|
}
|
|
|
|
export interface AppConfig {
|
|
port: number;
|
|
webOrigin: string;
|
|
serviceLayer: {
|
|
url: string;
|
|
companyDb: string;
|
|
rejectUnauthorized: boolean;
|
|
};
|
|
dbType: 'HANA' | 'MSSQL';
|
|
cookieSecure: boolean;
|
|
/** Carpeta con el build de Angular que la API sirve; null si no existe (desarrollo con `ng serve`). */
|
|
webDistDir: string | null;
|
|
/** null = la API escucha en HTTP. */
|
|
https: HttpsConfig | null;
|
|
/** Si hay HTTPS: puerto HTTP que redirige al HTTPS (por ejemplo 80). null = no se abre. */
|
|
httpRedirectPort: number | null;
|
|
}
|
|
|
|
const vacio = (v: string | undefined): string | undefined => (v && v.trim() !== '' ? v.trim() : undefined);
|
|
|
|
function leerHttps(): HttpsConfig | null {
|
|
const pfxPath = vacio(process.env.HTTPS_PFX_PATH);
|
|
const keyPath = vacio(process.env.HTTPS_KEY_PATH);
|
|
const certPath = vacio(process.env.HTTPS_CERT_PATH);
|
|
|
|
if (!pfxPath && !keyPath && !certPath) return null;
|
|
if (pfxPath && (keyPath || certPath)) {
|
|
throw new Error('Configure el certificado con HTTPS_PFX_PATH o con HTTPS_KEY_PATH + HTTPS_CERT_PATH, no con ambos.');
|
|
}
|
|
if (!pfxPath && !(keyPath && certPath)) {
|
|
throw new Error('Falta HTTPS_KEY_PATH o HTTPS_CERT_PATH: ambos son necesarios.');
|
|
}
|
|
return { pfxPath, passphrase: vacio(process.env.HTTPS_PFX_PASSPHRASE), keyPath, certPath };
|
|
}
|
|
|
|
/** WEB_DIST_DIR, o el build de Angular junto a la API (apps/web/dist/web/browser) si existe. */
|
|
function carpetaWeb(): string | null {
|
|
const configurada = vacio(process.env.WEB_DIST_DIR);
|
|
const ruta = configurada ? resolve(configurada) : resolve(import.meta.dirname, '../../../web/dist/web/browser');
|
|
if (existsSync(resolve(ruta, 'index.html'))) return ruta;
|
|
if (configurada) throw new Error(`WEB_DIST_DIR no contiene un index.html: ${ruta}`);
|
|
return null;
|
|
}
|
|
|
|
export default (): AppConfig => {
|
|
const dbType = (process.env.DB_TYPE ?? 'HANA').toUpperCase();
|
|
if (dbType !== 'HANA' && dbType !== 'MSSQL') {
|
|
throw new Error(`DB_TYPE inválido: ${dbType}. Valores permitidos: HANA, MSSQL.`);
|
|
}
|
|
|
|
const url = process.env.SL_URL;
|
|
const companyDb = process.env.SL_COMPANY_DB;
|
|
if (!url || !companyDb) {
|
|
throw new Error('Faltan SL_URL y/o SL_COMPANY_DB en la configuración (.env).');
|
|
}
|
|
|
|
return {
|
|
port: Number(process.env.PORT ?? 3000),
|
|
webOrigin: process.env.WEB_ORIGIN ?? 'http://localhost:4200',
|
|
serviceLayer: {
|
|
url: url.replace(/\/+$/, ''),
|
|
companyDb,
|
|
rejectUnauthorized: process.env.SL_REJECT_UNAUTHORIZED !== 'false',
|
|
},
|
|
dbType,
|
|
cookieSecure: process.env.COOKIE_SECURE === 'true',
|
|
webDistDir: carpetaWeb(),
|
|
https: leerHttps(),
|
|
httpRedirectPort: Number(vacio(process.env.HTTP_REDIRECT_PORT)) || null,
|
|
};
|
|
};
|