Files
SDS-CRM/scripts/import-anlagen-itt.mjs
2026-03-22 19:26:35 +01:00

157 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { randomUUID } from 'crypto';
import fs from 'fs';
import path from 'path';
import { DatabaseSync } from 'node:sqlite';
import { fileURLToPath } from 'url';
import XLSX from 'xlsx';
import dotenv from 'dotenv';
dotenv.config();
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const root = path.join(__dirname, '..');
const xlsxPath = path.join(root, 'Anlagenliste ITT.xlsx');
const dbPath = process.env.SQLITE_PATH || path.join(root, 'data', 'crm.db');
/** Zeile 9 (1-basiert): Spaltenbeschriftung / Feldnamen */
const ZEILE_BESCHREIBUNG = 9;
/** Zeile 7: Gruppierung / übergeordnete Rubrik pro Spalte (z. B. „Kunde“) */
const ZEILE_GRUPPE = 7;
/** Nur Spalten 199 importieren; Spalten 100180 entfallen */
const MAX_SPALTEN = 99;
if (!fs.existsSync(xlsxPath)) {
console.error('Datei nicht gefunden:', xlsxPath);
process.exit(1);
}
function dedupeHeaders(raw) {
const count = {};
return raw.map((h) => {
const base = String(h ?? '').trim() || 'Spalte';
count[base] = (count[base] || 0) + 1;
return count[base] === 1 ? base : `${base}_${count[base]}`;
});
}
function padRow(arr, width) {
const a = Array.isArray(arr) ? [...arr] : [];
while (a.length < width) a.push('');
return a.slice(0, width);
}
const wb = XLSX.readFile(xlsxPath);
const sheet =
wb.Sheets.Anlagen ||
wb.Sheets[wb.SheetNames.find((n) => /anlagen/i.test(n))] ||
wb.Sheets[wb.SheetNames[0]];
const aoa = XLSX.utils.sheet_to_json(sheet, { header: 1, defval: '' });
const beschreibIdx = ZEILE_BESCHREIBUNG - 1;
const gruppeIdx = ZEILE_GRUPPE - 1;
let width = 0;
for (const r of [beschreibIdx, gruppeIdx]) {
if (aoa[r] && aoa[r].length > width) width = aoa[r].length;
}
if (sheet['!ref']) {
const range = XLSX.utils.decode_range(sheet['!ref']);
width = Math.max(width, range.e.c + 1);
}
width = Math.min(width, MAX_SPALTEN);
const rawRow9 = padRow(aoa[beschreibIdx] || [], width).map((h) =>
String(h ?? '').trim(),
);
const rawRow7 = padRow(aoa[gruppeIdx] || [], width).map((h) =>
String(h ?? '').trim(),
);
const headers = dedupeHeaders(rawRow9);
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
const db = new DatabaseSync(dbPath);
db.exec('PRAGMA foreign_keys = ON');
const cols = db.prepare('PRAGMA table_info(machines)').all();
if (!cols.some((c) => c.name === 'extras')) {
db.exec('ALTER TABLE machines ADD COLUMN extras TEXT');
}
const replaceAll = process.argv.includes('--replace');
if (replaceAll) {
db.exec('DELETE FROM events');
db.exec('DELETE FROM tickets');
db.exec('DELETE FROM machines');
console.log('Bestehende Maschinen/Tickets/Events gelöscht.');
}
const insertMachine = db.prepare(
`INSERT INTO machines (id, name, typ, seriennummer, standort, extras, updated_at)
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`,
);
let imported = 0;
let skipped = 0;
db.exec('BEGIN');
try {
for (let i = beschreibIdx + 1; i < aoa.length; i++) {
const row = aoa[i];
if (!row || !row.length) continue;
const padded = padRow(row, width);
const sn = String(padded[0] ?? '').trim();
if (!/^ITT#/i.test(sn)) continue;
const dup = db
.prepare('SELECT id FROM machines WHERE seriennummer = ?')
.get(sn);
if (dup) {
skipped += 1;
continue;
}
const rowObj = {};
headers.forEach((h, j) => {
const v = padded[j];
rowObj[h] =
v === '' || v === undefined || v === null ? '' : String(v).trim();
});
const typ = rowObj.Typ || '—';
const standort =
[rowObj.Stadt, rowObj.Land].filter(Boolean).join(', ') || '—';
const werteAlsListe = padded.map((v) =>
v === '' || v === undefined || v === null ? '' : String(v).trim(),
);
const extrasObj = {
_beschriftungZeile9: rawRow9,
_gruppeZeile7: rawRow7,
_werteAlsListe: werteAlsListe,
...rowObj,
};
const extrasJson = JSON.stringify(extrasObj);
const id = randomUUID();
insertMachine.run(id, sn, typ, sn, standort, extrasJson);
imported += 1;
}
db.exec('COMMIT');
} catch (e) {
db.exec('ROLLBACK');
throw e;
}
db.close();
console.log(
`Anlagenliste: ${imported} Maschinen importiert, ${skipped} übersprungen (Seriennr. schon vorhanden).`,
);
if (!replaceAll && skipped > 0 && imported === 0) {
console.log(
'Hinweis: Für Neuimport: npm run import:anlagen -- --replace',
);
}