← back to Dwjs Consolidation 2026 04 23
hollywood_mfr_apply.js
78 lines
// Apply: write real mfr SKU from fmpro into custom.manufacturer_sku for 2,786 Hollywood products.
const fs = require('fs');
const TOKEN=(process.env.SHOPIFY_ADMIN_TOKEN || '');
const SHOP='designer-laboratory-sandbox.myshopify.com';
const API=`https://${SHOP}/admin/api/2024-10/graphql.json`;
const STATE = __dirname + '/hollywood_apply_state.json';
const NDJSON = __dirname + '/hollywood_apply_execution.ndjson';
const changes = JSON.parse(fs.readFileSync(__dirname + '/hollywood_changes.json','utf8'));
console.log(`Loaded ${changes.length} changes to apply`);
const state = fs.existsSync(STATE) ? JSON.parse(fs.readFileSync(STATE,'utf8')) : { done: [] };
const done = new Set(state.done);
const todo = changes.filter(c => !done.has(c.id));
console.log(`Already done: ${done.size}, Remaining: ${todo.length}\n`);
async function gql(q, vars, retries=3) {
for (let i=0;i<retries;i++) {
try {
const r = await fetch(API, {
method:'POST',
headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},
body: JSON.stringify({ query: q, variables: vars }),
});
const j = await r.json();
if (j.errors && j.errors.some(e => /THROTTLED|throttled/.test(JSON.stringify(e)))) {
await new Promise(r=>setTimeout(r, 2000*(i+1)));
continue;
}
return j;
} catch (e) {
if (i === retries-1) throw e;
await new Promise(r=>setTimeout(r, 1000*(i+1)));
}
}
}
const ndStream = fs.createWriteStream(NDJSON, { flags: 'a' });
const BATCH = 25;
(async () => {
let totalOk=0, totalErr=0, batchNum=0;
for (let i=0; i<todo.length; i+=BATCH) {
batchNum++;
const chunk = todo.slice(i, i+BATCH);
const metafields = chunk.map(c => ({
ownerId: c.id,
namespace: 'custom',
key: 'manufacturer_sku',
type: 'single_line_text_field',
value: c.newMfr,
}));
const q = `mutation set($mfs:[MetafieldsSetInput!]!) {
metafieldsSet(metafields: $mfs) {
metafields { id key }
userErrors { field message }
}
}`;
const j = await gql(q, { mfs: metafields });
const ue = j.data?.metafieldsSet?.userErrors || [];
const top = j.errors || [];
if (ue.length || top.length) {
totalErr += chunk.length;
ndStream.write(JSON.stringify({ ts:new Date().toISOString(), batch:batchNum, error:true, ue, top })+'\n');
} else {
totalOk += chunk.length;
chunk.forEach(c => done.add(c.id));
chunk.forEach(c => ndStream.write(JSON.stringify({ ts:new Date().toISOString(), id:c.id, sku:c.sku, oldMfr:c.currentMfr, newMfr:c.newMfr })+'\n'));
}
fs.writeFileSync(STATE, JSON.stringify({ done:[...done] }));
if (batchNum % 5 === 0 || i+BATCH >= todo.length) {
console.log(` batch ${batchNum}: ok=${totalOk} err=${totalErr} (${(((i+chunk.length)/todo.length)*100).toFixed(1)}%)`);
}
}
ndStream.end();
console.log(`\nDONE. ok=${totalOk} err=${totalErr}`);
})();