← back to Elitis Price 2026

exec/ws4_cleanup.py

76 lines

#!/usr/bin/env python3
"""WS4 - post-reconciliation cleanup of 3 pre-existing Elitis defects (live).
1) Retitle scraped-sentence garbage titles on VP-963-01/-03 to real pattern 'Osorno'.
2) Archive the mongrel 'Raffia Ii Vp 1048 02' product that dodged the WS2 VP-1048
   archive and collides on SKU DWEL-142747 with the legit 'Frivole' VP-1036-44.
Idempotent (checks current state first). $0 (Shopify Admin API is free).
Steve-approved via AskUserQuestion 2026-07-11 (options A + B)."""
import sys
import os
import csv
import datetime
sys.path.insert(0, "lib")
from shopify import gql

LEDGER = os.path.join("ledger", "ws4_cleanup.csv")
M_UPD = """mutation($input:ProductInput!){ productUpdate(input:$input){
  product{ id legacyResourceId title status handle } userErrors{ field message } } }"""

RETITLE = [
    (7787408261171, "Osorno 01 | Elitis"),   # was: Vp 963 01 Is Offered up...
    (7789388660787, "Osorno 03 | Elitis"),   # was: Vp 963 03 Is Offered up...
]
ARCHIVE = [
    (7787007475763, "Raffia Ii Vp 1048 02 | Elitis"),  # mongrel dup -> ARCHIVED
]


def gid(pid):
    return f"gid://shopify/Product/{pid}"


def log(action, pid, before, after, 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", "action", "product_id", "before", "after", "status"])
        w.writerow([datetime.datetime.now().isoformat(timespec="seconds"),
                    action, pid, before, after, status])


def run():
    for pid, newtitle in RETITLE:
        cur = gql("query($id:ID!){ product(id:$id){ title } }", {"id": gid(pid)})["product"]
        if cur["title"] == newtitle:
            print(f"  [skip] {pid} already '{newtitle}'")
            log("retitle", pid, cur["title"], newtitle, "SKIP")
            continue
        r = gql(M_UPD, {"input": {"id": gid(pid), "title": newtitle}})
        ue = r["productUpdate"]["userErrors"]
        if ue:
            print(f"  [ERR] {pid}: {ue}")
            log("retitle", pid, cur["title"], newtitle, "ERR:" + str(ue))
            continue
        print(f"  [ok] retitle {pid}: {cur['title'][:40]!r} -> {newtitle!r}")
        log("retitle", pid, cur["title"], newtitle, "OK")
    for pid, title in ARCHIVE:
        cur = gql("query($id:ID!){ product(id:$id){ status title } }", {"id": gid(pid)})["product"]
        if cur["status"] == "ARCHIVED":
            print(f"  [skip] {pid} already ARCHIVED")
            log("archive", pid, title, "ARCHIVED", "SKIP")
            continue
        r = gql(M_UPD, {"input": {"id": gid(pid), "status": "ARCHIVED"}})
        ue = r["productUpdate"]["userErrors"]
        if ue:
            print(f"  [ERR] {pid}: {ue}")
            log("archive", pid, title, "ARCHIVED", "ERR:" + str(ue))
            continue
        print(f"  [ok] archive {pid}: {title!r} ({cur['status']} -> ARCHIVED)")
        log("archive", pid, title, "ARCHIVED", "OK")


if __name__ == "__main__":
    run()
    print("\nWS4 cleanup done.")