← back to Dwjs Bolt Single Roll Fix
README.md
73 lines
# dwjs-bolt-single-roll-fix
## ✅ STATUS 2026-06-29: APPLIED LIVE (Apartment Wallpaper, 38 SKUs)
Executed with Steve's go. Verified on live `www.designerwallcoverings.com`:
option `Price Per Single Roll`, price `$31.86`, `global.v_prods_quantity_order_min=2`,
`v_prods_quantity_order_units=2` (definition-backed; read via singular `metafield()` —
the `metafields(first:N)` connection does NOT enumerate them, a Shopify gotcha).
Every order now consumes a full $34 bolt (2 × $31.86 = $63.72, ~47% margin). Leak closed.
`rollback.json` retained for one-command restore.
**Still open:** Phillipe Romano `GPR` "Glam" bolt line (21 leakers) — source unconfirmed
(unregistered prefix, not York `PSW####RL`), NO cost loaded → investigate source + load
cost before any relabel (Steve's call, 2026-06-29). Do NOT relabel on a guess.
---
Stops a confirmed **below-cost money leak** on the Jeffrey Stevens / Apartment
Wallpaper peel & stick line (York "Magnolia Home Premium Peel + Stick",
`PSW####RL`) on the live DW Shopify store (`designer-laboratory-sandbox`).
## The leak (confirmed)
- Order #32456 sold **DWJS-17621** as variant **"Price Per Bolt" @ $31.86**.
- A **bolt = double roll = 2 rolls**. Vendor net cost = **$34.00 per double roll**
(York portal). York ships **only un-splittable $34 double rolls** (Steve, 2026-06-29).
- $31.86 collected vs $34.00 cost shipped = **below cost on every unit**, before margin.
## Cohort (38 active variants, all option `Size = "Price Per Bolt"`)
| count | live price | reading |
|------:|-----------:|---------|
| 11 | $31.86 | single-roll price on a bolt unit → **leaking** |
| 3 | $34.31 | ~single-roll price → leaking |
| 14 | $65.00 | correct **bolt** price (≈ $34 / .65 / .85) |
| 10 | $60.00 | ~bolt price |
## The fix (Steve's decision: sell by single roll, normalize, never lose money)
Because York ships an **un-splittable $34 double roll**, a true qty-1 single-roll
sale at $31.86 would strand the 2nd roll and still lose money. The only
loss-proof way to offer a ~$31.86 single-roll price is to **sell in pairs** —
the same mechanism RL wallcovering already uses (min 2 / step 2). Per variant:
1. **Relabel** option value `Price Per Bolt` → `Price Per Single Roll`.
2. **Price** = `$31.86` (single-roll retail; ≥ $30.77 DW floor on $17/roll).
3. **Order minimum** metafields on the product (the live theme renders these
onto the cart qty input):
- `global.v_prods_quantity_order_min` = `2`
- `global.v_prods_quantity_order_units` = `2` (even qty only → whole bolts)
- `global.unit_of_measure` = `Priced Per Single Roll`
### Result — never below cost, never a stranded roll
Every order consumes a full $34 bolt: **2 × $31.86 = $63.72 revenue / $34 cost
= ~$29.72 margin (~47%)**.
- 14 leaking SKUs: effective bolt revenue $31.86 → **$63.72** (leak closed).
- 24 bolt-priced SKUs: ~$63.72 ≈ current $60–65 (revenue ~unchanged), now
consistent single-roll UX.
## Files
- `mapping.csv` — current → proposed per variant (38 rows; 27 price changes).
- `apply-single-roll-fix.js` — snapshot-first, **GATED** executor.
- Default = read-only: writes `rollback.json` (current option value + price +
order-min metafields) and prints the plan. Writes **nothing** to Shopify.
- `--execute --i-have-steve-go` = perform the live writes (rename + price +
metafields), snapshot-first, fail-closed on any userError.
- `--rollback rollback.json --execute --i-have-steve-go` = restore.
## Gate
This is a **customer-facing live Shopify write = Steve-gated**. Do not run
`--execute` until Steve signs the pending-approval memo and says go.
Open prerequisite to re-confirm: York truly cannot ship a separable single roll.
## Cost
$0 — local psql + Shopify Admin GraphQL (no per-call charge).