[object Object]

← back to Designer Wallcoverings

Kravet master price loader: WHLS cost + MAP from GDrive master into kravet_master_price

5ba2c38730d860151e615d2e7f04bc26b0aa5304 · 2026-06-11 15:56:51 -0700 · SteveStudio2

Files touched

Diff

commit 5ba2c38730d860151e615d2e7f04bc26b0aa5304
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Thu Jun 11 15:56:51 2026 -0700

    Kravet master price loader: WHLS cost + MAP from GDrive master into kravet_master_price
---
 shopify/scripts/cadence/kravet-master-loader.py | 145 ++++++++++++++++++++++++
 1 file changed, 145 insertions(+)

diff --git a/shopify/scripts/cadence/kravet-master-loader.py b/shopify/scripts/cadence/kravet-master-loader.py
new file mode 100644
index 00000000..2f59de7a
--- /dev/null
+++ b/shopify/scripts/cadence/kravet-master-loader.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+"""
+kravet-master-loader.py — load Kravet/Lee-Jofa/Cole&Son WHLS cost + MAP + retail from the
+authoritative GDrive master exports into dw_unified.kravet_master_price.
+
+WHY: "always look in GDrive first." The Kravet/LJ master exports carry, per SKU:
+  - Item            (mfr_sku, e.g. GWP-3716.155.0 / 100/1001.CS.0)
+  - WHLS Price      (wholesale COST)
+  - MAP             (minimum advertised price)
+  - Variant Price   (the DW retail historically used)
+  - Unit of measure (we keep ROLL rows — these are sold-per-roll wallcoverings)
+This is the price source for the sample-only Kravet-family wallpapers that have no roll
+variant yet. We prefer master WHLS cost (run through the cost/0.65/0.85 formula, floored at
+MAP) and keep retail as a last-resort fallback.
+
+SAFE: dry-run by default. --commit upserts into its OWN new table kravet_master_price.
+Never touches *_catalog, never touches Shopify.
+
+Usage:
+  python3 kravet-master-loader.py            # DRY-RUN (parse + coverage report)
+  python3 kravet-master-loader.py --commit   # write kravet_master_price
+"""
+import argparse, glob, os, subprocess, sys, tempfile
+
+MARGIN = 0.65 * 0.85   # retail = cost / 0.65 / 0.85
+
+# Each source: gdrive path + sheet + 0-based column indices (verified 2026-06-11).
+SOURCES = [
+    {
+        'gdrive': 'gdrive:Spreadsheets/OLD_MASTER  Coding for KRAVET DATA -  kravet/lj - 2021 (DWTK-500000-538418).xlsx',
+        'sheet': '2022(UL)', 'rank': 2,  # most recent
+        'c_item': 56, 'c_whls': 66, 'c_map': 106, 'c_retail': 19, 'c_unit': 67,
+        'c_brand': 59, 'c_pattern': 57, 'c_color': 58,
+    },
+    {
+        'gdrive': 'gdrive:Spreadsheets/Kravet - Export in Increments of 5000.xlsx',
+        'sheet': 'FInal - CODING', 'rank': 1,
+        'c_item': 71, 'c_whls': 81, 'c_map': None, 'c_retail': 19, 'c_unit': 82,
+        'c_brand': 74, 'c_pattern': 72, 'c_color': 73,
+    },
+]
+
+def num(v):
+    if v in (None, ''):
+        return None
+    try:
+        return float(str(v).replace('$', '').replace(',', '').strip())
+    except (ValueError, TypeError):
+        return None
+
+def cell(row, i):
+    if i is None or i >= len(row):
+        return None
+    return row[i]
+
+def main():
+    ap = argparse.ArgumentParser()
+    ap.add_argument('--commit', action='store_true')
+    ap.add_argument('--sample', type=int, default=8)
+    args = ap.parse_args()
+    import openpyxl
+
+    # mfr_sku -> dict(cost, map, retail, brand, pattern, color, src, rank)
+    recs = {}
+    for src in SOURCES:
+        tmp = tempfile.mkdtemp(prefix='kml-')
+        r = subprocess.run(['rclone', 'copy', src['gdrive'], tmp], capture_output=True, text=True)
+        files = glob.glob(os.path.join(tmp, '*.xlsx'))
+        if not files:
+            print(f"  WARN could not fetch {src['gdrive']}: {r.stderr[:160]}"); continue
+        wb = openpyxl.load_workbook(files[0], read_only=True, data_only=True)
+        if src['sheet'] not in wb.sheetnames:
+            print(f"  WARN sheet {src['sheet']!r} missing in {src['gdrive']}"); continue
+        ws = wb[src['sheet']]
+        it = ws.iter_rows(values_only=True); next(it, None)  # skip header
+        n_roll = 0
+        for row in it:
+            unit = str(cell(row, src['c_unit']) or '')
+            if 'ROLL' not in unit.upper():
+                continue
+            sku = cell(row, src['c_item'])
+            if not sku:
+                continue
+            sku = str(sku).strip()
+            cost = num(cell(row, src['c_whls']))
+            mp = num(cell(row, src['c_map']))
+            retail = num(cell(row, src['c_retail']))
+            if not (cost or retail):
+                continue
+            n_roll += 1
+            prev = recs.get(sku)
+            # prefer the row with a cost; then the higher-rank (newer) source
+            better = (prev is None
+                      or (cost and not prev['cost'])
+                      or (src['rank'] > prev['rank'] and bool(cost) == bool(prev['cost'])))
+            if better:
+                recs[sku] = {
+                    'cost': cost, 'map': mp, 'retail': retail, 'rank': src['rank'],
+                    'brand': str(cell(row, src['c_brand']) or '')[:80],
+                    'pattern': str(cell(row, src['c_pattern']) or '')[:120],
+                    'color': str(cell(row, src['c_color']) or '')[:80],
+                    'src': os.path.basename(src['gdrive'])[:60],
+                }
+        print(f"  [{src['sheet']}] ROLL rows scanned: {n_roll}")
+
+    withcost = sum(1 for v in recs.values() if v['cost'])
+    print(f"\nmaster ROLL SKUs: {len(recs)}  (with WHLS cost: {withcost}, retail-only: {len(recs)-withcost})")
+    print("samples (cost -> formula retail, MAP floor):")
+    for sku, v in list(recs.items())[:args.sample]:
+        formula = round(v['cost'] / MARGIN, 2) if v['cost'] else None
+        sell = max(formula or 0, v['map'] or 0, v['retail'] or 0 if not v['cost'] else 0)
+        print(f"  {sku:<18} cost {v['cost']} map {v['map']} retail {v['retail']} -> formula {formula}  [{v['brand']}]")
+
+    if not args.commit:
+        print("\nDRY-RUN — no writes. Re-run with --commit to load kravet_master_price.")
+        return
+
+    # write TSV + load
+    tmp = tempfile.mkdtemp(prefix='kml-load-')
+    tsv = os.path.join(tmp, 'm.tsv')
+    with open(tsv, 'w') as fh:
+        for sku, v in recs.items():
+            fh.write('\t'.join('' if x is None else str(x) for x in
+                     [sku, v['cost'], v['map'], v['retail'], v['brand'], v['pattern'], v['color'], v['src']]) + '\n')
+    ddl = """
+    CREATE TABLE IF NOT EXISTS kravet_master_price (
+      mfr_sku TEXT PRIMARY KEY, whls_cost NUMERIC, map_price NUMERIC, retail_price NUMERIC,
+      brand TEXT, pattern TEXT, color TEXT, source TEXT, loaded_at TIMESTAMPTZ DEFAULT now());
+    TRUNCATE kravet_master_price;
+    CREATE TEMP TABLE _m(mfr_sku text, whls_cost numeric, map_price numeric, retail_price numeric,
+      brand text, pattern text, color text, source text);
+    \\copy _m FROM '%s'
+    INSERT INTO kravet_master_price(mfr_sku,whls_cost,map_price,retail_price,brand,pattern,color,source)
+      SELECT mfr_sku,whls_cost,map_price,retail_price,brand,pattern,color,source FROM _m
+      ON CONFLICT (mfr_sku) DO NOTHING;
+    SELECT count(*) FROM kravet_master_price;
+    """ % tsv
+    w = subprocess.run(['psql', '-d', 'dw_unified', '-v', 'ON_ERROR_STOP=1'],
+                       input=ddl, capture_output=True, text=True)
+    if w.returncode != 0:
+        sys.exit(f"COMMIT failed: {w.stderr[:400]}")
+    print(f"\n✅ COMMITTED kravet_master_price rows: {w.stdout.strip().splitlines()[-1]}")
+
+if __name__ == '__main__':
+    main()

← 191ba013 schu-reimport: heartbeat to CNCP Looping-LIVE each tick + ma  ·  back to Designer Wallcoverings  ·  Add Kravet roll-variant adder: idempotent, MAP-priced, audit 4e4cff4e →