[object Object]

← back to Dw Photo Capture

All GRS- sold PER YARD: flipped 133 products (variant Roll->Per Yard, unit_of_measure->Priced Per Yard, dwc.order_unit->Yard); now 174/174 uniform. createFromSheet defaults to per-yard for future creates. Price unchanged (already per-yard)

a4af440e2c6d51c12f9218ea2e3f130d46c64ce7 · 2026-06-25 06:30:41 -0700 · steve@designerwallcoverings.com

Files touched

Diff

commit a4af440e2c6d51c12f9218ea2e3f130d46c64ce7
Author: steve@designerwallcoverings.com <steve@designerwallcoverings.com>
Date:   Thu Jun 25 06:30:41 2026 -0700

    All GRS- sold PER YARD: flipped 133 products (variant Roll->Per Yard, unit_of_measure->Priced Per Yard, dwc.order_unit->Yard); now 174/174 uniform. createFromSheet defaults to per-yard for future creates. Price unchanged (already per-yard)
---
 data/build.json |  5 +++--
 grs_per_yard.py | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 51 insertions(+), 2 deletions(-)

diff --git a/data/build.json b/data/build.json
index 847bf12..7b98532 100644
--- a/data/build.json
+++ b/data/build.json
@@ -1,5 +1,5 @@
 {
-  "next": 20,
+  "next": 21,
   "map": {
     "578af86f": 2,
     "bc95fdb0": 3,
@@ -18,6 +18,7 @@
     "9905b54e": 16,
     "48c9e659": 17,
     "779f6d1f": 18,
-    "598b1ee5": 19
+    "598b1ee5": 19,
+    "c3efeca8": 20
   }
 }
\ No newline at end of file
diff --git a/grs_per_yard.py b/grs_per_yard.py
new file mode 100644
index 0000000..3e71ef3
--- /dev/null
+++ b/grs_per_yard.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python3
+"""All GRS- products are sold PER YARD. Update: variant option 'Roll'->'Per Yard',
+   global.unit_of_measure->'Priced Per Yard', dwc.order_unit->'Yard'. Price unchanged
+   (already per-yard = cost*0.75). DRY default; CONFIRM=1 writes."""
+import os,sys,json,time,urllib.request
+SHOP="designer-laboratory-sandbox.myshopify.com";API="2024-10";DRY=os.environ.get("CONFIRM","0")!="1"
+TOKEN=""
+for l in open(os.path.expanduser("~/Projects/secrets-manager/.env")):
+    if l.startswith("SHOPIFY_ADMIN_TOKEN="): TOKEN=l.strip().split("=",1)[1];break
+H={"X-Shopify-Access-Token":TOKEN,"Content-Type":"application/json"}
+def api(m,p,pl=None):
+    d=json.dumps(pl).encode() if pl is not None else None
+    r=urllib.request.Request(f"https://{SHOP}/admin/api/{API}"+p,data=d,headers=H,method=m)
+    with urllib.request.urlopen(r,timeout=60) as x: b=x.read().decode();return x.status,(json.loads(b) if b.strip() else {})
+def gql(q,v=None): return api("POST","/graphql.json",{"query":q,"variables":v or {}})[1]
+Q="""query($c:String){products(first:100,query:"vendor:Fentucci",after:$c){pageInfo{hasNextPage endCursor}
+ edges{node{legacyResourceId status uom:metafield(namespace:"global",key:"unit_of_measure"){value}
+  v:variants(first:3){edges{node{legacyResourceId sku title}}}}}}}"""
+c=None;targets=[]
+while True:
+    d=gql(Q,{"c":c})["data"]["products"]
+    for e in d["edges"]:
+        n=e["node"]
+        if n["status"]=="ARCHIVED": continue
+        roll=next((v["node"] for v in n["v"]["edges"] if (v["node"]["sku"] or "").upper().startswith("GRS-") and not (v["node"]["sku"] or "").upper().endswith("-SAMPLE")),None)
+        if not roll: continue
+        uom=(n.get("uom") or {}).get("value")
+        if roll["title"]!="Per Yard" or uom!="Priced Per Yard":
+            targets.append({"pid":n["legacyResourceId"],"vid":roll["legacyResourceId"],"sku":roll["sku"],"title":roll["title"],"uom":uom})
+    if d["pageInfo"]["hasNextPage"]: c=d["pageInfo"]["endCursor"]
+    else: break
+print(f"GRS products to update -> Per Yard: {len(targets)}")
+for t in targets[:6]: print(f"   {t['sku']:12} variant '{t['title']}'->Per Yard | uom '{t['uom']}'->Priced Per Yard")
+if DRY: print("\n[DRY] CONFIRM=1 to apply."); sys.exit()
+n=0
+for t in targets:
+    try:
+        if t["title"]!="Per Yard":
+            api("PUT",f"/variants/{t['vid']}.json",{"variant":{"id":t["vid"],"option1":"Per Yard"}})
+        gql("""mutation($id:ID!){metafieldsSet(metafields:[
+          {ownerId:$id,namespace:"global",key:"unit_of_measure",type:"single_line_text_field",value:"Priced Per Yard"},
+          {ownerId:$id,namespace:"dwc",key:"order_unit",type:"single_line_text_field",value:"Yard"}]){userErrors{message}}}""",
+          {"id":f"gid://shopify/Product/{t['pid']}"})
+        n+=1
+        if n%25==0: print(f"  ...{n}")
+        time.sleep(0.4)
+    except Exception as e: print(f"  ERR {t['sku']}: {e}")
+print(f"\nDONE — set {n} GRS products to Per Yard")

← 3c7d0a2 Add ⭐ Favorites + 🕘 Recent views: star any card to pin SKUs  ·  back to Dw Photo Capture  ·  Multi-photo add: ➕ Multiple in the Photos gallery batch-appe 4e6ec3f →