Motiv-Entwurf eingepasst (meet, in Trim-Fläche) + sevDesk-Diagnose-Logs

- Motiv-A6-Layout: Motiv vollständig in 148×105 eingepasst (meet, mittig) auf
  weißem A6-Grund statt randabfallend beschnitten (slice).
- skrift-sevdesk: Lade-Log (Token gesetzt/fehlt) + Logs je Auftrag (source-Gate,
  bereits erstellt) zur Diagnose, warum ggf. nichts erzeugt wird.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
s4luorth
2026-09-18 11:48:09 +02:00
parent 2c9ffbbc9b
commit f4ce602b7a
2 changed files with 15 additions and 5 deletions

View File

@@ -211,9 +211,11 @@ const handler = (router, { services, getSchema, logger }) => {
if (!meta?.filename_disk) throw new Error(`Motiv-Datei ${fileId} nicht gefunden.`); if (!meta?.filename_disk) throw new Error(`Motiv-Datei ${fileId} nicht gefunden.`);
const base64 = fs.readFileSync(path.join(UPLOAD_ROOT, meta.filename_disk)).toString('base64'); const base64 = fs.readFileSync(path.join(UPLOAD_ROOT, meta.filename_disk)).toString('base64');
const mime = meta.type || 'image/png'; const mime = meta.type || 'image/png';
// A6 quer randabfallend: Motiv füllt die volle Beschnittfläche (cover), mittig. // A6 quer: Motiv wird VOLLSTÄNDIG in die Trim-Fläche (148×105) eingepasst
// (mittig, nichts beschnitten) auf weißem A6-Grund inkl. 2 mm Beschnitt.
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="152mm" height="109mm" viewBox="0 0 152 109">` const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="152mm" height="109mm" viewBox="0 0 152 109">`
+ `<image href="data:${mime};base64,${base64}" x="0" y="0" width="152" height="109" preserveAspectRatio="xMidYMid slice"/>` + `<rect x="0" y="0" width="152" height="109" fill="#ffffff"/>`
+ `<image href="data:${mime};base64,${base64}" x="2" y="2" width="148" height="105" preserveAspectRatio="xMidYMid meet"/>`
+ `</svg>`; + `</svg>`;
const files = new FilesService({ schema, accountability: null }); const files = new FilesService({ schema, accountability: null });
const storage = (process.env.STORAGE_LOCATIONS || 'local').split(',')[0].trim() || 'local'; const storage = (process.env.STORAGE_LOCATIONS || 'local').split(',')[0].trim() || 'local';

View File

@@ -138,8 +138,11 @@ export default (register, { services, getSchema, logger }) => {
'customer.company', 'customer.phone', 'customer.sevdesk_contact_id'], 'customer.company', 'customer.phone', 'customer.sevdesk_contact_id'],
}); });
if (!order) return; if (!order) return;
if (order.sevdesk_invoice_id) return; // schon erstellt if (order.sevdesk_invoice_id) { logger.info(`[skrift-sevdesk] ${order.order_number}: bereits erstellt (#${order.sevdesk_invoice_id}).`); return; }
if (!SOURCES.includes(String(order.source || ''))) return; // nur Konfigurator if (!SOURCES.includes(String(order.source || ''))) {
logger.info(`[skrift-sevdesk] ${order.order_number}: source="${order.source}" nicht in [${SOURCES.join(',')}] → übersprungen.`);
return;
}
const lines = Array.isArray(order.price_lines) ? order.price_lines : []; const lines = Array.isArray(order.price_lines) ? order.price_lines : [];
if (!lines.length || !(Number(order.net_total) > 0)) { if (!lines.length || !(Number(order.net_total) > 0)) {
logger.info(`[skrift-sevdesk] ${order.order_number}: keine Positionen/Betrag → keine Rechnung.`); logger.info(`[skrift-sevdesk] ${order.order_number}: keine Positionen/Betrag → keine Rechnung.`);
@@ -202,9 +205,14 @@ export default (register, { services, getSchema, logger }) => {
} }
} }
// Beim Laden einmal protokollieren, damit sichtbar ist, ob die Extension aktiv
// ist und ob der Token gesetzt wurde.
logger.info(`[skrift-sevdesk] geladen – Token ${TOKEN ? 'gesetzt' : 'FEHLT'}, sources=[${SOURCES.join(',')}], base=${BASE}`);
register.action('orders.items.create', async ({ key, keys }) => { register.action('orders.items.create', async ({ key, keys }) => {
if (!TOKEN) return; // ohne Token nichts tun
const ids = keys || (key != null ? [key] : []); const ids = keys || (key != null ? [key] : []);
if (!TOKEN) { logger.info(`[skrift-sevdesk] Auftrag ${ids.join(',')} – kein SEVDESK_API_TOKEN gesetzt, übersprungen.`); return; }
logger.info(`[skrift-sevdesk] orders.create → prüfe Auftrag/Aufträge ${ids.join(',')}`);
for (const id of ids) { for (const id of ids) {
try { await rechnungFuerAuftrag(id); } try { await rechnungFuerAuftrag(id); }
catch (e) { logger.error(`[skrift-sevdesk] Rechnung für Auftrag ${id} fehlgeschlagen: ${e.message}`); } catch (e) { logger.error(`[skrift-sevdesk] Rechnung für Auftrag ${id} fehlgeschlagen: ${e.message}`); }