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 }[];