This commit is contained in:
seb
2026-10-11 18:20:35 +02:00
parent 1eb5cb4e59
commit fe7be79b90
12 changed files with 1395 additions and 937 deletions

View File

@@ -0,0 +1,165 @@
// MARK: - Imports
// #region Imports
import { cleanValue, parseGermanFloat } from './csvParser.js';
import { createLogger } from '../../util/logger.js';
// #endregion
const log = createLogger('import');
// MARK: - Order / Manifest Importer
// #region Order / Manifest Importer
/**
* Imports order manifests and line items, resolving customer entities.
*
* @param {object} params
* @param {object} params.store - Store singleton
* @param {number} params.googleAuthId
* @param {Array<Record<string, string>>} params.manRecords
* @param {Array<Record<string, string>>} params.itemRecords
* @param {object} params.progressTracker
* @returns {Promise<{ ordersImported: number, ordersSkipped: number }>}
*/
export async function importOrders({
store,
googleAuthId,
manRecords,
itemRecords,
progressTracker,
}) {
let ordersImported = 0;
let ordersSkipped = 0;
if (manRecords.length === 0 || itemRecords.length === 0) {
return { ordersImported, ordersSkipped };
}
const itemsByAuftrag = new Map();
for (const it of itemRecords) {
const kAuftrag = String(it.kAuftrag || '').trim();
if (!kAuftrag) continue;
if (!itemsByAuftrag.has(kAuftrag)) {
itemsByAuftrag.set(kAuftrag, []);
}
itemsByAuftrag.get(kAuftrag).push(it);
}
const existingOrdersResult = await store.order.list(googleAuthId);
const existingOrderList = Array.isArray(existingOrdersResult)
? existingOrdersResult
: (existingOrdersResult?.orders || []);
const existingOrderNumbers = new Set(
existingOrderList.map((o) => (o.number || '').trim()).filter(Boolean)
);
let defaultCustomerGroupId = null;
try {
const groups = await store.customergroup.list(googleAuthId);
defaultCustomerGroupId = groups[0]?.id || null;
} catch {}
const entityMap = new Map();
try {
const entities = await store.entity.list(googleAuthId);
for (const ent of entities) {
if (ent.name) {
entityMap.set(ent.name.trim().toLowerCase(), ent.id);
}
}
} catch {}
const resolveEntityId = async (name, firstName) => {
const cleanName = (name || '').trim();
if (!cleanName || !defaultCustomerGroupId) return null;
const key = cleanName.toLowerCase();
if (entityMap.has(key)) return entityMap.get(key);
try {
const ent = await store.entity.create(googleAuthId, {
customergroupId: defaultCustomerGroupId,
name: cleanName,
firstName: (firstName || '').trim() || undefined,
});
entityMap.set(key, ent.id);
return ent.id;
} catch (err) {
log.warn(`Could not create entity "${cleanName}":`, err.message);
return null;
}
};
for (const m of manRecords) {
const orderNumber = cleanValue(m.cAuftragsNr);
if (!orderNumber || existingOrderNumbers.has(orderNumber)) {
ordersSkipped++;
progressTracker.counts.receiptsdone++;
progressTracker.emitProgress();
continue;
}
const rawItems = itemsByAuftrag.get(String(m.kAuftrag || '').trim()) || [];
if (rawItems.length === 0) {
ordersSkipped++;
progressTracker.counts.receiptsdone++;
progressTracker.emitProgress();
continue;
}
const lines = rawItems.map((it) => {
const sku = cleanValue(it.cArtNr) || null;
const rawName = cleanValue(it.cName || it.cNameStandard);
const name = rawName || (sku ? `Artikel ${sku}` : 'Artikel');
const amount = parseGermanFloat(it.fAnzahl, 1);
const net = parseGermanFloat(it.fVKNetto, 0);
const taxrate = parseGermanFloat(it.fMwSt, 19);
const rebate = parseGermanFloat(it.fRabatt, 0);
const comment = cleanValue(it.cHinweis) || null;
return {
sku,
name,
amount,
net,
taxrate,
rebate,
comment,
};
});
const custName = cleanValue(m.cName) || 'Laufkunde';
const custFirstName = cleanValue(m.cVorname);
const entityId = await resolveEntityId(custName, custFirstName);
const dateStr = cleanValue(m.dErstellt);
const parsedDate = dateStr ? new Date(dateStr) : new Date();
const validDate = !Number.isNaN(parsedDate.getTime()) ? parsedDate.toISOString() : new Date().toISOString();
try {
await store.order.create(googleAuthId, {
number: orderNumber,
externalNumber: cleanValue(m.cExterneAuftragsnummer) || null,
date: validDate,
createdAt: validDate,
entityId: entityId || undefined,
lines,
});
existingOrderNumbers.add(orderNumber);
ordersImported++;
} catch (err) {
log.warn(`Failed to create order ${orderNumber}:`, err.message);
}
progressTracker.counts.receiptsdone++;
progressTracker.emitProgress();
}
progressTracker.emitProgress(true);
log.info(`Orders complete: ${ordersImported} created, ${ordersSkipped} skipped`);
return {
ordersImported,
ordersSkipped,
};
}
// #endregion