Untitled
unknown
plain_text
10 months ago
4.7 kB
17
Indexable
// helpers
function _toArray(list) {
if (!list) return [];
if (Array.isArray(list)) return list;
if (typeof list.length === "function" && typeof list.get === "function") {
return list.get(0, list.length());
}
return [];
}
function _thingId(t) {
if (!t) return null;
if (typeof t === "string") return t;
if (t.get) return t.get("_id") || t.get("unique_id") || t.get("id") || t.get("slug") || t.get("name") || null;
return t._id || t.unique_id || t.id || t.slug || t.name || null;
}
function _thingName(t) {
if (!t) return null;
if (typeof t === "string") return t;
if (t.get) return t.get("name") || t.get("label") || t.get("title") || t.get("value") || null;
return t.name || t.label || t.title || t.value || null;
}
function _field(row, key) {
return row && row.get ? row.get(key) : row ? row[key] : null;
}
function _cartesian(arrays) {
if (!arrays.length) return [];
return arrays.reduce((acc, curr) => acc.flatMap(a => curr.map(b => [...a, b])), [[]]);
}
// build
const rows = _toArray(properties.thing_list_1); // ProductVariants list
const orderThings = _toArray(properties.thing_list_2); // optional productOptions list
const primaryOpt = properties.thing_1 || null; // optional productOption
const skuPrefix = properties.sku_prefix || "SKU";
const defaultPrice = properties.default_price != null ? Number(properties.default_price) : 0;
const defaultQty = properties.default_qty != null ? Number(properties.default_qty) : 1;
if (!rows.length) {
return JSON.stringify({ productId: null, count: 0, combinations: [] });
}
// derive product id from first row
const firstRow = rows[0];
const productThing = _field(firstRow, "product");
const productId = _thingId(productThing);
// group valueIds by optionId
const byOptionId = new Map(); // optionId -> Set(valueId)
const optionLabelMap = new Map(); // optionId -> name
const valueLabelMap = new Map(); // valueId -> name
const firstSeen = new Map(); // optionId -> order index
let seen = 0;
for (const r of rows) {
const p = _field(r, "product");
if (_thingId(p) !== productId) continue;
const opt = _field(r, "option"); // can be Thing or text: "Color"
const val = _field(r, "optionValue"); // can be Thing or text: "White" or an id
const optionId = _thingId(opt);
const valueId = _thingId(val);
if (!optionId || !valueId) continue;
const optionName = _thingName(opt);
const valueName = _thingName(val);
if (optionName != null && !optionLabelMap.has(optionId)) optionLabelMap.set(optionId, optionName);
if (valueName != null && !valueLabelMap.has(valueId)) valueLabelMap.set(valueId, valueName);
if (!byOptionId.has(optionId)) {
byOptionId.set(optionId, new Set());
if (!firstSeen.has(optionId)) firstSeen.set(optionId, seen++);
}
byOptionId.get(optionId).add(valueId);
}
// pick option order (max 4)
let optionIds = Array.from(byOptionId.keys()).slice(0, 4);
if (orderThings.length) {
const ordered = orderThings.map(_thingId).filter(Boolean);
const set = new Set(ordered);
optionIds = ordered.filter(id => byOptionId.has(id)).slice(0, 4);
for (const id of byOptionId.keys()) {
if (!set.has(id) && optionIds.length < 4) optionIds.push(id);
}
} else {
const primaryId = _thingId(primaryOpt);
optionIds.sort((a, b) => {
if (primaryId && a === primaryId) return -1;
if (primaryId && b === primaryId) return 1;
return (firstSeen.get(a) ?? 0) - (firstSeen.get(b) ?? 0);
});
}
// value arrays per option
const valueArrays = optionIds.map(id => Array.from(byOptionId.get(id) || []));
if (!valueArrays.length) {
return JSON.stringify({ productId, count: 0, combinations: [] });
}
// combinations
const combos = _cartesian(valueArrays);
const out = combos.map((valueIds, i) => {
const key = optionIds.map((optId, idx) => `${optId}:${valueIds[idx]}`).join("|");
const optionLabels = optionIds.map(id => optionLabelMap.get(id)).filter(v => v != null);
const valueLabels = valueIds.map(id => valueLabelMap.get(id)).filter(v => v != null);
return {
productId,
optionIds,
valueIds,
combination_key_ids: key,
sku: `${skuPrefix}-${String(i + 1).padStart(4, "0")}`,
price: defaultPrice,
quantity: defaultQty,
...(optionLabels.length === optionIds.length ? { optionLabels } : {}),
...(valueLabels.length === valueIds.length ? { valueLabels } : {})
};
});
// return JSON text
return JSON.stringify({ productId, count: out.length, combinations: out });
Editor is loading...
Leave a Comment