mirror of
https://origin.cursor.com/mrdevmx/panels.git
synced 2026-10-09 17:43:19 +00:00
98 lines
4.6 KiB
TypeScript
98 lines
4.6 KiB
TypeScript
import { assertEquals, assertStringIncludes } from "jsr:@std/assert@1";
|
|
import * as XLSX from "xlsx";
|
|
import { buildBudgetTemplate, parseBudgetRows, parseMoney, previewBudgetExcel } from "./budget.ts";
|
|
|
|
Deno.test("parsea partidas estilo CLAVE DESCRIPCION UNIDAD", () => {
|
|
const parsed = parseBudgetRows([
|
|
["Obra:", "Barda perimetral"],
|
|
["BARDAS PERIMETRALES", "", "", "", "", ""],
|
|
["CLAVE", "DESCRIPCION", "UNIDAD", "CANTIDAD", "PRECIO U", "IMPORTE"],
|
|
["PRE01", "TRAZO Y NIVELACION", "ml", 92, 10, 920],
|
|
["EXC-001", "EXCAVACION", "M3", 8, 850, 6800],
|
|
["", "", "", "", "SUB TOTAL", 398545.97],
|
|
["", "", "", "", "16% IVA", 63767.36],
|
|
["", "", "", "", "TOTAL", 462313.33],
|
|
]);
|
|
assertEquals(parsed.items.length, 2);
|
|
assertEquals(parsed.items[0].code, "PRE01");
|
|
assertEquals(parsed.items[0].quantity, 92);
|
|
assertEquals(parsed.items[0].amount, 920);
|
|
assertEquals(parsed.items[0].chapter, "BARDAS PERIMETRALES");
|
|
assertEquals(parsed.items[1].code, "EXC-001");
|
|
});
|
|
|
|
Deno.test("parsea plantilla con columna CAPITULO", () => {
|
|
const parsed = parseBudgetRows([
|
|
["CAPITULO", "CLAVE", "DESCRIPCION", "UNIDAD", "CANTIDAD", "PRECIO", "IMPORTE"],
|
|
["Acabados", "ACA01", "Aplanado", "M2", 10, 20, 200],
|
|
["Cimentacion", "CIM01", "Zapata", "PZA", 2, 100, 200],
|
|
]);
|
|
assertEquals(parsed.items.map((item) => item.chapter), ["Acabados", "Cimentacion"]);
|
|
assertEquals(parsed.items[0].amount, 200);
|
|
});
|
|
|
|
Deno.test("lee importes con coma o signo", () => {
|
|
assertEquals(parseMoney("$ 1,500.00"), 1500);
|
|
assertEquals(parseMoney("201.47"), 201.47);
|
|
});
|
|
|
|
Deno.test("parsea Opus/Neodata: agrupadores, continuaciones y totales ignorados", () => {
|
|
const parsed = parseBudgetRows([
|
|
["Código", "Concepto", "Unidad", "Cantidad", "P. Unitario", "Importe", "%"],
|
|
["A", "LOCAL L224", "", "", "", "", ""],
|
|
["A001", "PRELIMINARES Y ALBAÑILERÍA", "", "", "", "", ""],
|
|
["10301-001", "Trazo y nivelación manual para establecer ejes, banco", "M2", 61.9, 15.53, 961.31, 0.000847],
|
|
["", "de nivel y referencias, incluye: materiales, mano de", "", 0, 0, 0, 0],
|
|
["", "obra, equipo y herramienta.", "", 0, 0, 0, 0],
|
|
["A001", "TOTAL PRELIMINARES Y ALBAÑILERÍA", "", "", "", 123219.19, 0.1],
|
|
["", "IVA 16.00%", "", "", "", 181433.44, ""],
|
|
["", "TOTAL DEL PRESUPUESTO MOSTRADO:", "", "", "", 1315392.47, ""],
|
|
]);
|
|
assertEquals(parsed.items.length, 1);
|
|
assertEquals(parsed.groups.map((group) => group.code), ["A", "A001"]);
|
|
assertEquals(parsed.groups[0].kind, "lote");
|
|
assertEquals(parsed.groups[1].parentWbs, parsed.groups[0].wbs);
|
|
assertEquals(parsed.items[0].code, "10301-001");
|
|
assertEquals(parsed.items[0].chapter, "PRELIMINARES Y ALBAÑILERÍA");
|
|
assertEquals(parsed.items[0].parentWbs, parsed.groups[1].wbs);
|
|
assertStringIncludes(parsed.items[0].description, "Trazo y nivelación manual");
|
|
assertStringIncludes(parsed.items[0].description, "banco de nivel y referencias");
|
|
assertStringIncludes(parsed.items[0].description, "equipo y herramienta");
|
|
});
|
|
|
|
Deno.test("parsea plantilla WBS lote-capitulo-concepto", () => {
|
|
const parsed = parseBudgetRows([
|
|
["WBS", "TIPO", "CODIGO", "DESCRIPCION", "UNIDAD", "CANTIDAD", "PRECIO"],
|
|
["1", "lote", "A", "LOCAL L224", "", "", ""],
|
|
["1.01", "capitulo", "A001", "Preliminares y albañilería", "", "", ""],
|
|
["1.01.01", "concepto", "10301-001", "Trazo y nivelación manual", "M2", 61.9, 15.53],
|
|
["1.02", "capitulo", "A002", "Instalación hidrosanitaria", "", "", ""],
|
|
["1.02.01", "concepto", "11402-001", "Inodoro", "PZA", 1, 100],
|
|
]);
|
|
assertEquals(parsed.groups.length, 3);
|
|
assertEquals(parsed.groups[0].kind, "lote");
|
|
assertEquals(parsed.groups[1].parentWbs, "1");
|
|
assertEquals(parsed.items.length, 2);
|
|
assertEquals(parsed.items[0].parentWbs, "1.01");
|
|
assertEquals(parsed.items[0].chapter, "Preliminares y albañilería");
|
|
assertEquals(parsed.items[1].parentWbs, "1.02");
|
|
assertEquals(parsed.items[0].amount, 961.31);
|
|
});
|
|
|
|
Deno.test("la plantilla es un xlsx valido", () => {
|
|
const bytes = buildBudgetTemplate();
|
|
assertEquals(bytes[0], 0x50);
|
|
assertEquals(bytes[1], 0x4b);
|
|
const wb = XLSX.read(bytes, { type: "array" });
|
|
assertEquals(wb.SheetNames.includes("PRESUPUESTO"), true);
|
|
assertEquals(wb.SheetNames.includes("INSTRUCCIONES"), true);
|
|
});
|
|
|
|
Deno.test("preview de plantilla no guarda y arma arbol", () => {
|
|
const preview = previewBudgetExcel(buildBudgetTemplate());
|
|
assertEquals(preview.format, "wbs");
|
|
assertEquals(preview.errors.length, 0);
|
|
assertEquals(preview.tree[0]?.code, "A");
|
|
assertEquals(preview.tree[0]?.children.length, 2);
|
|
assertEquals(preview.totals.item_count, 4);
|
|
});
|