← back to Zero Price Fix
fix.py
31 lines
#!/usr/bin/env python3
"""Free-checkout fix (PR Elowen). PREP / DRY-RUN BY DEFAULT.
'Elowen Paperweave' has a $0.00 sellable 'Standard' variant (inv_policy=continue) with no cost
-> orderable FREE. Default fix: DRAFT the product (off storefront, reversible, sample kept intact).
Live requires --apply + ZEROFIX_CONFIRM=YES. reverse.py restores prev status.
Alt (rule-correct, manual): quote-tag it once it's a confirmed quote-only line, or set a real price."""
import os,sys,json,time,urllib.request,urllib.error
HERE=os.path.dirname(os.path.abspath(__file__)); SHOP="designer-laboratory-sandbox.myshopify.com"; API="2024-10"
def token():
for l in open(os.path.expanduser("~/Projects/secrets-manager/.env")):
if l.startswith("SHOPIFY_ADMIN_TOKEN="): return l.split("=",1)[1].strip()
sys.exit("no token")
def main():
target="archived" if "--archive" in sys.argv else "draft"
live="--apply" in sys.argv and os.environ.get("ZEROFIX_CONFIRM")=="YES"
if "--apply" in sys.argv and not live: print("REFUSING --apply without ZEROFIX_CONFIRM=YES. DRY-RUN.\n")
w=json.load(open(os.path.join(HERE,"data","worklist.json")))
print(f"=== zero-price fix [{'LIVE' if live else 'DRY-RUN'}] -> {target.upper()} — {len(w)} product ===")
tok=token() if live else None
for r in w:
line=f"{r['num']} {r['title']} (prev={r['prev_status']})"
if not live: print(f"WOULD set -> {target} | {line}"); continue
try:
req=urllib.request.Request(f"https://{SHOP}/admin/api/{API}/products/{r['num']}.json",
data=json.dumps({"product":{"id":int(r['num']),"status":target}}).encode(),method="PUT",
headers={"X-Shopify-Access-Token":tok,"Content-Type":"application/json"})
urllib.request.urlopen(req,timeout=40); print(f"OK -> {target} | {line}")
except urllib.error.HTTPError as e: print(f"FAIL {line} HTTP {e.code}")
print("DRY-RUN complete. Nothing written." if not live else "applied. Reverse with reverse.py")
if __name__=="__main__": main()