diff --git a/src/services/companyExport.js b/src/services/companyExport.js index 166fa8e..e1a36fa 100644 --- a/src/services/companyExport.js +++ b/src/services/companyExport.js @@ -506,11 +506,23 @@ export async function executeCompanyExport({ log.warn('Could not prefetch payment/shipping types:', err.message); } + const entityMap = new Map(); + try { + const entities = await store.entity.list(googleAuthId); + for (const ent of entities) { + entityMap.set(ent.id, ent); + } + } catch (err) { + log.warn('Could not prefetch entities for order export:', err.message); + } + const manifestCsvHeaders = [ '"id"', '"nr"', '"extnr"', '"created_at"', + '"customerNr"', + '"customerName"', '"paymentType"', '"shippingType"', '"payed"', @@ -543,11 +555,21 @@ export async function executeCompanyExport({ const payType = paymentMap.get(ord.id) || ord.payment?.type || ord.payments?.[0]?.type || 'Bar'; const shipType = shippingMap.get(ord.id) || ord.shipping?.type || ord.shippings?.[0]?.type || 'Selbstabholer'; + const entity = ord.entity || (ord.entityId ? entityMap.get(ord.entityId) : null); + const customerNr = ord.customerNr || entity?.number || ord.customer?.number || ''; + const customerName = ord.customerName + || entity?.name + || [entity?.firstName, entity?.lastName].filter(Boolean).join(' ') + || [ord.customerFirstName, ord.customerLastName].filter(Boolean).join(' ') + || ''; + manifestCsvRows.push([ formatCsvField(ord.id), formatCsvField(ord.number), formatCsvField(ord.externalNumber || ''), formatCsvField(ord.createdAt || ord.date || new Date().toISOString()), + formatCsvField(customerNr), + formatCsvField(customerName), formatCsvField(payType), formatCsvField(shipType), formatCsvField(ord.isPaid || ord.paid ? '1' : '0'), diff --git a/src/services/companyImport.js b/src/services/companyImport.js index e442735..14d4ef2 100644 --- a/src/services/companyImport.js +++ b/src/services/companyImport.js @@ -216,6 +216,7 @@ export async function executeCompanyImport({ ordersSkipped: ordersResult.ordersSkipped, paymentsImported: ordersResult.paymentsImported, shippingsImported: ordersResult.shippingsImported, + customersImported: ordersResult.customersImported || 0, }, }; } diff --git a/src/services/companyImport/orderImporter.js b/src/services/companyImport/orderImporter.js index 78d2cef..f1ea78e 100644 --- a/src/services/companyImport/orderImporter.js +++ b/src/services/companyImport/orderImporter.js @@ -61,8 +61,11 @@ export async function importOrders({ let defaultCustomerGroupId = null; try { const groups = await store.customergroup.list(googleAuthId); - defaultCustomerGroupId = groups[0]?.id || null; - } catch {} + const posGroup = groups.find((g) => g.name === 'POS' || g.name?.toUpperCase() === 'POS'); + defaultCustomerGroupId = posGroup?.id || groups[0]?.id || null; + } catch (err) { + log.warn('Could not list customer groups:', err.message); + } let defaultWarehouseId = null; try { @@ -77,31 +80,82 @@ export async function importOrders({ log.warn('Could not ensure warehouse:', err.message); } + let customersImported = 0; const entityMap = new Map(); + const entityByNumber = 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); } + if (ent.number) { + entityByNumber.set(String(ent.number).trim().toLowerCase(), ent.id); + } } - } catch {} + } catch (err) { + log.warn('Could not list existing entities:', err.message); + } - const resolveEntityId = async (name, firstName) => { + const resolveEntityId = async (name, firstName, number) => { const cleanName = (name || '').trim(); + const cleanNr = (number || '').trim(); if (!cleanName || !defaultCustomerGroupId) return null; + + const nrKey = cleanNr ? cleanNr.toLowerCase() : null; + if (nrKey && entityByNumber.has(nrKey)) { + return entityByNumber.get(nrKey); + } + const key = cleanName.toLowerCase(); - if (entityMap.has(key)) return entityMap.get(key); + if (!nrKey && entityMap.has(key)) return entityMap.get(key); try { const ent = await store.entity.create(googleAuthId, { customergroupId: defaultCustomerGroupId, name: cleanName, firstName: (firstName || '').trim() || undefined, + number: cleanNr || undefined, }); entityMap.set(key, ent.id); + if (ent.number) { + entityByNumber.set(String(ent.number).trim().toLowerCase(), ent.id); + } + if (nrKey) { + entityByNumber.set(nrKey, ent.id); + } + customersImported++; return ent.id; } catch (err) { + if (cleanNr && err.message?.includes('Number already in use')) { + try { + const refreshed = await store.entity.list(googleAuthId).catch(() => []); + const found = refreshed.find( + (e) => String(e.number).trim().toLowerCase() === nrKey + ); + if (found) { + entityByNumber.set(nrKey, found.id); + if (found.name) entityMap.set(found.name.trim().toLowerCase(), found.id); + return found.id; + } + } catch {} + try { + const ent = await store.entity.create(googleAuthId, { + customergroupId: defaultCustomerGroupId, + name: cleanName, + firstName: (firstName || '').trim() || undefined, + }); + entityMap.set(key, ent.id); + if (ent.number) { + entityByNumber.set(String(ent.number).trim().toLowerCase(), ent.id); + } + customersImported++; + return ent.id; + } catch (retryErr) { + log.warn(`Could not create entity "${cleanName}":`, retryErr.message); + return null; + } + } log.warn(`Could not create entity "${cleanName}":`, err.message); return null; } @@ -218,9 +272,10 @@ export async function importOrders({ }; }); - const custName = cleanValue(m.name ?? m.cName) || 'Laufkunde'; + const custName = cleanValue(m.customerName ?? m.name ?? m.cName) || 'Laufkunde'; const custFirstName = cleanValue(m.firstName ?? m.cVorname); - const entityId = await resolveEntityId(custName, custFirstName); + const custNr = cleanValue(m.customerNr ?? m.cKundenNr); + const entityId = await resolveEntityId(custName, custFirstName, custNr); const dateStr = cleanValue(m.created_at ?? m.dErstellt); const parsedDate = dateStr ? new Date(dateStr) : new Date(); @@ -380,13 +435,14 @@ export async function importOrders({ } progressTracker.emitProgress(true); - log.info(`Orders complete: ${ordersImported} created, ${ordersSkipped} skipped, ${paymentsImported} payments, ${shippingsImported} shippings`); + log.info(`Orders complete: ${ordersImported} created, ${ordersSkipped} skipped, ${paymentsImported} payments, ${shippingsImported} shippings, ${customersImported} customers`); return { ordersImported, ordersSkipped, paymentsImported, shippingsImported, + customersImported, }; }