← back to Koroseal Goodrich Audit

push_shopify_only.py

38 lines

#!/usr/bin/env python3
"""Shopify-only push, batched by <=25 metafields/call (metafieldsSet hard limit).
PG mirror already written. Idempotent-safe. Usage: --apply to fire."""
import json,os,sys,time,urllib.request
APPLY="--apply" in sys.argv
ROOT="/Users/macstudio3/Projects/koroseal-goodrich-audit"
def env(k):
    for l in open(os.path.expanduser("~/Projects/secrets-manager/.env")):
        if l.startswith(k+"="): return l.split("=",1)[1].strip()
TOKEN=env("SHOPIFY_ADMIN_TOKEN"); SHOP=env("SHOPIFY_STORE"); VER="2024-10"
writes=[json.loads(l) for l in open(os.path.join(ROOT,"mfr_width_writelist.jsonl"))]
# flatten to metafield inputs
mfs=[]
for w in writes:
    for k,v in w["fields"].items():
        ns,key=k.split(".")
        mfs.append({"ownerId":w["shopify_id"],"namespace":ns,"key":key,
                    "type":"single_line_text_field","value":v})
print(f"[{'APPLY' if APPLY else 'DRY'}] total metafields to push: {len(mfs)} (batch<=25)  cost=$0")
q="mutation($m:[MetafieldsSetInput!]!){metafieldsSet(metafields:$m){metafields{id} userErrors{field message}}}"
def call(chunk):
    body=json.dumps({"query":q,"variables":{"m":chunk}}).encode()
    req=urllib.request.Request(f"https://{SHOP}/admin/api/{VER}/graphql.json",data=body,
        headers={"X-Shopify-Access-Token":TOKEN,"Content-Type":"application/json"})
    with urllib.request.urlopen(req) as r: return json.load(r)
if not APPLY:
    print("dry-run only"); sys.exit(0)
ok=0; errs=0
for i in range(0,len(mfs),25):
    ch=mfs[i:i+25]
    res=call(ch)
    d=res.get("data",{}).get("metafieldsSet",{})
    ue=d.get("userErrors",[])
    if ue: errs+=len(ue); print("  userErrors:",ue[:3])
    ok+=len(d.get("metafields",[]))
    time.sleep(0.6)
print(f"  Shopify: set {ok} metafields, userErrors={errs}")