feat: add pricing panel with catalog CRUD and CSV import
This commit is contained in:
87
mvp/b2c/src/app/panel/precios/actions.ts
Normal file
87
mvp/b2c/src/app/panel/precios/actions.ts
Normal file
@@ -0,0 +1,87 @@
|
||||
'use server';
|
||||
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { revalidatePath } from 'next/cache';
|
||||
import { db } from '@/db';
|
||||
import { catalogItems, pricingConfig } from '@/db/schema';
|
||||
import { getTenantId } from '@/db/pricing-queries';
|
||||
import { parseCatalogCsv } from '@/budget/csv';
|
||||
|
||||
export async function crearMaterial(formData: FormData) {
|
||||
const tenantId = await getTenantId();
|
||||
await db.insert(catalogItems).values({
|
||||
tenantId,
|
||||
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),
|
||||
unidad: formData.get('unidad') as 'm2' | 'ml' | 'ud',
|
||||
descriptorRender: String(formData.get('descriptorRender') ?? ''),
|
||||
esDefault: formData.get('esDefault') === 'on',
|
||||
sku: String(formData.get('sku') ?? ''),
|
||||
});
|
||||
revalidatePath('/panel/precios');
|
||||
}
|
||||
|
||||
export async function actualizarPrecio(formData: FormData) {
|
||||
const tenantId = await getTenantId();
|
||||
const id = String(formData.get('id') ?? '');
|
||||
await db
|
||||
.update(catalogItems)
|
||||
.set({ precioUnit: Math.round(Number(formData.get('precioEuros') ?? 0) * 100) })
|
||||
.where(and(eq(catalogItems.id, id), eq(catalogItems.tenantId, tenantId)));
|
||||
revalidatePath('/panel/precios');
|
||||
}
|
||||
|
||||
export async function borrarMaterial(formData: FormData) {
|
||||
const tenantId = await getTenantId();
|
||||
const id = String(formData.get('id') ?? '');
|
||||
await db.delete(catalogItems).where(and(eq(catalogItems.id, id), eq(catalogItems.tenantId, tenantId)));
|
||||
revalidatePath('/panel/precios');
|
||||
}
|
||||
|
||||
export async function actualizarConfig(formData: FormData) {
|
||||
const tenantId = await getTenantId();
|
||||
await db
|
||||
.update(pricingConfig)
|
||||
.set({
|
||||
alturaTechoDefault: Number(formData.get('alturaTechoDefault') ?? 2.5),
|
||||
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),
|
||||
},
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(pricingConfig.tenantId, tenantId));
|
||||
revalidatePath('/panel/precios');
|
||||
}
|
||||
|
||||
export type ImportResult = { ok: boolean; inserted: number; errors: { line: number; message: string }[] };
|
||||
|
||||
export async function importarCatalogoCsv(_prev: ImportResult | null, formData: FormData): Promise<ImportResult> {
|
||||
const tenantId = await getTenantId();
|
||||
const csv = String(formData.get('csv') ?? '');
|
||||
const { rows, errors } = parseCatalogCsv(csv);
|
||||
if (errors.length > 0) return { ok: false, inserted: 0, errors };
|
||||
|
||||
for (const r of rows) {
|
||||
await db
|
||||
.insert(catalogItems)
|
||||
.values({ tenantId, ...r })
|
||||
.onConflictDoUpdate({
|
||||
target: [catalogItems.tenantId, catalogItems.sku],
|
||||
set: {
|
||||
categoria: r.categoria,
|
||||
nombre: r.nombre,
|
||||
calidad: r.calidad,
|
||||
precioUnit: r.precioUnit,
|
||||
unidad: r.unidad,
|
||||
descriptorRender: r.descriptorRender,
|
||||
},
|
||||
});
|
||||
}
|
||||
revalidatePath('/panel/precios');
|
||||
return { ok: true, inserted: rows.length, errors: [] };
|
||||
}
|
||||
Reference in New Issue
Block a user