fix: validate numeric pricing inputs and drop unused import
Guard euro/altura inputs in precios actions so empty or non-numeric form values return a Spanish error instead of writing NaN and throwing a 500. Remove the now-unused formatEuros import flagged by ESLint. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,24 @@ import { catalogItems, pricingConfig } from '@/db/schema';
|
||||
import { getTenantId } from '@/db/pricing-queries';
|
||||
import { parseCatalogCsv } from '@/budget/csv';
|
||||
|
||||
// Valida un importe en euros del formulario y lo convierte a céntimos.
|
||||
// Lanza un error en español si el valor no es un número finito >= 0.
|
||||
function eurosToCents(raw: FormDataEntryValue | null, campo: string): number {
|
||||
const euros = Number(raw);
|
||||
if (!Number.isFinite(euros) || euros < 0) {
|
||||
throw new Error(`El valor de "${campo}" debe ser un número mayor o igual que 0.`);
|
||||
}
|
||||
return Math.round(euros * 100);
|
||||
}
|
||||
|
||||
function parsePositive(raw: FormDataEntryValue | null, campo: string): number {
|
||||
const n = Number(raw);
|
||||
if (!Number.isFinite(n) || n <= 0) {
|
||||
throw new Error(`El valor de "${campo}" debe ser un número mayor que 0.`);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
export async function crearMaterial(formData: FormData) {
|
||||
const tenantId = await getTenantId();
|
||||
await db.insert(catalogItems).values({
|
||||
@@ -14,7 +32,7 @@ export async function crearMaterial(formData: FormData) {
|
||||
categoria: formData.get('categoria') as 'suelo' | 'pared' | 'pintura' | 'mobiliario',
|
||||
nombre: String(formData.get('nombre') ?? ''),
|
||||
calidad: formData.get('calidad') as 'basica' | 'media' | 'premium',
|
||||
precioUnit: Math.round(Number(formData.get('precioEuros') ?? 0) * 100),
|
||||
precioUnit: eurosToCents(formData.get('precioEuros'), 'precio'),
|
||||
unidad: formData.get('unidad') as 'm2' | 'ml' | 'ud',
|
||||
descriptorRender: String(formData.get('descriptorRender') ?? ''),
|
||||
esDefault: formData.get('esDefault') === 'on',
|
||||
@@ -28,7 +46,7 @@ export async function actualizarPrecio(formData: FormData) {
|
||||
const id = String(formData.get('id') ?? '');
|
||||
await db
|
||||
.update(catalogItems)
|
||||
.set({ precioUnit: Math.round(Number(formData.get('precioEuros') ?? 0) * 100) })
|
||||
.set({ precioUnit: eurosToCents(formData.get('precioEuros'), 'precio') })
|
||||
.where(and(eq(catalogItems.id, id), eq(catalogItems.tenantId, tenantId)));
|
||||
revalidatePath('/panel/precios');
|
||||
}
|
||||
@@ -45,12 +63,12 @@ export async function actualizarConfig(formData: FormData) {
|
||||
await db
|
||||
.update(pricingConfig)
|
||||
.set({
|
||||
alturaTechoDefault: Number(formData.get('alturaTechoDefault') ?? 2.5),
|
||||
alturaTechoDefault: parsePositive(formData.get('alturaTechoDefault'), 'altura de techo'),
|
||||
manoObra: {
|
||||
demolicion: Math.round(Number(formData.get('mo_demolicion') ?? 0) * 100),
|
||||
fontaneria: Math.round(Number(formData.get('mo_fontaneria') ?? 0) * 100),
|
||||
electricidad: Math.round(Number(formData.get('mo_electricidad') ?? 0) * 100),
|
||||
mano_de_obra: Math.round(Number(formData.get('mo_mano_de_obra') ?? 0) * 100),
|
||||
demolicion: eurosToCents(formData.get('mo_demolicion'), 'demolición'),
|
||||
fontaneria: eurosToCents(formData.get('mo_fontaneria'), 'fontanería'),
|
||||
electricidad: eurosToCents(formData.get('mo_electricidad'), 'electricidad'),
|
||||
mano_de_obra: eurosToCents(formData.get('mo_mano_de_obra'), 'mano de obra'),
|
||||
},
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { getPricingConfig, getCatalog } from '@/db/pricing-queries';
|
||||
import { formatEuros } from '@/lib/funnel';
|
||||
import {
|
||||
crearMaterial,
|
||||
actualizarPrecio,
|
||||
|
||||
Reference in New Issue
Block a user