Assessor_2.0/outputs/01a089e9-f688-7f21-87c9-db2.../update_timesheet.mjs

171 lines
6.9 KiB
JavaScript

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}`);