← back to Novasuede Min Fix
reorder-default.mjs
55 lines
import fs from 'fs';
const env=fs.readFileSync(process.env.HOME+'/Projects/secrets-manager/.env','utf8');
const get=k=>(env.match(new RegExp('^'+k+'=(.*)$','m'))||[])[1];
const TOKEN=get('SHOPIFY_ADMIN_TOKEN');
const API='https://designer-laboratory-sandbox.myshopify.com/admin/api/2024-10/graphql.json';
async function gql(q,v={}){const r=await fetch(API,{method:'POST',headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});return r.json();}
const APPLY = process.argv.includes('--apply');
// products to fix: Sample is at pos1, must move Per Yard to pos1, Wallcovering pos2, Sample pos3
const targets = [
{handle:'novasuede™-sand', id:'gid://shopify/Product/7923064930355'},
{handle:'novasuede™-fabric-wallcovering-gentle-pine', id:'gid://shopify/Product/7924270497843'},
];
const FETCH=`query($id:ID!){ product(id:$id){ id title variants(first:20){ nodes{ id title position } } } }`;
const REORDER=`mutation($id:ID!,$moves:[ProductVariantPositionInput!]!){
productVariantsBulkReorder(productId:$id, positions:$moves){
product{ id }
userErrors{ field message }
}
}`;
function classify(t){
if(/per yard/i.test(t) && !/wallcover/i.test(t)) return 'peryard';
if(/wallcover/i.test(t)) return 'wallcovering';
if(/sample/i.test(t)) return 'sample';
return 'other';
}
const DESIRED = {peryard:1, wallcovering:2, sample:3, other:99};
const restoreAdditions = [];
for(const t of targets){
const f=await gql(FETCH,{id:t.id});
const p=f.data.product;
const vs=[...p.variants.nodes].sort((a,b)=>a.position-b.position);
const oldOrder = vs.map(v=>({id:v.id, title:v.title, position:v.position}));
// build desired positions
const moves = vs.map(v=>({id:v.id, position:DESIRED[classify(v.title)]}))
.sort((a,b)=>a.position-b.position);
console.log('\n'+p.title);
console.log(' OLD:', oldOrder.map(v=>v.position+':'+v.title).join(' '));
console.log(' NEW:', moves.map(m=>m.position+':'+(oldOrder.find(o=>o.id===m.id).title)).join(' '));
restoreAdditions.push({ type:'variant_reorder', productId:t.id, title:p.title, handle:t.handle, oldOrder });
if(APPLY){
const r=await gql(REORDER,{id:t.id, moves});
const ue=r?.data?.productVariantsBulkReorder?.userErrors||[];
if(ue.length||r.errors){ console.log(' ERROR:', JSON.stringify(ue), JSON.stringify(r.errors)); }
else console.log(' APPLIED ok');
}
}
// write/extend restore map (separate file so we don't clobber the qty restore-map.json)
fs.writeFileSync('restore-map-reorder.json', JSON.stringify(restoreAdditions,null,2));
console.log('\nrestore-map-reorder.json written ('+restoreAdditions.length+' products).', APPLY?'APPLIED':'DRY-RUN (pass --apply to execute)');