Untitled

 avatar
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