← back to Shopify Sample Shipping
retune-samples-band.mjs
65 lines
#!/usr/bin/env node
// TK-11333 — CORRECT band-retune executor. Targets the LIVE free-sample band on the
// DEDICATED "Samples — Free Shipping (No Tracking)" profile (96764067891), method
// 730269646899, Domestic(US) zone 367888826419 — NOT the General profile.
//
// WHY THIS EXISTS: remove-band.mjs and raise-band.mjs both hardcode the GENERAL profile
// (29033627699), which no longer carries the band. That mis-targeting is what produced the
// false "band already gone / remove is a no-op" claim. This script reads + (gated) edits the
// REAL band. Per the DTD Option-A verdict the recommended action is NO CHANGE ($45 already
// gives ~10 samples free, comfortably covering retail 5+5); --cap is only for an optional
// tighten (e.g. 42.50 = exactly 10) IF Steve wants it.
//
// node retune-samples-band.mjs # READ-ONLY: print the live band + recommend
// node retune-samples-band.mjs --cap 42.50 --apply # GATED write: set the <= cap to 42.50
//
// Undo: verification/samples-band-retune-snapshot.json records the pre-change conditions;
// re-run with --cap <old-value> --apply to restore.
import fs from 'node:fs';
import {query} from './query.mjs';
const PROFILE = 'gid://shopify/DeliveryProfile/96764067891';
const arg = k => { const i = process.argv.indexOf('--' + k); return i >= 0 ? process.argv[i + 1] : undefined; };
const NEW_CAP = arg('cap'); // string dollars, e.g. "42.50"
const APPLY = process.argv.includes('--apply');
const rq = `query($id:ID!){deliveryProfile(id:$id){name profileLocationGroups{locationGroup{id}
locationGroupZones(first:20){nodes{zone{id name} methodDefinitions(first:40){nodes{id name active
rateProvider{__typename ... on DeliveryRateDefinition{price{amount}}}
methodConditions{id operator field conditionCriteria{__typename ... on MoneyV2{amount currencyCode}}}}}}}}}}`;
const d = await query(rq, { id: PROFILE });
let m, lg, zone;
for (const g of d.deliveryProfile.profileLocationGroups) for (const z of g.locationGroupZones.nodes) {
if (z.zone.name !== 'Domestic') continue;
for (const md of z.methodDefinitions.nodes) if (md.name === 'Free Shipping (No Tracking)' && md.rateProvider?.price?.amount === '0.0') { m = md; lg = g.locationGroup.id; zone = z.zone.id; }
}
if (!m) { console.error('Could not find the live $0 band on the Samples profile — aborting.'); process.exit(1); }
const conds = m.methodConditions.filter(c => c.field === 'TOTAL_PRICE');
const cap = conds.find(c => c.operator === 'LESS_THAN_OR_EQUAL_TO');
console.log(`Profile: ${d.deliveryProfile.name}`);
console.log(`Band method: ${m.id} [${m.active ? 'active' : 'INACTIVE'}] $${m.rateProvider.price.amount}`);
console.log(`Current condition: ${conds.map(c => `${c.operator} $${c.conditionCriteria.amount}`).join(' AND ')}`);
if (!NEW_CAP) {
console.log('\nRECOMMENDED (DTD Option A): leave the cap at $45 — no change. It already gives ~10 samples free (covers retail 5+5).');
console.log('To tighten to exactly 10 samples: node retune-samples-band.mjs --cap 42.50 --apply');
process.exit(0);
}
if (!APPLY) {
console.log(`\nDRY RUN — would replace the <= cap ($${cap?.conditionCriteria.amount}) with $${NEW_CAP}. Add --apply to write.`);
process.exit(0);
}
// GATED WRITE: snapshot, delete old TOTAL_PRICE conditions, recreate 0..NEW_CAP.
fs.writeFileSync(new URL('./verification/samples-band-retune-snapshot.json', import.meta.url),
JSON.stringify({ at: new Date().toISOString(), profile: PROFILE, lg, zone, method: m.id, previousConditions: conds }, null, 2) + '\n');
const mut = `mutation($id:ID!,$profile:DeliveryProfileInput!){deliveryProfileUpdate(id:$id,profile:$profile){profile{id} userErrors{field message}}}`;
const del = await query(mut, { id: PROFILE, profile: { conditionsToDelete: conds.map(c => c.id) } });
if (del.deliveryProfileUpdate.userErrors.length) { console.error('delete err', del.deliveryProfileUpdate.userErrors); process.exit(1); }
const add = await query(mut, { id: PROFILE, profile: { locationGroupsToUpdate: [{ id: lg, zonesToUpdate: [{ id: zone, methodDefinitionsToUpdate: [{ id: m.id, priceConditionsToCreate: [
{ operator: 'GREATER_THAN_OR_EQUAL_TO', criteria: { amount: '0', currencyCode: 'USD' } },
{ operator: 'LESS_THAN_OR_EQUAL_TO', criteria: { amount: NEW_CAP, currencyCode: 'USD' } }] }] }] }] } });
if (add.deliveryProfileUpdate.userErrors.length) { console.error('add err', add.deliveryProfileUpdate.userErrors); process.exit(1); }
console.log(`\nAPPLIED — band cap set to $${NEW_CAP}. Undo: node retune-samples-band.mjs --cap ${cap?.conditionCriteria.amount || '45'} --apply`);