← back to Rebel Walls Push

scripts/TK-10405-aprime-undo.mjs

40 lines

#!/usr/bin/env node
// UNDO for TK-10405 A' mitigation — restores each held orphan's original SKU (strips -DUP)
// and restores its inventory available to qty_before, from the recorded restore map.
// Run:  node scripts/TK-10405-aprime-undo.mjs
import fs from 'node:fs';
const DOM = 'designer-laboratory-sandbox.myshopify.com';
const VER = '2024-10';
const RESTORE = new URL('../data/TK-10405-restore-map.json', import.meta.url).pathname;
const env = fs.readFileSync(process.env.HOME + '/Projects/secrets-manager/.env', 'utf8');
const TOKEN = (env.match(/^SHOPIFY_FULL_ACCESS_TOKEN=(.+)$/m)?.[1] || '').trim().replace(/^["']|["']$/g, '');

async function gql(query, variables, tries = 6) {
  for (let i = 0; i < tries; i++) {
    const r = await fetch(`https://${DOM}/admin/api/${VER}/graphql.json`, {
      method: 'POST', headers: { 'X-Shopify-Access-Token': TOKEN, 'Content-Type': 'application/json' },
      body: JSON.stringify({ query, variables }) });
    if ([429, 500, 502, 503].includes(r.status) && i < tries - 1) { await new Promise(s => setTimeout(s, 1500 * (i + 1))); continue; }
    return r.json();
  }
}
const M_SKU = `mutation($productId:ID!,$variants:[ProductVariantsBulkInput!]!){
  productVariantsBulkUpdate(productId:$productId,variants:$variants){ productVariants{ id sku } userErrors{ field message } } }`;
const M_INV = `mutation($input:InventorySetQuantitiesInput!){
  inventorySetQuantities(input:$input){ inventoryAdjustmentGroup{ createdAt } userErrors{ field message } } }`;

(async () => {
  const rm = JSON.parse(fs.readFileSync(RESTORE, 'utf8'));
  const ps = rm.a_prime_mitigation?.prestate;
  if (!ps) { console.error('no a_prime_mitigation.prestate in restore map — nothing to undo'); process.exit(1); }
  for (const [id, e] of Object.entries(ps)) {
    console.log(`Undo ${e.label} (${id}): sku -> ${e.sku_before}, qty -> ${e.qty_before}`);
    const rs = await gql(M_SKU, { productId: e.product_gid, variants: [{ id: e.variant_gid, inventoryItem: { sku: e.sku_before } }] });
    console.log('  sku userErrors:', JSON.stringify(rs?.data?.productVariantsBulkUpdate?.userErrors || rs?.errors || []));
    const ri = await gql(M_INV, { input: { name: 'available', reason: 'correction', ignoreCompareQuantity: true,
      quantities: [{ inventoryItemId: e.inventory_item_gid, locationId: e.location_gid, quantity: e.qty_before }] } });
    console.log('  inv userErrors:', JSON.stringify(ri?.data?.inventorySetQuantities?.userErrors || ri?.errors || []));
  }
  console.log('UNDO complete.');
})();