import fs from "node:fs/promises"; import { FileBlob, SpreadsheetFile } from "@oai/artifact-tool"; const inputPath = "C:/Users/milu/OneDrive - Exxeta/Dokumente/Assessor Zeiterfassung/ASSESSOR_Zeiterfassung_Sep2026_Jul2027_Form_wie_vorher.xlsx"; const outputDir = "C:/Users/milu/OneDrive - Exxeta/Dokumente/VS CODE/ASSESSOR-2-5/outputs/01a089e9-f688-7f21-87c9-db223e98841f"; const outputPath = `${outputDir}/ASSESSOR_Zeiterfassung_Aug2026_Jul2027_aktualisiert.xlsx`; const workbook = await SpreadsheetFile.importXlsx(await FileBlob.load(inputPath)); // The supplied workbook starts in September. Add August using the existing // 31-day October sheet as the structural and formatting reference. const october = workbook.worksheets.getItem("Oktober 2026"); const august = workbook.worksheets.add("August 2026"); august.getRange("A1:AH5").copyFrom(october.getRange("A1:AH5"), "all"); // Normalize all date columns to the existing weekday style, then apply the // existing Saturday/Sunday pair style to the five August weekends. for (let col = 2; col <= 32; col += 1) { august.getRangeByIndexes(0, col, 4, 1).copyFrom(october.getRange("C1:C4"), "all"); } for (const startCol of [2, 9, 16, 23, 30]) { august.getRangeByIndexes(0, startCol, 4, 2).copyFrom(october.getRange("E1:F4"), "all"); } const weekdayNames = ["Sa", "So", "Mo", "Di", "Mi", "Do", "Fr"]; for (let day = 1; day <= 31; day += 1) { const col = day + 1; august.getCell(0, col).values = [[day]]; august.getCell(1, col).values = [[weekdayNames[(day - 1) % 7]]]; august.getCell(2, col).clear({ applyTo: "contents" }); august.getCell(3, col).clear({ applyTo: "contents" }); } august.getRange("A1:B5").copyFrom(october.getRange("A1:B5"), "all"); august.getRange("AH1:AH5").copyFrom(october.getRange("AH1:AH5"), "all"); august.getRange("AH4").formulas = [["=SUM(C4:AG4)"]]; august.getRange("AH5").formulas = [["=AH4"]]; // Recreate the supplied visual grammar on the newly added sheet. Range copies // preserve content/formulas but not the source sheet's merged cells or widths. august.mergeCells("A3:B3"); august.mergeCells("A4:B4"); august.mergeCells("A5:AG5"); august.getRange("A1:AH5").format = { font: { name: "Carlito", size: 11, color: "#000000" }, verticalAlignment: "center", horizontalAlignment: "center", borders: { preset: "all", style: "thin", color: "#B7B7B7" }, }; august.getRange("A1:B1").format = { fill: "#00E640", font: { name: "Carlito", size: 12, bold: true, color: "#000000" }, horizontalAlignment: "center", }; august.getRange("A2:B2").format = { fill: "#D9EAD3", font: { name: "Carlito", size: 11, bold: true, color: "#000000" }, horizontalAlignment: "center", }; august.getRange("A3:B4").format = { fill: "#E7E6E6", font: { name: "Carlito", size: 11, bold: true, color: "#000000" }, horizontalAlignment: "center", verticalAlignment: "center", }; august.getRange("A5:AH5").format = { fill: "#D9EAD3", font: { name: "Carlito", size: 11, bold: true, color: "#000000" }, horizontalAlignment: "center", }; august.getRange("C1:AG2").format = { fill: "#FFFACD", font: { name: "Carlito", size: 11, bold: true, color: "#000000" }, horizontalAlignment: "center", }; august.getRange("C3:AG4").format = { fill: "#FFFFFF", font: { name: "Carlito", size: 11, color: "#000000" }, horizontalAlignment: "center", verticalAlignment: "top", }; for (const weekend of ["C1:D4", "J1:K4", "Q1:R4", "X1:Y4", "AE1:AF4"]) { august.getRange(weekend).format = { fill: "#2E65A3", font: { name: "Carlito", size: 11, bold: true, color: "#FFFFFF" }, horizontalAlignment: "center", verticalAlignment: "center", wrapText: true, }; } august.getRange("AH1:AH4").format = { fill: "#FFF2CC", font: { name: "Carlito", size: 11, bold: true, color: "#000000" }, horizontalAlignment: "center", }; august.getRange("A1:B5").format.columnWidthPx = 110; august.getRange("C1:AG5").format.columnWidthPx = 108; august.getRange("AH1:AH5").format.columnWidthPx = 118; august.getRange("A1:AH1").format.rowHeightPx = 22; august.getRange("A2:AH2").format.rowHeightPx = 22; august.getRange("A3:AH3").format.rowHeightPx = 96; august.getRange("A4:AH5").format.rowHeightPx = 24; const augustEntries = { 24: { task: "Repo-Import; PingCastle-Mapping; Dashboard; PostgreSQL/CI", hours: 7 }, 26: { task: "UI-Anpassungen; Purple Knight/PingCastle HTML-Import", hours: 7.5 }, }; for (const [dayText, entry] of Object.entries(augustEntries)) { const col = Number(dayText) + 1; august.getCell(2, col).values = [[entry.task]]; august.getCell(3, col).values = [[entry.hours]]; } august.getRange("C3:AG3").format.wrapText = true; august.getRange("C3:AG3").format.verticalAlignment = "top"; august.getRange("C3:AG3").format.rowHeightPx = 96; august.getRange("C4:AG4").format.numberFormat = "0.0"; august.getRange("AH4:AH5").format.numberFormat = "0.0"; const september = workbook.worksheets.getItem("September 2026"); const septemberEntries = { 3: { task: "Client Info; GPO-Regeln und Analysepfad; Tests", hours: 5 }, 4: { task: "GPO-Import robuster; nicht lesbare Einträge behandelt", hours: 9.5 }, 6: { task: "GPO-Auswertung testbereit; UI/Pfade; Regressionstests", hours: 9 }, 7: { task: "Scan-Navigation; GPO-Duplikate und Ergebnisabgleich", hours: 4 }, 8: { task: "GPO-Quellen konsolidiert; Historie und Tests", hours: 7 }, 9: { task: "Import-Timeout; Navigation-Performance; Tests/Build", hours: 8 }, }; for (const [dayText, entry] of Object.entries(septemberEntries)) { const col = Number(dayText) + 1; september.getCell(2, col).values = [[entry.task]]; september.getCell(3, col).values = [[entry.hours]]; } september.getRange("C3:AF3").format.wrapText = true; september.getRange("C3:AF3").format.verticalAlignment = "top"; september.getRange("C3:AF3").format.rowHeightPx = 96; september.getRange("C4:AF4").format.numberFormat = "0.0"; september.getRange("AG4:AG5").format.numberFormat = "0.0"; workbook.recalculate(); const checks = []; for (const range of ["August 2026!A1:AH5", "September 2026!A1:AG5"]) { const check = await workbook.inspect({ kind: "table", range, include: "values,formulas", tableMaxRows: 5, tableMaxCols: 40, maxChars: 12000, }); checks.push(check.ndjson); } console.log(checks.join("\n")); const errors = await workbook.inspect({ kind: "match", searchTerm: "#REF!|#DIV/0!|#VALUE!|#NAME\\?|#N/A|#NUM!|#NULL!|#SPILL!|#CALC!", options: { useRegex: true, maxResults: 300 }, summary: "final formula error scan", }); console.log(errors.ndjson); for (const sheetName of ["August 2026", "September 2026"]) { const preview = await workbook.render({ sheetName, autoCrop: "all", scale: 1, format: "png" }); await fs.writeFile(`${outputDir}/updated_${sheetName.replace(/[^a-z0-9_-]+/gi, "_")}.png`, new Uint8Array(await preview.arrayBuffer())); } await fs.mkdir(outputDir, { recursive: true }); const output = await SpreadsheetFile.exportXlsx(workbook); await output.save(outputPath); console.log(`OUTPUT\t${outputPath}`);