← back to Letsbegin
fix_x_mfr.js
75 lines
const https = require('https');
const STORE = 'designer-laboratory-sandbox.myshopify.com';
const TOKEN = process.env.SHOPIFY_PRODUCT_TOKEN;
if (!TOKEN) {
throw new Error('SHOPIFY_PRODUCT_TOKEN environment variable is required');
}
function gql(body) {
return new Promise((resolve, reject) => {
const data = JSON.stringify(body);
const req = https.request({
hostname: STORE, path: '/admin/api/2024-10/graphql.json', method: 'POST',
headers: { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
}, res => { let c = ''; res.on('data', d => c += d); res.on('end', () => { try { resolve(JSON.parse(c)); } catch { resolve({ error: c.slice(0,300) }); } }); });
req.on('error', reject);
req.setTimeout(30000, () => { req.destroy(); reject(new Error('timeout')); });
req.write(data); req.end();
});
}
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
async function main() {
console.log('=== X-Series MFR SKU Fixer v2 ===');
console.log('global.manufacturer_sku → custom.manufacturer_sku\n');
let cursor = null, page = 1, fixed = 0, noGlobal = 0, already = 0, total = 0, errors = 0;
while (true) {
const after = cursor ? `, after: "${cursor}"` : '';
const r = await gql({
query: `{ products(first: 25, query: "sku:X* AND status:active"${after}) {
edges { cursor node { id title metafields(first: 30) { edges { node { namespace key value } } } } }
pageInfo { hasNextPage }
} }`
});
const edges = r?.data?.products?.edges || [];
if (edges.length === 0) break;
for (const edge of edges) {
const p = edge.node;
cursor = edge.cursor;
total++;
let globalMfr = '', globalVni = '', customMfr = '';
for (const m of p.metafields.edges) {
const ns = m.node.namespace, k = m.node.key, v = m.node.value || '';
if (ns === 'global' && k === 'manufacturer_sku') globalMfr = v;
if (ns === 'global' && k === 'vendor_name_internal') globalVni = v;
if (ns === 'custom' && k === 'manufacturer_sku') customMfr = v;
}
const realMfr = globalMfr || globalVni;
if (!realMfr) { noGlobal++; continue; }
if (customMfr === realMfr) { already++; continue; }
if (customMfr && /[A-Za-z]/.test(customMfr) && customMfr.length > 5) { already++; continue; }
try {
const result = await gql({
query: 'mutation metafieldsSet($m: [MetafieldsSetInput!]!) { metafieldsSet(metafields: $m) { metafields { key } userErrors { message } } }',
variables: { m: [{ ownerId: p.id, namespace: 'custom', key: 'manufacturer_sku', value: realMfr, type: 'single_line_text_field' }] }
});
if ((result?.data?.metafieldsSet?.userErrors || []).length === 0) fixed++;
else errors++;
} catch { errors++; }
await sleep(400);
}
console.log(`Page ${page}: total=${total} fixed=${fixed} noGlobal=${noGlobal} already=${already}`);
if (!r?.data?.products?.pageInfo?.hasNextPage) break;
page++; await sleep(200);
}
console.log(`\n=== DONE === Fixed: ${fixed} | No global MFR: ${noGlobal} | Already correct: ${already} | Errors: ${errors}`);
}
main().catch(e => { console.error('Fatal:', e); process.exit(1); });