← back to Wolfgordon Crawl

unmatched-analysis.js

59 lines

#!/usr/bin/env node
// Drill into the 789 unmatched legacy WG products (read-only).
// Goal: distinguish genuine discontinues from recoverable patterns.
const { pool } = require('./scraper-utils');

function norm(s){return s?String(s).toLowerCase().replace(/[®™©]/g,'').replace(/&/g,'&').replace(/[^a-z0-9]+/g,' ').replace(/\s+/g,' ').trim():'';}
function nsku(s){return s?String(s).toLowerCase().replace(/_8$/,'').replace(/[^a-z0-9]+/g,''):'';}

async function main(){
  const cat = (await pool.query(`SELECT mfr_sku,pattern_name,color_name FROM wolf_gordon_catalog`)).rows;
  const catNsku = new Set(cat.map(r=>nsku(r.mfr_sku)));
  const catPat  = new Set(cat.map(r=>norm(r.pattern_name)));   // pattern-only catalog set
  const catPC = new Set(cat.map(r=>`${norm(r.pattern_name)}|${norm(r.color_name)}`));

  const leg = (await pool.query(`SELECT sku,mfr_sku,pattern_name,title,status FROM shopify_products WHERE vendor='Wolf Gordon'`)).rows;

  const unmatched=[];
  for(const r of leg){
    const head=(r.title||'').split('|')[0].trim();
    const ci=head.indexOf(' - ');
    const color=ci===-1?null:head.slice(ci+3).trim();
    if(catNsku.has(nsku(r.mfr_sku))) continue;
    const pc=`${norm(r.pattern_name)}|${norm(color)}`;
    if(color && catPC.has(pc)) continue;
    unmatched.push({...r, color});
  }

  // Bucket the unmatched.
  let patternStillExists=0, patternGone=0, patternIsSku=0;
  const goneSamples=[], patStillSamples=[];
  for(const u of unmatched){
    const p=norm(u.pattern_name);
    // pattern_name that is literally the SKU (weak legacy data)
    if(nsku(u.pattern_name)===nsku(u.mfr_sku)){ patternIsSku++; continue; }
    if(catPat.has(p)){ patternStillExists++; if(patStillSamples.length<12) patStillSamples.push(u); }
    else { patternGone++; if(goneSamples.length<12) goneSamples.push(u); }
  }

  const byStatus={};
  for(const u of unmatched) byStatus[u.status]=(byStatus[u.status]||0)+1;

  console.log('UNMATCHED LEGACY ANALYSIS  (total '+unmatched.length+')');
  console.log('='.repeat(64));
  console.log('By Shopify status:');
  for(const k of Object.keys(byStatus)) console.log('  '+k.padEnd(22)+byStatus[k]);
  console.log('-'.repeat(64));
  console.log('pattern_name is just the SKU (weak data):        '+patternIsSku);
  console.log('pattern STILL EXISTS in catalog (color drifted): '+patternStillExists+'  <- likely recolored/renamed, recoverable');
  console.log('pattern GONE from catalog entirely:              '+patternGone+'  <- genuine discontinue');
  console.log('='.repeat(64));
  console.log('\nSAMPLE — pattern still exists but exact color/sku drifted:');
  for(const u of patStillSamples) console.log('  '+u.sku.padEnd(16)+(u.pattern_name+' / '+(u.color||'')).padEnd(34)+'status='+u.status);
  console.log('\nSAMPLE — pattern gone (genuine discontinue):');
  for(const u of goneSamples) console.log('  '+u.sku.padEnd(16)+(u.pattern_name+' / '+(u.color||'')).padEnd(34)+'status='+u.status);

  await pool.end();
}
main().catch(e=>{console.error(e);process.exit(1);});