← back to Tk10630 Sku Suffix Canary
lib.mjs
65 lines
// Pure transform + detection logic shared by enumerate / apply / canary.
// No I/O, no side effects on import.
// Fabricated DW codes to purge. Hollywood Wallcoverings & Phillipe Romano are DW
// BRANDS, not external vendors — a scraper (dw-sku-registry mintNewPrefix) minted
// DW-vendor-style SKUs = "DW" + 2-4 letters + number. Within the Hollywood line the
// REAL codes are always non-DW (XWH-, NOC-, HWC-, FLS-, XJP-, HLW-, DUR-, ...), so
// ANY DW-prefixed base is fabricated. Observed families: DWHD, DWHW2, DWHV, DWYX,
// DWKK, DWPR, DWGB, DWCC, DWPN, DWPP, DWHQ. (Narrow /^DWH[DW]/ missed DWHV/DWYX/... .)
export const FABRICATED = /^DW[A-Z]{1,4}\d?-\d/i;
// A legit ORIGINAL private-label code: alpha prefix + digits, e.g. XWH-52359, NOC-105.
const ORIG = /^([A-Z]{2,5})-?(\d{2,})$/i;
function normCode(s) {
const m = s.match(ORIG);
return m ? `${m[1].toUpperCase()}-${m[2]}` : s.toUpperCase();
}
// Derive a product's ORIGINAL line code (prefix-agnostic), ignoring fabricated codes.
// Returns a string base, null (no code), or {conflict:[...]} (variants disagree).
export function deriveBase(p) {
const cand = new Set();
for (const v of p.variants.nodes) {
const m = (v.sku || '').match(/^(.+?)-(sample|yard|roll)$/i);
const raw = m ? m[1] : (v.sku || '');
if (raw && !FABRICATED.test(raw) && ORIG.test(raw)) cand.add(normCode(raw));
}
if (cand.size === 1) return [...cand][0];
if (cand.size > 1) return { conflict: [...cand] };
const hm = p.handle.match(/-([a-z]{2,5})-(\d{2,})$/i);
if (hm) { const b = `${hm[1].toUpperCase()}-${hm[2]}`; if (!FABRICATED.test(b)) return b; }
if (p.pn?.value) { const m = p.pn.value.match(/^([A-Z]{2,5})-?(\d{2,})$/i); if (m) { const b = `${m[1].toUpperCase()}-${m[2]}`; if (!FABRICATED.test(b)) return b; } }
return null; // no NON-fabricated original code recoverable → skip/flag (needs staging reconciliation)
}
// Which purchase-option suffix a variant should carry.
export function suffixFor(v) {
const opt = (v.selectedOptions?.find(o => /purchase option/i.test(o.name))?.value || v.title || '').toLowerCase();
const cur = (v.sku || '').toLowerCase();
if (/sample/.test(opt) || /-sample$/.test(cur)) return 'sample';
if (/roll/.test(opt) || /-roll$/.test(cur)) return 'roll';
if (/yard/.test(opt) || /per yard/.test(opt) || /-yard$/.test(cur)) return 'yard';
return 'yard';
}
// Compute the change set for one product given its canonical base.
export function planProduct(p, base) {
const varChanges = [];
for (const v of p.variants.nodes) {
const suf = suffixFor(v);
const target = `${base}-${suf}`;
if ((v.sku || '') !== target)
varChanges.push({ variantId: v.id, invItemId: v.inventoryItem.id, from: v.sku, to: target, option: suf });
}
const mfChanges = [];
// Three dw_sku metafield namespaces carry the fabricated codes: global, dwc, custom.
for (const [ns, mf] of [['global', p.mfG], ['dwc', p.mfD], ['custom', p.mfC]]) {
if (mf === undefined) continue; // namespace not fetched for this pass
const cur = mf?.value || null;
if (cur !== base) mfChanges.push({ namespace: ns, key: 'dw_sku', ownerId: p.id, from: cur, to: base });
}
return { varChanges, mfChanges };
}