u
This commit is contained in:
@@ -48,6 +48,180 @@ export function formatPfandName(val) {
|
||||
|
||||
// #endregion
|
||||
|
||||
// MARK: - Pfand Setup & Linking Helpers
|
||||
// #region Pfand Setup & Linking Helpers
|
||||
|
||||
/**
|
||||
* Pre-creates the Pfand category and Pfand articles upfront.
|
||||
*
|
||||
* @param {object} params
|
||||
* @param {object} params.store - Store singleton
|
||||
* @param {number} params.googleAuthId
|
||||
* @param {number} params.hauptDashId
|
||||
* @param {Array<Record<string, string>>} params.includedArticles
|
||||
* @returns {Promise<{ pfandArticlesCreated: number, pfandArticlesUpdated: number, pfandCatId: number|null, uniqueValues: number[] }>}
|
||||
*/
|
||||
export async function setupPfandArticles({
|
||||
store,
|
||||
googleAuthId,
|
||||
hauptDashId,
|
||||
includedArticles,
|
||||
}) {
|
||||
// 1. Discover unique Pfand values from all included articles (checking attributes)
|
||||
const uniqueValuesSet = new Set();
|
||||
for (const a of includedArticles) {
|
||||
const val = extractPfandValue(a.attributes);
|
||||
if (val != null) {
|
||||
uniqueValuesSet.add(val);
|
||||
}
|
||||
}
|
||||
|
||||
if (uniqueValuesSet.size === 0) {
|
||||
log.info('No pfand attributes detected among articles.');
|
||||
return {
|
||||
pfandArticlesCreated: 0,
|
||||
pfandArticlesUpdated: 0,
|
||||
pfandCatId: null,
|
||||
uniqueValues: [],
|
||||
};
|
||||
}
|
||||
|
||||
const uniqueValues = Array.from(uniqueValuesSet).sort((a, b) => a - b);
|
||||
log.info(`Discovered ${uniqueValues.length} unique Pfand values: ${uniqueValues.join(', ')}`);
|
||||
|
||||
// 2. Resolve or create "Pfand" subcategory under "Haupt"
|
||||
let pfandCatId = null;
|
||||
try {
|
||||
const treeResult = await store.category.getTreeForCompany(googleAuthId);
|
||||
const existingTree = treeResult.tree || [];
|
||||
const existingPfandCat = existingTree.find(
|
||||
(c) => c.parentId === hauptDashId && String(c.name || '').trim().toLowerCase() === 'pfand'
|
||||
);
|
||||
|
||||
if (existingPfandCat) {
|
||||
pfandCatId = existingPfandCat.id;
|
||||
} else {
|
||||
const created = await store.category.createUnderParent({
|
||||
googleAuthId,
|
||||
parentId: hauptDashId,
|
||||
name: 'Pfand',
|
||||
});
|
||||
pfandCatId = created.id;
|
||||
log.info(`Created "Pfand" category under Haupt (id: ${pfandCatId})`);
|
||||
}
|
||||
} catch (err) {
|
||||
log.warn('Could not resolve or create Pfand category under Haupt, falling back to Haupt:', err.message);
|
||||
pfandCatId = hauptDashId;
|
||||
}
|
||||
|
||||
// 3. Create or update Pfand articles
|
||||
let pfandArticlesCreated = 0;
|
||||
let pfandArticlesUpdated = 0;
|
||||
|
||||
for (const val of uniqueValues) {
|
||||
const pfandSku = formatPfandSku(val);
|
||||
const pfandName = formatPfandName(val);
|
||||
|
||||
let existingArticle = null;
|
||||
try {
|
||||
const res = await store.article.getBySku(googleAuthId, pfandSku);
|
||||
existingArticle = res.article;
|
||||
} catch {
|
||||
existingArticle = null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (existingArticle) {
|
||||
await store.article.updateBySku(googleAuthId, pfandSku, {
|
||||
name: pfandName,
|
||||
track_stock: 0,
|
||||
});
|
||||
await store.article.setPricesBySku(googleAuthId, pfandSku, [
|
||||
{ gross: val, tax: 19 },
|
||||
]);
|
||||
pfandArticlesUpdated++;
|
||||
log.info(`Updated existing Pfand article: ${pfandSku} ("${pfandName}")`);
|
||||
} else {
|
||||
await store.article.createUnderParent({
|
||||
googleAuthId,
|
||||
parentId: pfandCatId,
|
||||
name: pfandName,
|
||||
sku: pfandSku,
|
||||
track_stock: 0,
|
||||
});
|
||||
await store.article.setPricesBySku(googleAuthId, pfandSku, [
|
||||
{ gross: val, tax: 19 },
|
||||
]);
|
||||
pfandArticlesCreated++;
|
||||
log.info(`Created new Pfand article: ${pfandSku} ("${pfandName}")`);
|
||||
}
|
||||
} catch (err) {
|
||||
log.warn(`Failed to create or update Pfand article ${pfandSku}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pfandArticlesCreated,
|
||||
pfandArticlesUpdated,
|
||||
pfandCatId,
|
||||
uniqueValues,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Links an article to its mandatory Pfand deposit option.
|
||||
*
|
||||
* @param {object} params
|
||||
* @param {object} params.store
|
||||
* @param {number} params.googleAuthId
|
||||
* @param {string} params.sku
|
||||
* @param {number} params.pfandVal
|
||||
* @returns {Promise<boolean>}
|
||||
*/
|
||||
export async function linkArticlePfand({
|
||||
store,
|
||||
googleAuthId,
|
||||
sku,
|
||||
pfandVal,
|
||||
}) {
|
||||
if (!sku || pfandVal == null) return false;
|
||||
const pfandSku = formatPfandSku(pfandVal);
|
||||
|
||||
let existingOptions = [];
|
||||
try {
|
||||
existingOptions = (await store.article.getOptionslist(googleAuthId, sku)) || [];
|
||||
} catch {
|
||||
existingOptions = [];
|
||||
}
|
||||
|
||||
const otherOptions = existingOptions.filter((o) => !o.sku?.startsWith('PFAND-'));
|
||||
const newOptions = [
|
||||
...otherOptions.map((o, idx) => ({
|
||||
sku: o.sku,
|
||||
articleId: o.articleId,
|
||||
count: o.count || 1,
|
||||
sort: idx,
|
||||
mandated: Boolean(o.mandated),
|
||||
})),
|
||||
{
|
||||
sku: pfandSku,
|
||||
count: 1,
|
||||
sort: otherOptions.length,
|
||||
mandated: true,
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
await store.article.setOptionslist(googleAuthId, sku, newOptions);
|
||||
return true;
|
||||
} catch (err) {
|
||||
log.warn(`Failed to link Pfand option ${pfandSku} to article ${sku}:`, err.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// #endregion
|
||||
|
||||
// MARK: - Pfand Importer
|
||||
// #region Pfand Importer
|
||||
|
||||
@@ -116,125 +290,31 @@ export async function importPfand({
|
||||
};
|
||||
}
|
||||
|
||||
// 3. Find unique Pfand values
|
||||
const uniqueValues = Array.from(new Set(articleTargets.map((t) => t.pfandVal))).sort((a, b) => a - b);
|
||||
log.info(`Discovered ${articleTargets.length} articles with Pfand across ${uniqueValues.length} unique values: ${uniqueValues.join(', ')}`);
|
||||
// 3. Setup Pfand category and Pfand articles
|
||||
const setupResult = await setupPfandArticles({
|
||||
store,
|
||||
googleAuthId,
|
||||
hauptDashId,
|
||||
includedArticles,
|
||||
});
|
||||
|
||||
// 4. Resolve or create "Pfand" subcategory under "Haupt"
|
||||
let pfandCatId = null;
|
||||
try {
|
||||
const treeResult = await store.category.getTreeForCompany(googleAuthId);
|
||||
const existingTree = treeResult.tree || [];
|
||||
const existingPfandCat = existingTree.find(
|
||||
(c) => c.parentId === hauptDashId && String(c.name || '').trim().toLowerCase() === 'pfand'
|
||||
);
|
||||
|
||||
if (existingPfandCat) {
|
||||
pfandCatId = existingPfandCat.id;
|
||||
} else {
|
||||
const created = await store.category.createUnderParent({
|
||||
googleAuthId,
|
||||
parentId: hauptDashId,
|
||||
name: 'Pfand',
|
||||
});
|
||||
pfandCatId = created.id;
|
||||
log.info(`Created "Pfand" category under Haupt (id: ${pfandCatId})`);
|
||||
}
|
||||
} catch (err) {
|
||||
log.warn('Could not resolve or create Pfand category under Haupt, falling back to Haupt:', err.message);
|
||||
pfandCatId = hauptDashId;
|
||||
}
|
||||
|
||||
// 5. Create or update Pfand articles
|
||||
let pfandArticlesCreated = 0;
|
||||
let pfandArticlesUpdated = 0;
|
||||
|
||||
for (const val of uniqueValues) {
|
||||
const pfandSku = formatPfandSku(val);
|
||||
const pfandName = formatPfandName(val);
|
||||
|
||||
let existingArticle = null;
|
||||
try {
|
||||
const res = await store.article.getBySku(googleAuthId, pfandSku);
|
||||
existingArticle = res.article;
|
||||
} catch {
|
||||
existingArticle = null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (existingArticle) {
|
||||
await store.article.updateBySku(googleAuthId, pfandSku, {
|
||||
name: pfandName,
|
||||
track_stock: 0,
|
||||
});
|
||||
await store.article.setPricesBySku(googleAuthId, pfandSku, [
|
||||
{ gross: val, tax: 19 },
|
||||
]);
|
||||
pfandArticlesUpdated++;
|
||||
log.info(`Updated existing Pfand article: ${pfandSku} ("${pfandName}")`);
|
||||
} else {
|
||||
await store.article.createUnderParent({
|
||||
googleAuthId,
|
||||
parentId: pfandCatId,
|
||||
name: pfandName,
|
||||
sku: pfandSku,
|
||||
track_stock: 0,
|
||||
});
|
||||
await store.article.setPricesBySku(googleAuthId, pfandSku, [
|
||||
{ gross: val, tax: 19 },
|
||||
]);
|
||||
pfandArticlesCreated++;
|
||||
log.info(`Created new Pfand article: ${pfandSku} ("${pfandName}")`);
|
||||
}
|
||||
} catch (err) {
|
||||
log.warn(`Failed to create or update Pfand article ${pfandSku}:`, err.message);
|
||||
}
|
||||
}
|
||||
|
||||
// 6. Link each target article to its Pfand article as a mandatory option
|
||||
// 4. Link each target article to its Pfand article as a mandatory option
|
||||
let pfandOptionsLinked = 0;
|
||||
|
||||
for (const { sku, pfandVal } of articleTargets) {
|
||||
const pfandSku = formatPfandSku(pfandVal);
|
||||
|
||||
let existingOptions = [];
|
||||
try {
|
||||
existingOptions = (await store.article.getOptionslist(googleAuthId, sku)) || [];
|
||||
} catch {
|
||||
existingOptions = [];
|
||||
}
|
||||
|
||||
// Filter out any existing PFAND options to prevent duplicates, keep any other options
|
||||
const otherOptions = existingOptions.filter((o) => !o.sku?.startsWith('PFAND-'));
|
||||
const newOptions = [
|
||||
...otherOptions.map((o, idx) => ({
|
||||
sku: o.sku,
|
||||
articleId: o.articleId,
|
||||
count: o.count || 1,
|
||||
sort: idx,
|
||||
mandated: Boolean(o.mandated),
|
||||
})),
|
||||
{
|
||||
sku: pfandSku,
|
||||
count: 1,
|
||||
sort: otherOptions.length,
|
||||
mandated: true,
|
||||
},
|
||||
];
|
||||
|
||||
try {
|
||||
await store.article.setOptionslist(googleAuthId, sku, newOptions);
|
||||
pfandOptionsLinked++;
|
||||
} catch (err) {
|
||||
log.warn(`Failed to link Pfand option ${pfandSku} to article ${sku}:`, err.message);
|
||||
}
|
||||
const linked = await linkArticlePfand({
|
||||
store,
|
||||
googleAuthId,
|
||||
sku,
|
||||
pfandVal,
|
||||
});
|
||||
if (linked) pfandOptionsLinked++;
|
||||
}
|
||||
|
||||
log.info(`Pfand import complete: ${pfandArticlesCreated} created, ${pfandArticlesUpdated} updated, ${pfandOptionsLinked} linked as mandatory options.`);
|
||||
log.info(`Pfand import complete: ${setupResult.pfandArticlesCreated} created, ${setupResult.pfandArticlesUpdated} updated, ${pfandOptionsLinked} linked as mandatory options.`);
|
||||
|
||||
return {
|
||||
pfandArticlesCreated,
|
||||
pfandArticlesUpdated,
|
||||
pfandArticlesCreated: setupResult.pfandArticlesCreated,
|
||||
pfandArticlesUpdated: setupResult.pfandArticlesUpdated,
|
||||
pfandOptionsLinked,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user