Board: Suche entlaggt, Order-Sprung, Versandadresse, Motiv-Hinweis; Mail: tägliche Statusübersicht
produktion: - Empfängersuche entlaggt (uncontrolled Input + 250ms-Debounce + vorab kleingeschriebenes Haystack) - kein Full-Rerender je Tastendruck mehr. - "Auftrag öffnen"-Link je Karte (-> Directus-Order, neuer Tab). - Sammelversand: Lieferadresse direkt auf der Karte (abweichende Order- Lieferadresse -> Kunden-Liefer-/Rechnungsadresse als Fallback). - Postkarten-Motiv wird als Badge hervorgehoben. mailer: - API-Einzelzusammenfassung entfernt; stattdessen taegliche Gesamtuebersicht um 03:00 ueber ALLE Auftraege inkl. Mengen je Produktionsstatus. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -260,44 +260,59 @@ export default (register, { services, getSchema, logger }) => {
|
||||
}
|
||||
});
|
||||
|
||||
// ── Tagesübersicht der API-Aufträge (statt Einzelmail je Auftrag) ───────────
|
||||
// Einmal täglich (Default 18:00): pro API-Kunde eine Zusammenfassung der heute
|
||||
// eingegangenen Aufträge, aufgeschlüsselt nach Versandtag.
|
||||
const API_DIGEST_CRON = process.env.SKRIFT_API_DIGEST_CRON || '0 18 * * *';
|
||||
register.schedule(API_DIGEST_CRON, async () => {
|
||||
// ── Tägliche Gesamtübersicht (03:00) – alle Aufträge nach Produktionsstatus ──
|
||||
// Ersetzt die frühere API-Einzelzusammenfassung: jeden Morgen eine Übersicht
|
||||
// ALLER Bestellungen inkl. Mengen (Schriftstücke) je Status. Keine separate
|
||||
// API-Zusammenfassung mehr.
|
||||
const UEBERSICHT_CRON = process.env.SKRIFT_UEBERSICHT_CRON || '0 3 * * *';
|
||||
const PSTATUS_ORDER = [
|
||||
['eingegangen', 'Eingegangen / Neu'],
|
||||
['im_druck', 'Im Druck'],
|
||||
['kuvertieren', 'Kuvertierung'],
|
||||
['versandfertig', 'Versandfertig'],
|
||||
['versendet', 'Versendet'],
|
||||
['storniert', 'Storniert'],
|
||||
];
|
||||
register.schedule(UEBERSICHT_CRON, async () => {
|
||||
try {
|
||||
const schema = await getSchema();
|
||||
const to = await teamEmpfaenger(schema);
|
||||
if (!to) return;
|
||||
const settings = await loadSettings(schema);
|
||||
const start = new Date(); start.setHours(0, 0, 0, 0);
|
||||
const orders = await new ItemsService('orders', { schema, accountability: null }).readByQuery({
|
||||
filter: { _and: [{ source: { _eq: 'api' } }, { date_created: { _gte: start.toISOString() } }] },
|
||||
fields: ['order_number', 'shipping_day', 'api_client.id', 'api_client.name', 'product.name'],
|
||||
limit: -1, sort: ['order_number'],
|
||||
fields: ['production_status', 'entries_count'], limit: -1,
|
||||
});
|
||||
if (!orders || !orders.length) return;
|
||||
|
||||
const byClient = new Map();
|
||||
for (const o of orders) {
|
||||
const kid = o.api_client?.id ?? 'x';
|
||||
let g = byClient.get(kid);
|
||||
if (!g) { g = { name: o.api_client?.name || 'API-Kunde', orders: [] }; byClient.set(kid, g); }
|
||||
g.orders.push(o);
|
||||
const agg = {};
|
||||
let gesamtA = 0, gesamtM = 0;
|
||||
for (const o of (orders || [])) {
|
||||
const st = o.production_status || 'eingegangen';
|
||||
if (!agg[st]) agg[st] = { auftraege: 0, menge: 0 };
|
||||
agg[st].auftraege += 1; agg[st].menge += Number(o.entries_count) || 0;
|
||||
gesamtA += 1; gesamtM += Number(o.entries_count) || 0;
|
||||
}
|
||||
for (const g of byClient.values()) {
|
||||
const byDay = {};
|
||||
for (const o of g.orders) { const d = o.shipping_day || 'ohne Versandtag'; byDay[d] = (byDay[d] || 0) + 1; }
|
||||
const zeilen = Object.entries(byDay).map(([d, n]) => `<li>${esc(d)}: <strong>${n}</strong></li>`).join('');
|
||||
const html = `<p>Heute über die API eingegangen von <strong>${esc(g.name)}</strong>: <strong>${g.orders.length}</strong> Auftrag/Aufträge.</p>`
|
||||
+ `<p>Nach Versandtag:</p><ul>${zeilen}</ul>`
|
||||
+ '<p>Im Produktions-Board unter „Neu" als Charge(n) gruppiert.</p>';
|
||||
const nachricht = { to, subject: `API-Tagesübersicht ${g.name} – ${g.orders.length} neue`, html, text: htmlZuText(html), replyTo: REPLY_TO };
|
||||
if (settings.sender_email) nachricht.from = settings.sender_name ? `${settings.sender_name} <${settings.sender_email}>` : settings.sender_email;
|
||||
try { await new MailService({ schema, accountability: null }).send(nachricht); }
|
||||
catch (e) { logger.warn(`[skrift-mailer] API-Tagesmail ${g.name}: ${e.message}`); }
|
||||
}
|
||||
logger.info(`[skrift-mailer] API-Tagesübersicht verschickt: ${byClient.size} Kunde(n)`);
|
||||
} catch (e) { logger.warn(`[skrift-mailer] API-Tageslauf: ${e.message}`); }
|
||||
// Bekannte Status in sinnvoller Reihenfolge, unbekannte hinten anhängen.
|
||||
const reihen = [...PSTATUS_ORDER];
|
||||
for (const st of Object.keys(agg)) if (!reihen.some(([k]) => k === st)) reihen.push([st, st]);
|
||||
const td = 'padding:4px 10px;';
|
||||
const zeilen = reihen.filter(([k]) => agg[k]).map(([k, label]) =>
|
||||
`<tr><td style="${td}">${esc(label)}</td>`
|
||||
+ `<td style="${td}text-align:right;"><strong>${agg[k].auftraege}</strong></td>`
|
||||
+ `<td style="${td}text-align:right;">${agg[k].menge}</td></tr>`).join('');
|
||||
const heute = new Date().toLocaleDateString('de-DE');
|
||||
const html = `<p>Gesamtübersicht aller Aufträge (Stand ${esc(heute)}):</p>`
|
||||
+ '<table style="border-collapse:collapse;font-size:14px;">'
|
||||
+ `<thead><tr><th style="text-align:left;${td}border-bottom:1px solid #ccc;">Status</th>`
|
||||
+ `<th style="text-align:right;${td}border-bottom:1px solid #ccc;">Aufträge</th>`
|
||||
+ `<th style="text-align:right;${td}border-bottom:1px solid #ccc;">Schriftstücke</th></tr></thead>`
|
||||
+ `<tbody>${zeilen || `<tr><td style="${td}" colspan="3">Keine Aufträge.</td></tr>`}</tbody>`
|
||||
+ `<tfoot><tr><td style="${td}border-top:2px solid #333;"><strong>Gesamt</strong></td>`
|
||||
+ `<td style="${td}text-align:right;border-top:2px solid #333;"><strong>${gesamtA}</strong></td>`
|
||||
+ `<td style="${td}text-align:right;border-top:2px solid #333;"><strong>${gesamtM}</strong></td></tr></tfoot>`
|
||||
+ '</table>';
|
||||
const nachricht = { to, subject: `Auftragsübersicht ${heute} – ${gesamtA} Aufträge`, html, text: htmlZuText(html), replyTo: REPLY_TO };
|
||||
if (settings.sender_email) nachricht.from = settings.sender_name ? `${settings.sender_name} <${settings.sender_email}>` : settings.sender_email;
|
||||
await new MailService({ schema, accountability: null }).send(nachricht);
|
||||
logger.info(`[skrift-mailer] Auftragsübersicht verschickt: ${gesamtA} Aufträge in ${Object.keys(agg).length} Status`);
|
||||
} catch (e) { logger.warn(`[skrift-mailer] Übersicht-Tageslauf: ${e.message}`); }
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user