u
This commit is contained in:
@@ -474,7 +474,8 @@ export function register(app, basePath = '') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
fs.rmSync(importDir, { recursive: true, force: true });
|
// Do not clean the import upload directory so files remain available for inspection/analysis
|
||||||
|
// fs.rmSync(importDir, { recursive: true, force: true });
|
||||||
fs.mkdirSync(importDir, { recursive: true });
|
fs.mkdirSync(importDir, { recursive: true });
|
||||||
|
|
||||||
// Preserve the raw zip archive
|
// Preserve the raw zip archive
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { getStore } from '../db/store.js';
|
import { getStore } from '../db/store.js';
|
||||||
|
import { createLogger } from '../util/logger.js';
|
||||||
|
|
||||||
|
const log = createLogger('import');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses RFC 4180 CSV text into an array of objects keyed by header.
|
* Parses RFC 4180 CSV text into an array of objects keyed by header.
|
||||||
@@ -254,7 +257,6 @@ export async function executeCompanyImport({
|
|||||||
// Fallback: Haupt category ID for unmapped items
|
// Fallback: Haupt category ID for unmapped items
|
||||||
const hauptDashId = jtlCatIdToDashCatId.get('1') || rootCategoryId;
|
const hauptDashId = jtlCatIdToDashCatId.get('1') || rootCategoryId;
|
||||||
|
|
||||||
// ─── Phase 2: Article Import Pass 1 (Create or Update) ───────────────────
|
|
||||||
const includedArticles = artRecords.filter((a) => {
|
const includedArticles = artRecords.filter((a) => {
|
||||||
let cats = [];
|
let cats = [];
|
||||||
try {
|
try {
|
||||||
@@ -268,8 +270,63 @@ export async function executeCompanyImport({
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ─── Phase 2: Brand (Hersteller) Import ──────────────────────────────────
|
||||||
|
const brandMap = new Map(); // brandName -> Set of picture relative paths
|
||||||
|
for (const a of includedArticles) {
|
||||||
|
const hersteller = String(a.Hersteller || '').trim();
|
||||||
|
if (!hersteller) continue;
|
||||||
|
if (!brandMap.has(hersteller)) {
|
||||||
|
brandMap.set(hersteller, new Set());
|
||||||
|
}
|
||||||
|
const rawPics = String(a.manufacturerPictureFiles || '').trim();
|
||||||
|
if (rawPics) {
|
||||||
|
for (const p of rawPics.split(/[;,]/).map((s) => s.trim()).filter(Boolean)) {
|
||||||
|
brandMap.get(hersteller).add(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const brandNameToId = new Map();
|
||||||
|
let createdBrandCount = 0;
|
||||||
|
let brandPicCount = 0;
|
||||||
|
const brandEntries = Array.from(brandMap.entries());
|
||||||
|
log.info(`Processing ${brandEntries.length} brands (Hersteller)...`);
|
||||||
|
|
||||||
|
for (let i = 0; i < brandEntries.length; i++) {
|
||||||
|
const [brandName, picSet] = brandEntries[i];
|
||||||
|
try {
|
||||||
|
const brand = await store.brand.upsert(googleAuthId, { name: brandName });
|
||||||
|
brandNameToId.set(brandName.toLowerCase(), brand.id);
|
||||||
|
createdBrandCount++;
|
||||||
|
|
||||||
|
// If brand doesn't have an image yet, import from manufacturerPictureFiles
|
||||||
|
if ((!brand.pics || brand.pics.length === 0) && picSet.size > 0) {
|
||||||
|
for (const picRel of picSet) {
|
||||||
|
const picPath = path.resolve(importDir, picRel);
|
||||||
|
if (fs.existsSync(picPath)) {
|
||||||
|
try {
|
||||||
|
const imgBuf = fs.readFileSync(picPath);
|
||||||
|
await store.brand.addImage(googleAuthId, brand.id, imgBuf);
|
||||||
|
brandPicCount++;
|
||||||
|
break; // 1 primary logo per brand
|
||||||
|
} catch (err) {
|
||||||
|
log.warn(`Brand image error for "${brandName}" (${picRel}):`, err.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
log.warn(`Failed to upsert brand "${brandName}":`, err.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
onProgress('brands', i + 1, brandEntries.length, brandName);
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`Brands resolved: ${brandNameToId.size}/${brandEntries.length}, brand images: ${brandPicCount}`);
|
||||||
|
|
||||||
|
// ─── Phase 3: Article Import Pass 1 (Create or Update) ───────────────────
|
||||||
const totalArticles = includedArticles.length;
|
const totalArticles = includedArticles.length;
|
||||||
console.log(`[Import] Articles to process: ${totalArticles}`);
|
log.info(`Articles to process: ${totalArticles}`);
|
||||||
onProgress('articles', 0, totalArticles, 'Starting articles import');
|
onProgress('articles', 0, totalArticles, 'Starting articles import');
|
||||||
|
|
||||||
let articlesImported = 0;
|
let articlesImported = 0;
|
||||||
@@ -355,6 +412,17 @@ export async function executeCompanyImport({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update brand if provided
|
||||||
|
const hersteller = String(a.Hersteller || '').trim();
|
||||||
|
const brandId = hersteller ? (brandNameToId.get(hersteller.toLowerCase()) || null) : null;
|
||||||
|
if (brandId && existingArticle.brand?.id !== brandId) {
|
||||||
|
try {
|
||||||
|
await store.article.setBrandIdBySku(googleAuthId, sku, brandId);
|
||||||
|
} catch (bErr) {
|
||||||
|
log.warn(`Could not set brand for ${sku}:`, bErr.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
articlesUpdated++;
|
articlesUpdated++;
|
||||||
} else {
|
} else {
|
||||||
// Create new article
|
// Create new article
|
||||||
@@ -385,6 +453,17 @@ export async function executeCompanyImport({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set brand if provided
|
||||||
|
const hersteller = String(a.Hersteller || '').trim();
|
||||||
|
const brandId = hersteller ? (brandNameToId.get(hersteller.toLowerCase()) || null) : null;
|
||||||
|
if (brandId) {
|
||||||
|
try {
|
||||||
|
await store.article.setBrandIdBySku(googleAuthId, sku, brandId);
|
||||||
|
} catch (bErr) {
|
||||||
|
log.warn(`Could not set brand for ${sku}:`, bErr.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
articlesImported++;
|
articlesImported++;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -470,6 +549,9 @@ export async function executeCompanyImport({
|
|||||||
categories: jtlCatIdToDashCatId.size,
|
categories: jtlCatIdToDashCatId.size,
|
||||||
categoriesCreated: createdCatCount,
|
categoriesCreated: createdCatCount,
|
||||||
categoryPictures: catPicCount,
|
categoryPictures: catPicCount,
|
||||||
|
brands: brandNameToId.size,
|
||||||
|
brandsCreated: createdBrandCount,
|
||||||
|
brandPictures: brandPicCount,
|
||||||
articlesTotal: totalArticles,
|
articlesTotal: totalArticles,
|
||||||
articlesImported,
|
articlesImported,
|
||||||
articlesUpdated,
|
articlesUpdated,
|
||||||
|
|||||||
Reference in New Issue
Block a user