← back to Hollywood Price 2026
archive_267.py
91 lines
#!/usr/bin/env python3
"""Archive the Hollywood products with no live Momentum match (Steve 2026-07-12,
'archive gone, price live' split) + reflect in dw_unified mirror.
Reads archive_final.csv. Shopify: status->ARCHIVED. dw_unified.shopify_products:
status->ARCHIVED (shopify_id = gid). Idempotent (ledger + skip already-archived).
Reversible (un-archive). $0."""
import sys
import os
import csv
import json
import glob
import re
import subprocess
import datetime
import time
sys.path.insert(0, "lib")
from shopify import gql
CSV = "archive_final.csv"
LEDGER = os.path.join("ledger", "archived.csv")
M_UPD = """mutation($input:ProductInput!){ productUpdate(input:$input){
product{ id status } userErrors{ field message } } }"""
Q = "query($id:ID!){ product(id:$id){ status } }"
def conn():
for f in glob.glob(os.path.expanduser("~/Projects/hollywood-import/**/.env"), recursive=True) + \
glob.glob(os.path.expanduser("~/Projects/hollywood-import/*.env")):
for line in open(f):
m = re.search(r"postgresql://dw_admin:[^\s\"']+@127\.0\.0\.1:5432/dw_unified", line)
if m:
return m.group(0)
return None
def log(pid, title, status):
new = not (os.path.exists(LEDGER) and os.path.getsize(LEDGER) > 0)
with open(LEDGER, "a", newline="") as f:
w = csv.writer(f)
if new:
w.writerow(["ts", "product_id", "title", "status"])
w.writerow([datetime.datetime.now().isoformat(timespec="seconds"), pid, title, status])
def seen():
s = set()
if os.path.exists(LEDGER):
for r in csv.DictReader(open(LEDGER)):
if r["status"].startswith("OK") and r.get("product_id"):
s.add(r["product_id"])
return s
def main():
rows = list(csv.DictReader(open(CSV)))
done = seen()
ok = skip = fail = 0
archived_gids = []
for i, r in enumerate(rows):
pid = str(r["product_id"]); gid = r["gid"]
if pid in done:
skip += 1; continue
cur = gql(Q, {"id": gid})["product"]
if not cur:
log(pid, r["title"], "SKIP:not-found"); skip += 1; continue
if cur["status"] == "ARCHIVED":
log(pid, r["title"], "OK:already-archived"); archived_gids.append(gid); ok += 1; continue
d = gql(M_UPD, {"input": {"id": gid, "status": "ARCHIVED"}})
ue = d["productUpdate"]["userErrors"]
if ue:
log(pid, r["title"], "FAIL:" + json.dumps(ue)[:120]); fail += 1; continue
log(pid, r["title"], "OK"); archived_gids.append(gid); ok += 1
if (i + 1) % 25 == 0:
print(f" ...{i+1}/{len(rows)} ok={ok} skip={skip} fail={fail}")
time.sleep(0.15)
print(f"SHOPIFY ARCHIVE DONE: ok={ok} skip={skip} fail={fail}")
# reflect in dw_unified mirror
c = conn()
if c and archived_gids:
vals = ",".join("'" + g.replace("'", "") + "'" for g in archived_gids)
sql = f"UPDATE shopify_products SET status='ARCHIVED' WHERE shopify_id IN ({vals});"
r = subprocess.run(["psql", c, "-tAc", sql], capture_output=True, text=True)
print("dw_unified update:", (r.stdout or r.stderr).strip()[:120])
else:
print("dw_unified: skipped (no conn or nothing archived)")
if __name__ == "__main__":
main()