diff --git a/apps/api/src/htmlreports/html-reports.service.ts b/apps/api/src/htmlreports/html-reports.service.ts index a07a187..1e39ee3 100644 --- a/apps/api/src/htmlreports/html-reports.service.ts +++ b/apps/api/src/htmlreports/html-reports.service.ts @@ -24,7 +24,8 @@ export function parseHtmlValues(def: HtmlReportDef, raw: Readonly { expect(() => validateHtmlReports([{ ...def, params: [P({ name: 'a' }), P({ name: 'a' })] }])).toThrow(/repite el parámetro/); expect(() => validateHtmlReports([{ ...def, template: '../fuera.njk' }])).toThrow(/dentro de la carpeta/); expect(() => validateHtmlReports([{ ...def, template: '/etc/passwd' }])).toThrow(/dentro de la carpeta/); + expect(() => validateHtmlReports([{ ...def, params: [P({ name: 'papel', readOnly: true })] }])).toThrow(/solo lectura y necesita un valor por defecto/); expect(validateHtmlReports([def])).toHaveLength(1); }); }); describe('valores de los parámetros', () => { + it('un parámetro de solo lectura vale siempre su valor por defecto, aunque el cliente mande otro', () => { + const fijo = { ...def, params: [P({ name: 'papel', label: 'Papel', kind: 'select', options: [{ value: 'Carta', label: 'Carta' }, { value: 'A4', label: 'A4' }], defaultValue: 'Carta', readOnly: true })] }; + expect(parseHtmlValues(fijo, {})).toEqual({ papel: 'Carta' }); + expect(parseHtmlValues(fijo, { papel: 'A4' })).toEqual({ papel: 'Carta' }); + }); + it('exige los obligatorios, aplica el valor por defecto y comprueba tipos', () => { expect(parseHtmlValues(def, { doc: '144153', cantidad: 6 })).toEqual({ doc: '144153', cantidad: '6', papel: 'Carta', fecha: '' }); expect(() => parseHtmlValues(def, { cantidad: '6' })).toThrow(/Falta indicar: Entrega/); diff --git a/apps/api/src/htmlreports/html-reports.ts b/apps/api/src/htmlreports/html-reports.ts index f9d40b8..6a65a4e 100644 --- a/apps/api/src/htmlreports/html-reports.ts +++ b/apps/api/src/htmlreports/html-reports.ts @@ -16,6 +16,7 @@ export function validateHtmlReports(reports: readonly HtmlReportDef[]): readonly for (const p of r.params) { if (names.has(p.name)) throw new Error(`El reporte ${r.code} repite el parámetro ${p.name}`); names.add(p.name); + if (p.readOnly && !p.defaultValue) throw new Error(`El parámetro ${p.name} de ${r.code} es de solo lectura y necesita un valor por defecto`); } } return reports; diff --git a/apps/web/src/app/features/reports/report-param-field.spec.ts b/apps/web/src/app/features/reports/report-param-field.spec.ts index 6a5dafd..871f468 100644 --- a/apps/web/src/app/features/reports/report-param-field.spec.ts +++ b/apps/web/src/app/features/reports/report-param-field.spec.ts @@ -60,6 +60,15 @@ describe('ReportParamField', () => { expect(select.value).toBe('2'); }); + it('un parámetro de solo lectura se ve con su valor pero no se puede cambiar', async () => { + await show(param({ kind: 'select', label: 'Papel', options: [{ value: 'Carta', label: 'Carta' }], readOnly: true }), 'Carta'); + const select = el().querySelector('select') as HTMLSelectElement; + expect(select.value).toBe('Carta'); + expect(select.disabled || select.hasAttribute('readonly') || select.closest('[readonly]') !== null).toBe(true); + await show(param({ label: 'Nombre', readOnly: true }), 'fijo'); + expect(inputs()[0].readOnly).toBe(true); + }); + it('un rango pide desde y hasta y los emite como lista', async () => { await show(param({ kind: 'date', range: true }), ['2026-01-01', '2026-01-31']); expect(labels().join(' ')).toContain('desde / hasta'); diff --git a/apps/web/src/app/features/reports/report-param-field.ts b/apps/web/src/app/features/reports/report-param-field.ts index dc53b4c..67d00aa 100644 --- a/apps/web/src/app/features/reports/report-param-field.ts +++ b/apps/web/src/app/features/reports/report-param-field.ts @@ -24,23 +24,23 @@ const asList = (v: Value): readonly string[] => (typeof v === 'string' ? (v === @case ('single') { @switch (p.kind) { @case ('number') { - + } @case ('date') { - + } @case ('select') { - + } @case ('lookup') { @if (catalog(); as c) { - + } @else { - + } } @default { - + } } } diff --git a/libs/sap-types/src/gateway.ts b/libs/sap-types/src/gateway.ts index 16615d4..97c87b6 100644 --- a/libs/sap-types/src/gateway.ts +++ b/libs/sap-types/src/gateway.ts @@ -20,6 +20,8 @@ export interface GatewayParam { /** Se admiten varios valores. */ multiple?: boolean; defaultValue?: string; + /** Se muestra pero no se edita: vale siempre su valor por defecto (por ejemplo el papel de unas etiquetas precortadas). */ + readOnly?: boolean; placeholder?: string; /** Opciones de una lista fija (`kind = select`). */ options?: { value: string; label: string }[];