Commit Graph

18 Commits

Author SHA1 Message Date
type-two
00e08a86dd feat(sku): canonical 14-digit timestamp SKUs so RFID/EPC tagging works (new items)
RecordGod generated 'RG'+random-hex SKUs, which the SCANGOD EPC codec rejects
(it requires 14 digits: SKU × 10^9 + release_id packed onto the UHF chip). New
inventory now gets a 14-digit product-added timestamp (YYYYMMDDHHMMSS) via
_fresh_sku(), which bumps a second on collision to stay unique against the sku
PRIMARY KEY. release_id stays its own column (the sku+space+release_id string is
only the physical chip encoding, which the codec already builds).

New items only — existing 'RG' SKUs are untouched (they keep working; they just
aren't RFID-taggable until re-SKU'd, a separate migration if ever wanted).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 03:34:27 +10:00
type-two
db1788bfe5 feat(app): payments/packs/discogs-mp/dealgod modules + admin, shop, sales route work
Batch-committing the in-flight app work (all modules compile clean):
- app/payments.py, app/packs.py, app/discogs_mp.py, app/dealgod.py (new)
- admin_routes, main, navigator/sales/shop routes, site/search.html
- customer_woo_sync + disc_sync tweaks; test_dealgod_supply, test_startup_ddl

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 23:07:28 +10:00
type-two
d489e8807d feat(buylist): wishlist scarcity ranking via DealGod /api/supply
DealGod shipped POST /api/supply (store_count + discogs_seller_count per release). RecordGod half:
PRICEGOD scrapes the RareWaves wishlist (www.rarewaves.com/pages/wishlist) → /products/<ean>- barcodes +
colour-from-slug → POST /admin/wishlist/scarcity → resolve barcodes → batch DealGod /api/supply → upsert
buylist (store_count/au_copies/lowest_au/discogs_seller_count/discogs_lowest + already_stocked). New 🎯 Buy
list admin view ranks rarest-first (store_count asc, sellers asc), flags colour vinyl + already-stocked.
Endpoints /admin/{wishlist/scarcity, buylist, buylist/clear}; _dealgod_supply batches ≤200. Verified e2e on
6 real wishlist items: ranked 0-store rarest first, AU prices live, sellers backfill per DealGod's pin sweep.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 12:07:48 +10:00
type-two
ef37063b2e feat(distro): Inertia xlsx ingest + cost/new-used/margin in inventory editor
(1) Inventory edit modal gains Cost + New/Used + a live Margin readout (price−cost, %); inv_edit accepts
cost_price + condition_type; inventory list returns them.
(2) Inertia/Warner SOH list = an xlsx that doubles as the order form (fill ORDER QTY, upload). New
/admin/intake/distro-sheet[/preview]: openpyxl parses header-mapped columns (ORDER QTY/UPC/ARTIST/TITLE/
FORMAT/PPD), takes rows with QTY>0 → shared _ingest_distro core (refactored out of the RareWaves path) →
staged NEW stock with cost_price=PPD, kind from FORMAT (cd/vinyl), catno kept. Upload+preview UI in New stock.
DistroItem gains kind+catno; RareWaves path now passes kind too. Verified on the real 3,368-row Warner sheet:
3 ordered titles → 4 copies, all resolved, kind=cd, cost from PPD. Added openpyxl to requirements.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 11:39:39 +10:00
type-two
926468a8b5 feat(distro): RareWaves order ingest → cost-tracked NEW stock + approval landing
End-to-end: PRICEGOD scrapes a RareWaves order (account.rarewaves.com/orders/<id>) → POST /admin/intake/distro
→ resolve barcode→release_id (normalised: DB barcodes stored inconsistently, functional index on digits-only +
EAN/UPC leading-zero variants; Discogs barcode-search fallback) → stage one NEW copy per qty with cost_price +
cost_source, in_stock=false. Idempotent per order. New '/admin/newstock' approval queue: staff confirm/re-pick the
release (trgm search), set retail, flip new/used → publish (staged=f, in_stock=t). Bulk publish-all-matched-&-priced.
Backend verified e2e (ingest→queue→approve→live, unapproved stay staged). PRICEGOD: rarewaves.js content script +
account.rarewaves.com host perm + wowplatter.distro + bg rwDistro handler (needs extension reload to test live).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 11:13:48 +10:00
type-two
9a66f59bfe feat(auth): staff email+password login + password reset (login stays token-based under the hood)
Staff were stuck pasting a raw bearer token with no reset. Now: a proper /login page (email+password)
that exchanges to the staff member's existing token (SPA unchanged downstream). PBKDF2 hashing (stdlib,
no bcrypt dep). New: POST /auth/login, POST /auth/change-password (self), POST /admin/staff/{id}/password
(admin reset). staff gains email(unique)/phone/pay_rate/password_hash. Staff admin UI: add/edit details,
set-password, and timecards now show pay (hours × rate). admin.html redirects to /login when unauthed +
bounces expired tokens; nav gets Change-password + Sign-out. Owner master token still works (break-glass on
the login page). Verified e2e: login, wrong-pw 401, token auth, admin reset invalidates old pw.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-26 16:24:34 +10:00
type-two
a57b74700c feat(admin): System tab — read-only Postgres health (db size/version/uptime/conns/cache-hit, largest tables, data freshness)
Admin-only /admin/system; no maintenance buttons (PG autovacuums, infra owns backups).
The useful 10% of WowPlatter's System page; the WP cache/transients/WP-CLI/debug rest dropped.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 18:44:44 +10:00
type-two
6a95efb9bb fix(report): count paid+completed sales (migrated=paid), fix hour :00 bind-param, add format breakdown
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 18:26:57 +10:00
type-two
336d525585 feat(admin): comprehensive lazy dashboard + reports workbench (Chart.js)
Dashboard: fast KPI tiles (instant /stats) + lazy 30-day revenue line + stock-by-format
donut. Reports rebuilt into a parameterized workbench — date presets (7d/30d/90d/12mo/all
+ custom from/to) × dimension (trend/genre/style/format/condition/payment/weekday/hour +
top releases/artists/labels/customers) × metric (revenue/count), each chart fetched ON
DEMAND. New /admin/report/{kpis,series,breakdown,top,stock} (whitelisted dims, bound dates).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 18:22:17 +10:00
type-two
b46930d468 feat(staff): time clock — clock on/off = shift = timecard
staff_shift table (one open shift per staff via partial unique index). /admin/clock
(status+today total), /clock/in (idempotent), /clock/out; /admin/timecards (admin)
= per-staff hours + recent shifts over a window. search.html top bar gets a live
clock widget (🟢 On 2h14m · Clock off · Log out; Clock on when off) ticking every 30s;
Log out warns if still clocked on. admin Staff tab gains a Timecards report.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:40:02 +10:00
type-two
5e2a9e7ab1 feat(auth): staff accounts + roles — operators run the store, admins keep the keys
Token resolver now checks the env owner-token (admin) then a staff table (name/token/
role). New require_admin gates /settings/* (API keys/connections) + staff CRUD; everything
operational (search/scan/inventory/labels/intake) stays on require_token so staff can do it.
admin.html: /admin/me drives ROLE; data-admin nav (Staff + Connections) hidden for staff +
go() blocks the views; new Staff tab to add operators, set role, reset/show token once,
deactivate. Tokens shown once on create.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 15:33:19 +10:00
type-two
48f8579bff feat(shop): P4 wantlist — public 'request a record' page + admin queue
Storefront /wantlist form (themed, email-keyed, guest-friendly) posts to
/shop/wantlist → wantlist table (lazy DDL). Release pages deep-link to it
(prefilled; 'not in stock — request this record' when no copies). Admin gets
a Wantlist tab: pending/found/fulfilled queue with one-click status actions.
Default storefront menu → Records + Wanted.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 01:29:00 +10:00
type-two
d6e75667bf feat(customers): CRM — list with spend/orders/last + record page (overview stats, editable info, mailing opt-in, sales history)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 23:17:11 +10:00
type-two
a817b9d163 feat(import): bulk stock-in — resolve Release ID/barcode/catno against disc_release → create inventory (UI + endpoint)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 22:48:43 +10:00
type-two
4ece321b76 feat(inventory): CRUD backend (add/edit/delete/bulk) — first cream from the WowPlatter audit; + migration audit doc
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 22:39:17 +10:00
type-two
b4cdc8aee4 feat(admin): Store Map + Intake/Crates/Reports 2026-06-21 20:03:08 +10:00
3732dfa325 feat(admin): Intake, Crates, Reports views + endpoints 2026-06-21 19:50:47 +10:00
1f388f241c feat(admin): MEGA admin dash + /admin endpoints (stats/inventory/orders) 2026-06-21 19:19:56 +10:00