- ✅ Node.js/Express Server mit DOCX Template-Verarbeitung - ✅ Automatische Tag-Erkennung und Demo-Daten-Generierung - ✅ Tabellen-Unterstützung mit Schleifen-Tags - ✅ REST-API /api/process-template für externe Integration - ✅ Web-Oberfläche mit vollständiger Dokumentation - ✅ SSL-Unterstützung (HTTPS Port 443 öffentlich) - ✅ Intelligente Spaltenerkennung für Tabellen - ✅ Detaillierte Statusmeldungen für alle Operationen - ✅ Flexible Custom-Daten + Auto-Generierung - ✅ Template- und Dokument-Management APIs
355 lines
12 KiB
JavaScript
355 lines
12 KiB
JavaScript
const PizZip = require('pizzip');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
// Erstelle ein Template mit professioneller Tabelle für docxtemplater
|
|
function createTableTemplate() {
|
|
const zip = new PizZip();
|
|
|
|
// Content Types
|
|
zip.file('[Content_Types].xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
|
|
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
|
|
<Default Extension="xml" ContentType="application/xml"/>
|
|
<Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
|
|
<Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/>
|
|
</Types>`);
|
|
|
|
// Main relationships
|
|
zip.file('_rels/.rels', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml"/>
|
|
</Relationships>`);
|
|
|
|
// Document relationships
|
|
zip.file('word/_rels/document.xml.rels', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
|
|
<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>
|
|
</Relationships>`);
|
|
|
|
// Styles
|
|
zip.file('word/styles.xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
|
<w:docDefaults>
|
|
<w:rPrDefault>
|
|
<w:rPr>
|
|
<w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
|
|
<w:sz w:val="22"/>
|
|
<w:szCs w:val="22"/>
|
|
<w:lang w:val="de-DE"/>
|
|
</w:rPr>
|
|
</w:rPrDefault>
|
|
</w:docDefaults>
|
|
</w:styles>`);
|
|
|
|
// Document content optimiert für docxtemplater
|
|
zip.file('word/document.xml', `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
|
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
|
|
<w:body>
|
|
<!-- Erste Seite: Kopfdaten -->
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="center"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:rPr>
|
|
<w:b/>
|
|
<w:sz w:val="32"/>
|
|
</w:rPr>
|
|
<w:t>RECHNUNG</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p/>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Firma: {firma}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Ansprechpartner: {vorname} {nachname}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>E-Mail: {email}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Adresse: {adresse}, {plz} {stadt}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Rechnungsdatum: {datum}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Rechnungsnummer: {nummer}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<!-- Seitenumbruch -->
|
|
<w:p>
|
|
<w:r>
|
|
<w:br w:type="page"/>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<!-- Zweite Seite: Tabelle -->
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="center"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:rPr>
|
|
<w:b/>
|
|
<w:sz w:val="24"/>
|
|
</w:rPr>
|
|
<w:t>RECHNUNGSPOSITIONEN</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p/>
|
|
|
|
<!-- Tabelle für docxtemplater optimiert -->
|
|
<w:tbl>
|
|
<w:tblPr>
|
|
<w:tblStyle w:val="TableGrid"/>
|
|
<w:tblW w:w="5000" w:type="pct"/>
|
|
<w:tblBorders>
|
|
<w:top w:val="single" w:sz="6" w:space="0" w:color="000000"/>
|
|
<w:left w:val="single" w:sz="6" w:space="0" w:color="000000"/>
|
|
<w:bottom w:val="single" w:sz="6" w:space="0" w:color="000000"/>
|
|
<w:right w:val="single" w:sz="6" w:space="0" w:color="000000"/>
|
|
<w:insideH w:val="single" w:sz="6" w:space="0" w:color="000000"/>
|
|
<w:insideV w:val="single" w:sz="6" w:space="0" w:color="000000"/>
|
|
</w:tblBorders>
|
|
</w:tblPr>
|
|
|
|
<w:tblGrid>
|
|
<w:gridCol w:w="1000"/>
|
|
<w:gridCol w:w="3000"/>
|
|
<w:gridCol w:w="1500"/>
|
|
<w:gridCol w:w="1500"/>
|
|
</w:tblGrid>
|
|
|
|
<!-- Kopfzeile -->
|
|
<w:tr>
|
|
<w:tc>
|
|
<w:tcPr>
|
|
<w:shd w:val="clear" w:color="auto" w:fill="CCCCCC"/>
|
|
<w:tcW w:w="1000" w:type="dxa"/>
|
|
</w:tcPr>
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="center"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Pos.</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:tcPr>
|
|
<w:shd w:val="clear" w:color="auto" w:fill="CCCCCC"/>
|
|
<w:tcW w:w="3000" w:type="dxa"/>
|
|
</w:tcPr>
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="center"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Beschreibung</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:tcPr>
|
|
<w:shd w:val="clear" w:color="auto" w:fill="CCCCCC"/>
|
|
<w:tcW w:w="1500" w:type="dxa"/>
|
|
</w:tcPr>
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="center"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Betrag (EUR)</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:tcPr>
|
|
<w:shd w:val="clear" w:color="auto" w:fill="CCCCCC"/>
|
|
<w:tcW w:w="1500" w:type="dxa"/>
|
|
</w:tcPr>
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="center"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Datum</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
</w:tr>
|
|
|
|
<!-- Datenzeilen mit docxtemplater Loop -->
|
|
<w:tr>
|
|
<w:tc>
|
|
<w:p>
|
|
<w:r>
|
|
<w:t>{#items}{items_position}{/items}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:p>
|
|
<w:r>
|
|
<w:t>{items_name}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="right"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:t>{items_value}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="center"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:t>{items_date}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
</w:tr>
|
|
|
|
<!-- Summenzeile -->
|
|
<w:tr>
|
|
<w:tc>
|
|
<w:tcPr>
|
|
<w:shd w:val="clear" w:color="auto" w:fill="EEEEEE"/>
|
|
</w:tcPr>
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="center"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>∑</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:tcPr>
|
|
<w:shd w:val="clear" w:color="auto" w:fill="EEEEEE"/>
|
|
</w:tcPr>
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>GESAMTBETRAG</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:tcPr>
|
|
<w:shd w:val="clear" w:color="auto" w:fill="EEEEEE"/>
|
|
</w:tcPr>
|
|
<w:p>
|
|
<w:pPr>
|
|
<w:jc w:val="right"/>
|
|
</w:pPr>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>{betrag}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
<w:tc>
|
|
<w:tcPr>
|
|
<w:shd w:val="clear" w:color="auto" w:fill="EEEEEE"/>
|
|
</w:tcPr>
|
|
<w:p>
|
|
<w:r>
|
|
<w:t></w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:tc>
|
|
</w:tr>
|
|
</w:tbl>
|
|
|
|
<w:p/>
|
|
<w:p/>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>Bemerkungen:</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:t>{beschreibung}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p/>
|
|
<w:p/>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:t>Mit freundlichen Grüßen</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
|
|
<w:p>
|
|
<w:r>
|
|
<w:rPr><w:b/></w:rPr>
|
|
<w:t>{firma}</w:t>
|
|
</w:r>
|
|
</w:p>
|
|
</w:body>
|
|
</w:document>`);
|
|
|
|
return zip.generate({ type: 'nodebuffer' });
|
|
}
|
|
|
|
// Erstelle das Template
|
|
const templateBuffer = createTableTemplate();
|
|
const templatePath = path.join(__dirname, 'templates', 'rechnung_mit_tabelle.docx');
|
|
|
|
fs.writeFileSync(templatePath, templateBuffer);
|
|
console.log('Template mit Tabelle erstellt:', templatePath);
|
|
console.log('Features:');
|
|
console.log('- Erste Seite: Rechnungskopf');
|
|
console.log('- Zweite Seite: Professionelle Tabelle mit Spalten für Position, Beschreibung, Betrag und Datum');
|
|
console.log('- Automatische Positionsnummerierung');
|
|
console.log('- Summenzeile am Ende der Tabelle'); |