From cc3f4fb758114f181e360bd69cd9d7f86457be3e Mon Sep 17 00:00:00 2001 From: Lucas Orth Date: Thu, 27 Aug 2026 09:42:10 +0200 Subject: [PATCH] Unterschriftenservice: Datei-Lesen von Platte (behebt transforms-Fehler), Marker-Token [[..]] statt paragraph, Breite/Versatz aus hinterlegter Signatur (Service + Brief) --- .../dist/index.js | 11 ++++++++--- .../dist/index.js | 19 +++++++++++-------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/extensions/directus-extension-skrift-neuauftrag/dist/index.js b/extensions/directus-extension-skrift-neuauftrag/dist/index.js index 9946265..be83be1 100644 --- a/extensions/directus-extension-skrift-neuauftrag/dist/index.js +++ b/extensions/directus-extension-skrift-neuauftrag/dist/index.js @@ -95,7 +95,7 @@ const NeuAuftrag = defineComponent({ api.get('/items/pricing_settings', { params: { fields: 'char_whitelist' } }).catch(() => ({ data: { data: {} } })), api.get('/items/muster_settings', { params: { fields: 'text_du,text_sie' } }).catch(() => ({ data: { data: {} } })), api.get('/items/muster_texts', { params: { limit: -1, filter: { active: { _eq: true } }, sort: 'sort', fields: 'id,label,text' } }).catch(() => ({ data: { data: [] } })), - api.get('/items/signatures', { params: { limit: -1, sort: '-date_created', fields: 'id,label,file,customer.first_name,customer.last_name' } }).catch(() => ({ data: { data: [] } })), + api.get('/items/signatures', { params: { limit: -1, sort: '-date_created', fields: 'id,label,file,marker_key,offset_x_mm,offset_y_mm,width_mm,customer.first_name,customer.last_name' } }).catch(() => ({ data: { data: [] } })), ]); produkte.value = p.data?.data || []; formate.value = f.data?.data || []; @@ -204,6 +204,9 @@ const NeuAuftrag = defineComponent({ const res = await api.get(`/assets/${s.file}`, { responseType: 'text' }); neu.sigSvg = typeof res.data === 'string' ? res.data : String(res.data || ''); neu.sigLabel = s.label || 'Unterschrift'; + // Versatz aus der hinterlegten Unterschrift übernehmen (X/Y in mm). + neu.sigX = Number(s.offset_x_mm) || 0; + neu.sigY = Number(s.offset_y_mm) || 0; sigEinfuegen(); } catch { neu.err = 'Signatur konnte nicht geladen werden.'; } } @@ -596,8 +599,10 @@ const NeuAuftrag = defineComponent({ function sigBestehendeWaehlen(id) { const s = signaturListe.value.find((x) => String(x.id) === String(id)); if (!s || !s.file) return; + // Breite/Versatz/Marker aus der hinterlegten Unterschrift übernehmen. sig.signaturen.push({ file_id: s.file, label: s.label || 'Unterschrift', aktiv: true, - marker_key: 'SIG' + (sig.signaturen.length + 1), position: 'genau', width_mm: 40, offset_x_mm: 0, offset_y_mm: 0 }); + marker_key: s.marker_key || ('SIG' + (sig.signaturen.length + 1)), position: 'genau', + width_mm: s.width_mm ?? 40, offset_x_mm: s.offset_x_mm ?? 0, offset_y_mm: s.offset_y_mm ?? 0 }); sig.pdf = ''; } async function sigSvgUpload(file) { @@ -657,7 +662,7 @@ const NeuAuftrag = defineComponent({ sig.docs.length > 1 ? h('div', { style: 'margin-top:12px;' }, [label('Dokument'), sel(sig.docId, sig.docs.map((d, i) => ({ v: d, t: `Dokument ${i + 1}` })), (e) => { sig.docId = e.target.value; sig.pdf = ''; })]) : null, ]) : h('div', {}, [ - label('Dokument (PDF mit Marker §§SIG…§§)'), + label('Dokument (PDF mit Marker [[SIG…]] – Token wie bei Brief-Platzhaltern)'), h('input', { type: 'file', accept: '.pdf', onChange: (e) => sigPdfUpload(e.target.files && e.target.files[0]), style: 'font-size:13px;' }), sig.docName ? subdued(`${sig.docName} hochgeladen.`, 'margin-top:6px;') : null, ]), diff --git a/extensions/directus-extension-skrift-orders/dist/index.js b/extensions/directus-extension-skrift-orders/dist/index.js index e968849..7cb881d 100644 --- a/extensions/directus-extension-skrift-orders/dist/index.js +++ b/extensions/directus-extension-skrift-orders/dist/index.js @@ -21,6 +21,8 @@ import path from 'node:path'; /** Basisordner der generierten Auftragsdateien (read-only in Directus gemountet). */ const OUTPUT_DIR = process.env.SKRIFT_OUTPUT_DIR || '/var/skrift-output'; +/** Directus-Upload-Ordner (lokaler Storage) – zum direkten Datei-Lesen. */ +const UPLOAD_ROOT = process.env.STORAGE_LOCAL_ROOT || '/directus/uploads'; // ── Sicherer Formel-Interpreter (kein eval) ───────────────────────────────── // Erlaubt: Zahlen, Variablen, + - * / ( ), unäres Minus, Vergleiche @@ -158,13 +160,14 @@ const handler = (router, { services, getSchema, logger }) => { // Signatur-Plotter-Service (intern über das npm-Netz per container_name erreichbar). const SIGN_URL = (process.env.SKRIFT_SIGN_URL || 'http://skrift-signature-service:8000').replace(/\/$/, ''); - /** Liest eine Directus-Datei (Upload) serverseitig als Buffer. */ + /** Liest eine Directus-Datei (Upload) serverseitig als Buffer – direkt von der + * Platte (lokaler Storage), wie der Mailer. Vermeidet AssetsService.getAsset, + * dessen Signatur je nach Directus-Version „transforms"-Fehler wirft. */ async function dateiBytes(schema, id) { - const assets = new AssetsService({ schema, accountability: null }); - const { stream } = await assets.getAsset(id, {}); - const chunks = []; - for await (const c of stream) chunks.push(c); - return Buffer.concat(chunks); + const f = await new ItemsService('directus_files', { schema, accountability: null }) + .readOne(id, { fields: ['filename_disk'] }); + if (!f?.filename_disk) throw new Error(`Datei ${id} nicht gefunden.`); + return fs.readFileSync(path.join(UPLOAD_ROOT, f.filename_disk)); } /** Baut die Multipart-Anfrage an den Signatur-Service (Vorschau/Render). */ @@ -179,9 +182,9 @@ const handler = (router, { services, getSchema, logger }) => { const svgBytes = await dateiBytes(schema, s.file_id); const svgName = `sig${i + 1}.svg`; form.append('svgs', new Blob([svgBytes], { type: 'image/svg+xml' }), svgName); - const marker = String(s.marker_key || `SIG${i + 1}`).replace(/§/g, '').trim(); + const marker = String(s.marker_key || `SIG${i + 1}`).replace(/[§[\]]/g, '').trim(); jobs.push({ - token: `§§${marker}§§`, + token: `[[${marker}]]`, svg_id: svgName, position: ['genau', 'ueber', 'unter'].includes(s.position) ? s.position : 'genau', breite_mm: Number(s.width_mm) > 0 ? Number(s.width_mm) : 45,