← back to Hollywood Price 2026

build_524_split.py

98 lines

#!/usr/bin/env python3
"""Split the 524 'absent' Needs-Price Hollywood products (Steve 2026-07-12):
  - PRICE the ones still live on Momentum (col3 pattern-prefix resolves to a live
    Momentum pattern WITH a price) -> plan_169.csv (price = pattern price x 1.448).
  - ARCHIVE the rest (no live Momentum pattern match) -> archive_355.csv.
Pattern-level pricing is valid (Momentum prices are per-pattern, verified). $0."""
import sys
import json
import os
import urllib.request
import re
import csv
sys.path.insert(0, "lib")
from shopify import gql

HI = os.path.expanduser("~/Projects/hollywood-import")
KEY = "95fe8376edc78d49e787db49edda68426b21649f6271f49e2f1412118612fbd6"
HOST = "https://ms-e886719d86e7-4256.sfo.meilisearch.io"
MARKUP = 1.448


def live_patterns():
    out = {}; off = 0
    while off < 20000:
        req = urllib.request.Request(f"{HOST}/indexes/redesign-colors/search",
            data=json.dumps({"q": "", "limit": 1000, "offset": off,
                "attributesToRetrieve": ["pattern_name", "price", "UOM"]}).encode(), method="POST",
            headers={"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"})
        hits = json.load(urllib.request.urlopen(req, timeout=40)).get("hits", [])
        if not hits:
            break
        for h in hits:
            pn = (h.get("pattern_name") or "").strip().lower()
            if pn and h.get("price"):
                out[pn] = {"price": h["price"], "uom": h.get("UOM")}
        off += len(hits)
        if len(hits) < 1000:
            break
    return out


def col3_pattern(c3):
    return re.split(r'[_-]?(sg|a|bx|l2|nv|hi|mi|nfr)?[\d]', c3 or "", flags=re.I)[0].replace("_", " ").strip().lower()


def main():
    absent = {str(r["mfr"]).strip(): r for r in json.load(open(HI + "/mom-col3-absent.json")) if r.get("mfr")}
    staged = {str(r["mfr"]).strip() for r in json.load(open(HI + "/mom-col3-staged.json")) if r.get("mfr")}
    lp = live_patterns()
    print(f"live Momentum patterns w/ price: {len(lp)}")
    Q = """query($q:String!,$after:String){ products(first:200, after:$after, query:$q){ pageInfo{hasNextPage endCursor}
      edges{ node{ id legacyResourceId title variants(first:5){ edges{ node{ sku } } } } } } }"""
    prods, cur = [], None
    while True:
        d = gql(Q, {"q": "vendor:'Hollywood Wallcoverings' status:active tag:Needs-Price", "after": cur})
        p = d["products"]; prods += [e["node"] for e in p["edges"]]
        if not p["pageInfo"]["hasNextPage"]:
            break
        cur = p["pageInfo"]["endCursor"]

    def base(n):
        for e in n["variants"]["edges"]:
            sk = (e["node"]["sku"] or "")
            if sk.lower().endswith("-sample"):
                return sk[:-len("-sample")]
        return None

    price_rows, arch_rows = [], []
    for n in prods:
        sb = base(n)
        if not sb or sb not in absent or sb in staged:
            continue
        c3 = absent[sb].get("col3", "") or ""
        pat = col3_pattern(c3)
        # confident match: normalized col3-pattern EXACTLY equals a live pattern name
        rec = lp.get(pat) if len(pat) > 3 else None
        if rec and (rec.get("uom") in (None, "YD", "SY")):
            price_rows.append({"gid": n["id"], "product_id": n["legacyResourceId"], "title": n["title"],
                "sku_base": sb, "unit": (rec.get("uom") or "YD"),
                "hw": round(rec["price"] * MARKUP, 2), "list": rec["price"],
                "mom_pattern": pat, "col3": c3})
        else:
            arch_rows.append({"gid": n["id"], "product_id": n["legacyResourceId"], "title": n["title"],
                "sku_base": sb, "col3": c3, "dwPattern": absent[sb].get("dwPattern")})
    for fn, rows in [("plan_169.csv", price_rows), ("archive_355.csv", arch_rows)]:
        if rows:
            with open(fn, "w", newline="") as f:
                w = csv.DictWriter(f, fieldnames=list(rows[0].keys())); w.writeheader(); w.writerows(rows)
    print(f"PRICE-LIVE (exact pattern match): {len(price_rows)} -> plan_169.csv")
    print(f"ARCHIVE (no live match):          {len(arch_rows)} -> archive_355.csv")
    if price_rows:
        for r in price_rows[:6]:
            print(f"    price: {r['title'][:34]:34} {r['mom_pattern']!r:14} list ${r['list']} -> hw ${r['hw']}")


if __name__ == "__main__":
    main()