← back to Designerwallcoverings

scripts/apply-1104-map.js

35 lines

#!/usr/bin/env node
/* Apply 2026 MAP to the 1,104 unit-verified under-MAP products (/tmp/cs_1104_plan.json).
   Per product: GraphQL-read variants, pick the NON-SAMPLE (Price Per Unit) variant, set its price
   to MAP via productVariantsBulkUpdate. Sample variant untouched. DRY RUN unless --apply. */
const https=require('https'); const fs=require('fs');
const TOKEN=process.env.T, STORE='designer-laboratory-sandbox.myshopify.com';
const APPLY=process.argv.includes('--apply');
const sleep=ms=>new Promise(r=>setTimeout(r,ms));
function gql(q,vars){return new Promise(r=>{const rq=https.request(`https://${STORE}/admin/api/2024-10/graphql.json`,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'}},x=>{let b='';x.on('data',d=>b+=d);x.on('end',()=>{try{r(JSON.parse(b))}catch(e){r({errors:b})}})});rq.write(JSON.stringify({query:q,variables:vars||{}}));rq.end();});}
const plan=JSON.parse(fs.readFileSync('/tmp/cs_1104_plan.json','utf8'));
const isSample=o=>/sample/i.test(o||'');

(async()=>{
  console.log(`${plan.length} products | mode: ${APPLY?'APPLY':'DRY RUN'}`);
  let ok=0,fail=0,skip=0;
  for(const it of plan){
    try{
      const d=await gql(`query($id:ID!){ product(id:$id){ variants(first:10){edges{node{id price selectedOptions{value}}}} } }`,{id:it.gid});
      const vs=(d.data?.product?.variants?.edges||[]).map(e=>e.node);
      const real=vs.filter(v=>!v.selectedOptions.some(o=>isSample(o.value)));
      const v=real.sort((a,b)=>parseFloat(b.price)-parseFloat(a.price))[0];
      if(!v){ skip++; continue; }
      if(Math.abs(parseFloat(v.price)-it.map)<=0.5){ skip++; continue; } // already at MAP
      if(!APPLY){ ok++; if(ok<=8)console.log(`  $${v.price} -> $${it.map}  ${it.vendor} ${it.sku}`); continue; }
      const m=await gql(`mutation($pid:ID!,$vars:[ProductVariantsBulkInput!]!){ productVariantsBulkUpdate(productId:$pid, variants:$vars){ userErrors{field message} } }`,
        {pid:it.gid, vars:[{id:v.id, price:String(it.map)}]});
      const errs=m.data?.productVariantsBulkUpdate?.userErrors;
      if(errs&&errs.length){ fail++; if(fail<=5)console.log('  ERR',it.sku,JSON.stringify(errs)); }
      else { ok++; if(ok%100===0)console.log(`  …${ok}/${plan.length}`); }
    }catch(e){ fail++; }
    await sleep(60);
  }
  console.log(`\nDONE — ${ok} ${APPLY?'repriced':'would reprice'}, ${fail} failed, ${skip} skipped(already-at-MAP/no-variant).`);
})().catch(e=>{console.error(e);process.exit(1);});