← back to Dw Signup Fulfillment

verification/tk10836/verify-abandoned-default.js

60 lines

#!/usr/bin/env node
// TK-11366 DECISIVE TEST of the preselection hypothesis.
// An ABANDONED checkout records whatever shipping line was selected when the shopper walked away.
// A shopper who abandons early never actively picks a rate -> the recorded line approximates the
// DEFAULT. So: if the default flipped away from $0.00 around 2026-08-18, abandoned checkouts should
// show the same before/after swing as orders. If the default never changed (customers are actively
// upgrading), abandoned checkouts should stay overwhelmingly $0.00 in BOTH windows.
// READ-ONLY.
const fs=require('fs'),os=require('os');
for (const line of fs.readFileSync(os.homedir()+'/Projects/secrets-manager/.env','utf8').split('\n')) {
  const m=line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)$/); if(!m) continue;
  let v=m[2].trim().replace(/^['"]|['"]$/g,''); if(!process.env[m[1]]) process.env[m[1]]=v;
}
const STORE=process.env.SHOPIFY_STORE_DOMAIN, TOKEN=process.env.SHOPIFY_FULL_ACCESS_TOKEN, API='2024-10';
async function gql(q,v={}){const r=await fetch(`https://${STORE}/admin/api/${API}/graphql.json`,{method:'POST',
  headers:{'X-Shopify-Access-Token':TOKEN,'Content-Type':'application/json'},body:JSON.stringify({query:q,variables:v})});
  const j=await r.json(); if(j.errors)console.error('ERR',JSON.stringify(j.errors).slice(0,400)); return j.data;}
const Q=`query($c:String){ abandonedCheckouts(first:40, after:$c, query:"created_at:>2026-06-01", sortKey:CREATED_AT){
  pageInfo{hasNextPage endCursor}
  nodes{ id createdAt
    subtotalPriceSet{shopMoney{amount}} totalPriceSet{shopMoney{amount}} totalTaxSet{shopMoney{amount}}
    shippingAddress{ countryCodeV2 }
    lineItems(first:20){ nodes{ title quantity variant{ sku } } } } } }`;
(async()=>{
  let c=null, rows=[];
  do{ const d=await gql(Q,{c}); if(!d) break;
    for(const a of d.abandonedCheckouts.nodes){
      const lis=a.lineItems.nodes; if(!lis.length) continue;
      if(!lis.every(li=>/(^|-)sample/i.test(li.variant?.sku||'')||/sample|memo|swatch/i.test(li.title||''))) continue;
      if(a.shippingAddress?.countryCodeV2!=='US') continue;
      const items=Number(a.subtotalPriceSet?.shopMoney?.amount||0);
      const total=Number(a.totalPriceSet?.shopMoney?.amount||0);
      const tax=Number(a.totalTaxSet?.shopMoney?.amount||0);
      const ship=+(total-items-tax).toFixed(2);
      rows.push({date:a.createdAt.slice(0,10), items, ship, units:lis.reduce((s,l)=>s+l.quantity,0)});
    } c=d.abandonedCheckouts.pageInfo.hasNextPage?d.abandonedCheckouts.pageInfo.endCursor:null; }while(c);
  console.log(`US sample-only ABANDONED checkouts since 2026-06-01: n=${rows.length}\n`);
  const bucket=(lo,hi)=>{
    const s=rows.filter(r=>r.date>=lo&&r.date<=hi);
    const withShip=s.filter(r=>r.ship>0.001);
    return {n:s.length, zero:s.length-withShip.length, paid:withShip.length,
            pct: s.length? (100*(s.length-withShip.length)/s.length).toFixed(0):'-'};
  };
  console.log('### shipping line recorded on ABANDONED sample checkouts (proxy for the DEFAULT) ###');
  for(const [lab,lo,hi] of [['Jun 1 - Aug 17','2026-06-01','2026-08-17'],['Aug 18 - Sep 10','2026-08-18','2026-09-30']]){
    const b=bucket(lo,hi);
    console.log(`  ${lab}: n=${b.n}  ship\$0.00=${b.zero} (${b.pct}%)  ship>\$0=${b.paid}`);
  }
  console.log('\n### monthly ###');
  const months=[...new Set(rows.map(r=>r.date.slice(0,7)))].sort();
  for(const m of months){
    const s=rows.filter(r=>r.date.startsWith(m));
    const z=s.filter(r=>r.ship<=0.001).length;
    console.log(`  ${m}: n=${String(s.length).padStart(3)}  \$0.00=${String(z).padStart(3)} (${s.length?(100*z/s.length).toFixed(0):0}%)`);
  }
  const amts={}; for(const r of rows.filter(r=>r.ship>0.001&&r.date>='2026-08-18')) amts[r.ship]=(amts[r.ship]||0)+1;
  console.log('\n  paid shipping amounts on abandoned checkouts since Aug 18:', JSON.stringify(amts));
  fs.writeFileSync('verification/tk10836/abandoned-default.json',JSON.stringify(rows,null,2));
})();