Revert Backend-Laender-Split: Auftrag bleibt einer (Trennung nur als Anzeige in Directus geplant)

zielInland()-Erkennung bleibt fuer count_inland/count_ausland und die kommende
Anzeige-/Druck-Trennung im Produktions-Board. Kein zweiter Auftragsdatensatz mehr.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
s4luorth
2026-09-03 10:35:10 +02:00
parent 2b575fa540
commit b76e01d10a

View File

@@ -1592,16 +1592,9 @@ const handler = (router, { services, getSchema, logger }) => {
const jt = new Date();
const praefix = `${String(jt.getDate()).padStart(2, '0')}-${String(jt.getMonth() + 1).padStart(2, '0')}-${String(jt.getFullYear()).slice(2)}`;
// Freie Basis-Nummer; prüft auch die Split-Varianten -DE / -INT auf Kollision.
const freieBasis = async () => {
const naechsteNummer = async () => {
const heutige = await svc('orders').readByQuery({ filter: { order_number: { _starts_with: `${praefix}-` } }, limit: -1, fields: ['id'] });
let n = (heutige?.length ?? 0) + 1;
for (let v = 0; v < 30; v += 1, n += 1) {
const basis = `${praefix}-${String(n).padStart(3, '0')}`;
const koll = await svc('orders').readByQuery({ filter: { order_number: { _in: [basis, `${basis}-DE`, `${basis}-INT`] } }, limit: 1, fields: ['id'] });
if (!koll?.length) return basis;
}
throw new Error('Keine freie Auftragsnummer gefunden.');
return `${praefix}-${String((heutige?.length ?? 0) + 1).padStart(3, '0')}`;
};
const orderData = {
@@ -1634,54 +1627,38 @@ const handler = (router, { services, getSchema, logger }) => {
net_total: quote?.net_total ?? null, vat_amount: quote?.vat_amount ?? null, gross_total: quote?.gross_total ?? null,
};
const entryFelder = (e, nr) => ({
letter_number: nr,
salutation: clean(e.salutation) ?? null, first_name: clean(e.first_name) ?? null, last_name: clean(e.last_name) ?? null,
street: clean(e.street) ?? null, house_no: clean(e.house_no) ?? null, zip: clean(e.zip) ?? null,
city: clean(e.city) ?? null, country: clean(e.country) ?? null, free_text: clean(e.free_text) ?? null,
placeholders: e.placeholders && typeof e.placeholders === 'object'
? Object.fromEntries(Object.entries(e.placeholders).map(([k, v]) => [k, clean(String(v))])) : null,
});
const entriesSvc = svc('order_entries');
// Länder-Split: sobald DE- UND Welt-Empfänger vorkommen → zwei getrennte
// Aufträge (-DE / -INT), sonst ein Auftrag ohne Suffix. Gilt für Schriftstücke UND Kuverts.
const deEntries = entries.filter((e) => istInland(e));
const intEntries = entries.filter((e) => !istInland(e));
const gemischt = deEntries.length > 0 && intEntries.length > 0;
const anlegen = async (subEntries, nummer, gebiet) => {
const auslandN = subEntries.filter((e) => !istInland(e)).length;
let q = null;
try { q = await calculatePrice(schema, { ...body, quantity: subEntries.length }); } catch { /* nur Aufzeichnung */ }
const id = await svc('orders').createOne({
order_number: nummer,
...orderData,
entries_count: subEntries.length,
count_inland: subEntries.length - auslandN,
count_ausland: auslandN,
net_total: q?.net_total ?? null, vat_amount: q?.vat_amount ?? null, gross_total: q?.gross_total ?? null,
});
let k = 0;
for (const e of subEntries) { k += 1; await entriesSvc.createOne({ order: id, ...entryFelder(e, k) }); }
await svc('status_history').createOne({ order: id, status: 'eingegangen', note: gebiet ? `Manuell angelegt (Länder-Split: ${gebiet}).` : 'Manuell im Admin angelegt.' });
// Generierung IMMER anstoßen – das Backend entscheidet, was zu erzeugen ist.
fetch(`${BACKEND_URL}/api/order/from-directus`, {
method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Token': BACKEND_TOKEN },
body: JSON.stringify({ orderId: id }),
}).catch((err) => logger.warn(`[skrift-orders] Manuell-Generierung nicht gestartet: ${err.message}`));
return { order_number: nummer, id };
};
if (gemischt) {
const basis = await freieBasis();
const de = await anlegen(deEntries, `${basis}-DE`, 'Deutschland');
const int = await anlegen(intEntries, `${basis}-INT`, 'weltweit');
return res.json({ ok: true, split: true, orders: [de, int], order_number: de.order_number, id: de.id });
let orderId, orderNumber;
for (let v = 0; v < 6; v += 1) {
orderNumber = await naechsteNummer();
try { orderId = await svc('orders').createOne({ order_number: orderNumber, ...orderData }); break; }
catch (e) { if (v === 5 || !/unique|duplicate|bereits|exists/i.test(String(e?.message || ''))) throw e; }
}
const basis = await freieBasis();
const einzel = await anlegen(entries, basis, null);
return res.json({ ok: true, order_number: einzel.order_number, id: einzel.id });
const entriesSvc = svc('order_entries');
let n = 0;
for (const e of entries) {
n += 1;
await entriesSvc.createOne({
order: orderId, letter_number: n,
salutation: clean(e.salutation) ?? null, first_name: clean(e.first_name) ?? null, last_name: clean(e.last_name) ?? null,
street: clean(e.street) ?? null, house_no: clean(e.house_no) ?? null, zip: clean(e.zip) ?? null,
city: clean(e.city) ?? null, country: clean(e.country) ?? null, free_text: clean(e.free_text) ?? null,
placeholders: e.placeholders && typeof e.placeholders === 'object'
? Object.fromEntries(Object.entries(e.placeholders).map(([k, v]) => [k, clean(String(v))])) : null,
});
}
await svc('status_history').createOne({ order: orderId, status: 'eingegangen', note: 'Manuell im Admin angelegt.' });
// Generierung IMMER anstoßen – für jedes Produkt. Das Backend entscheidet,
// was zu erzeugen ist (Schriftstücke bei Handschrift-Produkten, Kuverts immer
// wenn gewünscht; bei Datei-Produkten NUR die Kuverts). Nichts = No-Op.
fetch(`${BACKEND_URL}/api/order/from-directus`, {
method: 'POST', headers: { 'Content-Type': 'application/json', 'X-API-Token': BACKEND_TOKEN },
body: JSON.stringify({ orderId }),
}).catch((e) => logger.warn(`[skrift-orders] Manuell-Generierung nicht gestartet: ${e.message}`));
return res.json({ ok: true, order_number: orderNumber, id: orderId });
} catch (err) {
logger.error(`[skrift-orders] manual-order: ${err.stack || err.message}`);
return res.status(400).json({ error: err.message });