171 lines
6.9 KiB
JavaScript
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}`);
|