Añade revisión pre-envío del reformista y PDF de presupuesto pulido

Adelanta de F1.5 a F2 la validación pre-envío: el panel permite elegir
modo de envío (automático/revisión), editar los conceptos del
presupuesto y enviar al cliente por WhatsApp (simulado).

Añade datos de empresa y logo configurables en /panel/empresa y genera
el presupuesto como PDF real descargable con esa marca vía
@react-pdf/renderer, sustituyendo la vista HTML imprimible.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Carlos Narro
2026-05-30 22:27:05 +02:00
parent b84b2f37a2
commit ec141cdd6e
26 changed files with 3961 additions and 59 deletions

View File

@@ -0,0 +1,30 @@
import type { BudgetResult, PartidaResult } from './types';
export const AVISO_EDITADO = 'Presupuesto ajustado manualmente por el reformista.';
// Aplica la edición manual de conceptos del reformista sobre un presupuesto ya calculado.
// Conserva el factor de zona del cálculo original; el reformista ha validado las cifras,
// así que la confianza pasa a alta y el rango colapsa al total.
export function applyConceptoEdits(prev: BudgetResult, partidas: PartidaResult[]): BudgetResult {
const clean: PartidaResult[] = partidas
.map((p) => ({
key: p.key,
label: p.label.trim(),
importe: Math.max(0, Math.round(p.importe)),
}))
.filter((p) => p.label.length > 0);
const subtotal = clean.reduce((s, p) => s + p.importe, 0);
const total = Math.round(subtotal * prev.factorZona);
const avisos = prev.avisos.includes(AVISO_EDITADO) ? prev.avisos : [...prev.avisos, AVISO_EDITADO];
return {
...prev,
partidas: clean,
subtotal,
total,
rango: { min: total, max: total },
confianza: 'alta',
avisos,
};
}

View File

@@ -44,7 +44,9 @@ export interface BudgetInputs {
}
export interface PartidaResult {
key: PartidaKey;
// PartidaKey para las partidas que genera el motor; string libre (p. ej. 'custom-1')
// para las que añade el reformista a mano en la revisión.
key: PartidaKey | string;
label: string;
importe: number; // céntimos (base, antes de factor zona)
}