u
This commit is contained in:
@@ -91,6 +91,51 @@ export function parseCsvRecords(text) {
|
||||
return records;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts or derives a variant attribute value for a child article
|
||||
* based on its name relative to its parent name, or SKU suffixes.
|
||||
*
|
||||
* @param {string} parentName
|
||||
* @param {string} childName
|
||||
* @param {string} childSku
|
||||
* @param {string} parentSku
|
||||
* @returns {string}
|
||||
*/
|
||||
export function extractVariantValue(parentName, childName, childSku, parentSku) {
|
||||
let pName = (parentName || '').replace(/[©®™]/g, '').trim();
|
||||
let cName = (childName || '').replace(/[©®™]/g, '').trim();
|
||||
|
||||
if (pName && cName) {
|
||||
// Child name starts with parent name
|
||||
if (cName.toLowerCase().startsWith(pName.toLowerCase())) {
|
||||
let val = cName.slice(pName.length).trim().replace(/^[-–—:/,\s]+/, '').trim();
|
||||
if (val) return val;
|
||||
}
|
||||
// Match common leading tokens
|
||||
const pWords = pName.toLowerCase().split(/\s+/);
|
||||
const cWords = cName.split(/\s+/);
|
||||
if (cWords.length > 1 && pWords[0] === cWords[0].toLowerCase()) {
|
||||
let matchCount = 0;
|
||||
while (matchCount < pWords.length && matchCount < cWords.length && pWords[matchCount] === cWords[matchCount].toLowerCase()) {
|
||||
matchCount++;
|
||||
}
|
||||
if (matchCount > 0) {
|
||||
const remaining = cWords.slice(matchCount).join(' ').trim().replace(/^[-–—:/,\s]+/, '').trim();
|
||||
if (remaining) return remaining;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SKU suffix: "42001505-1" with parent "42001505" -> "1"
|
||||
if (parentSku && childSku && childSku.startsWith(parentSku)) {
|
||||
let suffix = childSku.slice(parentSku.length).trim().replace(/^[-_]+/, '').trim();
|
||||
if (suffix) return suffix;
|
||||
}
|
||||
|
||||
if (cName && cName !== pName) return cName;
|
||||
return childSku || 'Standard';
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes full catalog import from preserved files in importDir.
|
||||
*
|
||||
@@ -502,23 +547,108 @@ export async function executeCompanyImport({
|
||||
console.log(`[Import] Linking ${variantChildren.length} child variants to parents...`);
|
||||
onProgress('variants', 0, variantChildren.length, 'Linking variants');
|
||||
|
||||
let variantsLinked = 0;
|
||||
for (let i = 0; i < variantChildren.length; i++) {
|
||||
const child = variantChildren[i];
|
||||
const childSku = String(child.cArtNr || '').trim();
|
||||
// Ensure a default attribute (e.g. "Variante") exists for variant parents
|
||||
let defaultVariantAttrId = null;
|
||||
try {
|
||||
const attrList = await store.attributename.list(googleAuthId);
|
||||
const existingAttr = attrList.find(
|
||||
(a) => (a.name || '').trim().toLowerCase() === 'variante'
|
||||
);
|
||||
if (existingAttr) {
|
||||
defaultVariantAttrId = existingAttr.id;
|
||||
} else {
|
||||
const createdAttr = await store.attributename.create(googleAuthId, {
|
||||
name: 'Variante',
|
||||
exclusive: true,
|
||||
});
|
||||
defaultVariantAttrId = createdAttr.id;
|
||||
}
|
||||
} catch (err) {
|
||||
log.warn('Could not ensure default "Variante" attribute:', err.message);
|
||||
}
|
||||
|
||||
// Group children by parent SKU
|
||||
const parentChildrenMap = new Map();
|
||||
for (const child of variantChildren) {
|
||||
const parentJtlId = String(child.kVaterArtikel || '').trim();
|
||||
const parentSku = jtlArtIdToSku.get(parentJtlId);
|
||||
const childSku = String(child.cArtNr || '').trim();
|
||||
if (!parentSku || !childSku || parentSku === childSku) continue;
|
||||
|
||||
if (childSku && parentSku && childSku !== parentSku) {
|
||||
try {
|
||||
await store.article.setParentBySku(googleAuthId, childSku, parentSku);
|
||||
variantsLinked++;
|
||||
} catch (err) {
|
||||
console.warn(`[Import] Failed to link child ${childSku} to parent ${parentSku}:`, err.message);
|
||||
if (!parentChildrenMap.has(parentSku)) {
|
||||
parentChildrenMap.set(parentSku, []);
|
||||
}
|
||||
parentChildrenMap.get(parentSku).push(child);
|
||||
}
|
||||
|
||||
let variantsLinked = 0;
|
||||
let processedCount = 0;
|
||||
|
||||
for (const [parentSku, children] of parentChildrenMap.entries()) {
|
||||
let parentDetail = null;
|
||||
try {
|
||||
const res = await store.article.getBySku(googleAuthId, parentSku);
|
||||
parentDetail = res.article;
|
||||
} catch (err) {
|
||||
log.warn(`[Import] Could not load parent ${parentSku}:`, err.message);
|
||||
processedCount += children.length;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure parent has is_parent = 1 and parentattributename_id set
|
||||
let parentAttrId = parentDetail?.parentAttributeNameId;
|
||||
if (!parentDetail?.isParent || !parentAttrId) {
|
||||
if (defaultVariantAttrId) {
|
||||
try {
|
||||
await store.article.toggleParent(googleAuthId, parentSku, {
|
||||
isParent: true,
|
||||
attributeNameId: defaultVariantAttrId,
|
||||
});
|
||||
parentAttrId = defaultVariantAttrId;
|
||||
} catch (err) {
|
||||
log.warn(`[Import] Could not toggle parent for ${parentSku}:`, err.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (i % 20 === 0 || i === variantChildren.length - 1) {
|
||||
onProgress('variants', i + 1, variantChildren.length, `${childSku} -> ${parentSku}`);
|
||||
|
||||
const parentName = parentDetail?.name || '';
|
||||
const usedValues = new Set();
|
||||
|
||||
for (const child of children) {
|
||||
processedCount++;
|
||||
const childSku = String(child.cArtNr || '').trim();
|
||||
let childName = '';
|
||||
try {
|
||||
const desc = JSON.parse(child.descriptions || '[]');
|
||||
childName = (Array.isArray(desc) ? desc[0]?.cName : desc?.cName) || '';
|
||||
} catch {}
|
||||
|
||||
let val = extractVariantValue(parentName, childName, childSku, parentSku);
|
||||
if (usedValues.has(val.toLowerCase())) {
|
||||
val = `${val} (${childSku})`;
|
||||
}
|
||||
usedValues.add(val.toLowerCase());
|
||||
|
||||
try {
|
||||
if (parentAttrId) {
|
||||
await store.article.attachChild(googleAuthId, parentSku, {
|
||||
sku: childSku,
|
||||
value: val,
|
||||
reparent: true,
|
||||
});
|
||||
variantsLinked++;
|
||||
} else {
|
||||
// Fallback to setParentBySku if toggleParent failed
|
||||
await store.article.setParentBySku(googleAuthId, childSku, parentSku);
|
||||
variantsLinked++;
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(`[Import] Failed to attach child ${childSku} to parent ${parentSku}:`, err.message);
|
||||
}
|
||||
|
||||
if (processedCount % 20 === 0 || processedCount === variantChildren.length) {
|
||||
onProgress('variants', processedCount, variantChildren.length, `${childSku} -> ${parentSku}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(`[Import] Linked ${variantsLinked}/${variantChildren.length} variants`);
|
||||
|
||||
Reference in New Issue
Block a user