← back to Zero Price Fix
Zero-price free-checkout fix prep — dry-run draft tooling for PR Elowen (no live writes)
0270566c412f78d391ef0c5da445767ed0a2df97 · 2026-08-01 22:11:36 -0700 · Steve Abrams
Files touched
A .gitignoreA README.mdA data/worklist.jsonA fix.pyA reverse.py
Diff
commit 0270566c412f78d391ef0c5da445767ed0a2df97
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Aug 1 22:11:36 2026 -0700
Zero-price free-checkout fix prep — dry-run draft tooling for PR Elowen (no live writes)
---
.gitignore | 5 +++++
README.md | 6 ++++++
data/worklist.json | 10 ++++++++++
fix.py | 30 ++++++++++++++++++++++++++++++
reverse.py | 16 ++++++++++++++++
5 files changed, 67 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ff2422c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+node_modules/
+.env*
+tmp/
+*.log
+.DS_Store
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0af37d6
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+# Zero-price / free-checkout fix (PREP — nothing live)
+PR "Elowen Paperweave Barley & Black Gloss" (7877230755891) has a $0.00 'Standard' variant
+(PWV-11886, inv_policy=continue) with no cost -> orderable FREE. Default fix: DRAFT (off storefront,
+reversible, keeps the $4.25 sample). Live: `ZEROFIX_CONFIRM=YES python3 fix.py --apply`. Undo: reverse.py.
+Alt (manual, rule-correct): quote-tag it if confirmed quote-only, or set a real price once cost exists.
+Memo: ~/.claude/yolo-queue/pending-approval/2026-08-01-zero-price-orderable-outlier.md
diff --git a/data/worklist.json b/data/worklist.json
new file mode 100644
index 0000000..23a1e0d
--- /dev/null
+++ b/data/worklist.json
@@ -0,0 +1,10 @@
+[
+{
+"num": "7877230755891",
+"prev_status": "active",
+"title": "Elowen Paperweave Barley & Black Gloss | Phillipe Romano",
+"zero_variant_ids": [
+44494274199603
+]
+}
+]
\ No newline at end of file
diff --git a/fix.py b/fix.py
new file mode 100644
index 0000000..9824d60
--- /dev/null
+++ b/fix.py
@@ -0,0 +1,30 @@
+#!/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()
diff --git a/reverse.py b/reverse.py
new file mode 100644
index 0000000..bf18c4e
--- /dev/null
+++ b/reverse.py
@@ -0,0 +1,16 @@
+#!/usr/bin/env python3
+"""Reverse: restore PR Elowen to its prev status. DRY-RUN default; live needs --apply + ZEROFIX_CONFIRM=YES."""
+import os,sys,json,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")
+live="--apply" in sys.argv and os.environ.get("ZEROFIX_CONFIRM")=="YES"
+for r in json.load(open(os.path.join(HERE,"data","worklist.json"))):
+ if not live: print(f"WOULD: {r['num']} -> {r['prev_status']}"); continue
+ tok=token()
+ req=urllib.request.Request(f"https://{SHOP}/admin/api/{API}/products/{r['num']}.json",
+ data=json.dumps({"product":{"id":int(r['num']),"status":r['prev_status']}}).encode(),method="PUT",
+ headers={"X-Shopify-Access-Token":tok,"Content-Type":"application/json"})
+ urllib.request.urlopen(req,timeout=40); print(f"OK: {r['num']} -> {r['prev_status']}")
(oldest)
·
back to Zero Price Fix
·
(newest)