[object Object]

← back to Designer Wallcoverings

min2/step2 top-up runner for 74 post-0630 roll products; wave-1 dims push + Kamatera write-back executed (Steve-approved)

015b437f5fdb5bf16bff6cb00fe02c6d1c0ac2b5 · 2026-07-02 10:43:04 -0700 · Steve

Files touched

Diff

commit 015b437f5fdb5bf16bff6cb00fe02c6d1c0ac2b5
Author: Steve <steve@designerwallcoverings.com>
Date:   Thu Jul 2 10:43:04 2026 -0700

    min2/step2 top-up runner for 74 post-0630 roll products; wave-1 dims push + Kamatera write-back executed (Steve-approved)
---
 shopify/scripts/build-min2-topup-targets.py | 71 +++++++++++++++++++++++++++++
 1 file changed, 71 insertions(+)

diff --git a/shopify/scripts/build-min2-topup-targets.py b/shopify/scripts/build-min2-topup-targets.py
new file mode 100644
index 00000000..f2d653ed
--- /dev/null
+++ b/shopify/scripts/build-min2-topup-targets.py
@@ -0,0 +1,71 @@
+#!/usr/bin/env python3
+"""Build /tmp/dwtt_af_target.json + /tmp/prod_state.json + /tmp/var_state.json
+for set-dwtt-annafrench-roll-min2-step2.py, scoped to the qmin-missing ROLL rows
+in the latest dwtt-af-spec-audit.json (part 2 of the approved wave-1 memo,
+2026-07-02). Read-only against Shopify."""
+import json, os, time, urllib.request
+
+TOKEN = os.environ["SHOPIFY_ADMIN_TOKEN"]
+SHOP = os.environ.get("SHOPIFY_SHOP", "designer-laboratory-sandbox.myshopify.com")
+URL = f"https://{SHOP}/admin/api/2024-10/graphql.json"
+
+AUDIT = os.path.expanduser(
+    "~/Projects/Designer-Wallcoverings/shopify/scripts/audits/dwtt-af-spec-audit.json")
+
+Q = """
+query($id: ID!) {
+  product(id: $id) {
+    id
+    pmin: metafield(namespace:"global", key:"v_prods_quantity_order_min"){ value }
+    punits: metafield(namespace:"global", key:"v_prods_quantity_order_units"){ value }
+    variants(first: 20) { nodes { id title
+      vmin: metafield(namespace:"custom", key:"v_prod_quantity_order_min"){ value }
+      vunits: metafield(namespace:"custom", key:"v_prods_quantity_order_units"){ value }
+    } }
+  }
+}"""
+
+def gql(query, variables):
+    body = json.dumps({"query": query, "variables": variables}).encode()
+    req = urllib.request.Request(URL, data=body, headers={
+        "X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json"})
+    with urllib.request.urlopen(req) as r:
+        d = json.loads(r.read())
+    if d.get("errors"):
+        raise RuntimeError(d["errors"])
+    return d["data"]
+
+audit = json.load(open(AUDIT))
+targets, prod_state, var_state = [], {}, {}
+missing = [r for vend in ("Thibaut", "Anna French")
+           for r in audit["rows"][vend] if r.get("roll") and not r.get("qmin")]
+print(f"qmin-missing roll rows from audit: {len(missing)}")
+
+for i, r in enumerate(missing, 1):
+    gid = r["id"]
+    pid = gid.rsplit("/", 1)[1]
+    d = gql(Q, {"id": gid})["product"]
+    roll_vars = [v for v in d["variants"]["nodes"] if "roll" in v["title"].lower()]
+    if not roll_vars:
+        print(f"  SKIP {r['mfr']} — no Roll-titled variant")
+        continue
+    prod_state[pid] = {
+        "v_prods_min": (d["pmin"] or {}).get("value"),
+        "v_prods_units": (d["punits"] or {}).get("value"),
+    }
+    tvars = []
+    for v in roll_vars:
+        vid = v["id"].rsplit("/", 1)[1]
+        var_state[vid] = {"min": (v["vmin"] or {}).get("value"),
+                          "units": (v["vunits"] or {}).get("value")}
+        tvars.append({"id": vid, "title": v["title"]})
+    targets.append({"product_id": pid, "mfr": r["mfr"], "handle": r["handle"],
+                    "variants": tvars})
+    if i % 20 == 0:
+        print(f"  ...{i}/{len(missing)} fetched")
+    time.sleep(0.25)
+
+json.dump({"targets": targets}, open("/tmp/dwtt_af_target.json", "w"), indent=1)
+json.dump(prod_state, open("/tmp/prod_state.json", "w"), indent=1)
+json.dump(var_state, open("/tmp/var_state.json", "w"), indent=1)
+print(f"targets written: {len(targets)} products, {len(var_state)} roll variants")

← 7c27f65f discontinued-sweep: contrarian gate addendum — SAMPLE-sku cl  ·  back to Designer Wallcoverings  ·  auto-save: 2026-07-02T10:47:21 (8 files) — pending-approval/ 0f8eb1f0 →