import { describe, it, expect } from 'vitest'; import { applyConceptoEdits, AVISO_EDITADO } from '@/budget/edit'; import type { BudgetResult } from '@/budget/types'; const base: BudgetResult = { partidas: [ { key: 'demolicion', label: 'Demolición', importe: 100000 }, { key: 'alicatado', label: 'Alicatado y solado', importe: 200000 }, ], subtotal: 300000, factorZona: 1.2, total: 360000, rango: { min: 324000, max: 396000 }, confianza: 'media', materialesRender: ['azulejo blanco'], avisos: ['Sin precio para pintura'], }; describe('applyConceptoEdits', () => { it('recalcula subtotal y total aplicando el factor de zona', () => { const result = applyConceptoEdits(base, [ { key: 'demolicion', label: 'Demolición', importe: 150000 }, { key: 'alicatado', label: 'Alicatado y solado', importe: 200000 }, ]); expect(result.subtotal).toBe(350000); expect(result.total).toBe(420000); // 350000 * 1.2 }); it('permite añadir partidas libres y quitar existentes', () => { const result = applyConceptoEdits(base, [ { key: 'demolicion', label: 'Demolición', importe: 100000 }, { key: 'custom-1', label: 'Imprevistos de obra', importe: 50000 }, ]); expect(result.partidas).toHaveLength(2); expect(result.partidas[1]).toEqual({ key: 'custom-1', label: 'Imprevistos de obra', importe: 50000 }); expect(result.subtotal).toBe(150000); }); it('descarta partidas sin etiqueta y normaliza importes (>=0, enteros)', () => { const result = applyConceptoEdits(base, [ { key: 'a', label: ' ', importe: 999 }, { key: 'b', label: 'Válida', importe: -500 }, { key: 'c', label: 'Decimal', importe: 123.7 }, ]); expect(result.partidas).toEqual([ { key: 'b', label: 'Válida', importe: 0 }, { key: 'c', label: 'Decimal', importe: 124 }, ]); }); it('marca el presupuesto como ajustado a mano (aviso idempotente, confianza alta, rango = total)', () => { const once = applyConceptoEdits(base, base.partidas); expect(once.confianza).toBe('alta'); expect(once.avisos).toContain(AVISO_EDITADO); expect(once.rango).toEqual({ min: once.total, max: once.total }); const twice = applyConceptoEdits(once, once.partidas); expect(twice.avisos.filter((a) => a === AVISO_EDITADO)).toHaveLength(1); }); });