Hello user — please read & accept before continuing
1. Confidential Information
By accessing the Pop Spot Analytics Portal ("the Portal"), you acknowledge that all data, reports, dashboards, transfer recommendations, store-level inventory figures, sales statistics, supplier information, product catalogs, pricing, and any other information contained herein constitute the confidential and proprietary information of Bingo Group ("the Company").
2. Permitted Use
The Portal and its contents are provided solely for internal business use by authorized personnel of the Company in the performance of their job duties. You agree to use the Portal exclusively for legitimate, work-related purposes and to maintain strict confidentiality of all information accessed.
3. Restrictions
You shall NOT, under any circumstances:
(a) Disclose, share, transmit, publish, or otherwise communicate any data, screenshots, exports, or insights from the Portal to any third party, competitor, vendor, contractor, family member, or unauthorized individual;
(b) Reproduce, copy, screenshot, photograph, or duplicate any portion of the Portal or its data except as expressly required for internal business reporting;
(c) Use the data for any personal benefit, competitive purpose, or commercial activity outside of your authorized employment;
(d) Discuss specific store performance, stock levels, transfer plans, or financial figures in public spaces, social media, or with any party outside the Company;
(e) Retain copies of any exported reports after termination of your engagement with the Company.
4. CSV Exports & Reports
All CSV files, reports, and data exports generated through the Portal remain the property of Bingo Group and are subject to this Agreement. They must be stored securely, accessed only by authorized personnel, and destroyed upon request of the Company or upon termination of your engagement.
5. Security
You agree to keep your access credentials confidential and not share them with any other person. Any suspected unauthorized access must be reported immediately to the Bingo Group IT administrator. You are responsible for all activity that occurs under your login.
6. Duration & Survival
The obligations of confidentiality herein shall survive the termination of your employment, contract, or engagement with the Company, and shall remain in effect indefinitely with respect to all confidential information accessed through the Portal.
7. Consequences of Breach
Any breach of this Agreement may result in immediate termination of access, disciplinary action up to and including termination of employment, civil action for damages, and where applicable criminal prosecution under the laws of the Arab Republic of Egypt.
8. Acknowledgement
By clicking "Accept & Enter Portal", you acknowledge that you have read, understood, and agree to be bound by this Non-Disclosure & Confidentiality Agreement. Your acceptance creates a binding obligation between you and Bingo Group. This agreement is effective immediately and applies to every session you access.
Penetration: Funko ÷ total company sales for that channel
Top Stores · Funko Share
Stores with highest Funko penetration
Stock by Property
Available units by IP / category
Stock by Series
Available units by product line
🏆 Top 10 Performers
Best performers · toggle each chart between Value & Qty
Top 10 Characters by Sales
Best-performing items by selected metric
Top 10 IPs by Sales
Best-performing IPs / properties by selected metric
Top 10 Lines by Sales
Best-performing product lines by selected metric
Top 10 Items — Wholesale
Top-selling SKUs through wholesale order sources
Channel × Sub-channel Cross-Tab
Product Catalog
· SKUs · click any card to see per-store stock and sales.
INTERNAL · OPERATIONAL DATA
CUSTOMER-FACING CATALOG
Store Performance
Per-store stock and sales analysis — click a row for SKU breakdown.
Transfer Engine
Move dead / slow-moving stock to where it's actually selling — you set the criteria.
How it works · you set the criteria
1. You define "dead stock" Set Days on shelf, Max recent sales, and Min SOH at the FROM store. Anything matching becomes a FROM candidate. Toggle warehouses and consignment in/out.
2. You define "demand" TO = stores selling above your threshold AND nearly out, OR new arrivals (≤ N days on shelf, low SOH) that haven't started selling yet.
3. Smart matching For each demand store, cover ~2 months of recent sales. Pull from warehouses first, then oldest-on-shelf, then highest SOH. Moves already in flight are skipped.
4. You choose the ranking Sort by Revenue Lift (default), Age-Weighted, or Velocity. Priority is a 0–100 score (100 = the top move under the chosen ranking); Revenue Lift stays in EGP. Min priority cuts the tail, and you can click any column header to re-sort.
SCOPE
FROM · DEAD-STOCK CRITERIA
TO · DEMAND CRITERIARANK BY
🚚 Live Transfers 0
Pending & recently-issued transfers from the live system. The recommender below skips moves that are already in flight.
Recommendations 0
Algorithmic suggestions. In-flight transfers above are excluded.
Reports
One-click exports. All CSV files open in Excel / Google Sheets.
Master Data
Full Sheet
All items · photos · catalog + per-store Stock/Sales/Sales Period + company & retail totals — mirrors the master sheet
Master Inventory
Full Export
Every SKU · every store · SOH + sales
Overstock Report
Risk
Stock that isn't moving · value at risk
OOS Best Sellers
Lost Sales
Top sellers with zero stock somewhere
Store P&L Summary
Per-Store
Revenue · stock value · turnover by store
License Performance
By IP
Revenue / SOH / unit count by license
Transfer Plan
Action
Full ranked transfer recommendations
⏳ Online & Pre-Order
Pipeline
Pre-order pipeline + online channels
📦 Warehouse Stock
Push Plan
All warehouse stock · push-to-store priorities
🤝 Consignment
3rd-Party
Hamleys + Hedeya stock per SKU
Channel Breakdown
Admin · Data Upload
Upload the 5 source Excel files. Each upload overwrites the matching table in Supabase.
1 · Supabase Admin Key
Required to write data. From Supabase → Settings → API Keys → service_role key.
No key entered — uploads will fail until you save a key above.
⚠ Security: The service_role key bypasses RLS. Only paste it here on a private machine — never commit this HTML with the key inside. The key is stored in sessionStorage and cleared when you close the tab.
2 · Upload the 5 files
Drop or pick each .xlsx, validate, then upload. Recommended order: Products → Stock → Transfers → History → Sales Orders.
ℹ How uploads work: Each file replaces only its own table (full delete + re-insert) — there is no cross-table cascade. You can upload any subset; the dashboard reflects whatever is currently in Supabase. For a complete refresh, upload all five. The two large files (Transfers ~88k and Sales ~83k rows) insert in 500-row batches, so they take a little while — watch the per-card progress bar.
Expects sheet Historical_Stock (file Transform_Stock_History_Funko_portal_V6.xlsx) with columns:
unique, sku, store_code, location, release_date, current_status, history, days_ofs, company_status The sheet's unique column maps to unique_key; trailing empty columns are ignored.
—
⑤
Sales Orders
→ sales_orders table
pending
Drop .xlsx here or click to choose
— —
Expects sheet Zazome Report (file Sales_Transactions_-_Items.xlsx) with the full 45-column layout, including:
customer_code, store_code, store_name, transaction_number, trx_date, transaction_date, item_code, item_name, quantity_sold, full_price, price, total_sales, total_sales_ex, recall_type, order_number, order_source_name, row_id, page_number (… and the rest).
Period filters read transaction_date. Sales value uses total_sales_ex (ex-VAT line total); returns (quantity_sold < 0) subtract.
—
📖 Pop Spot Portal — User Guide
Pop Spot Analytics is the command-center for the Funko catalog across Bingo Group's 33+ locations. It pulls live data from Supabase (products, stock, transfers, history) and gives you five working views.
DASHBOARD Sales & stock KPIs, channel/sub-channel breakdowns, top brands/IPs/lines/characters. All values are live from Supabase and respond to the 8 filters at the top.
CATALOG All SKUs with per-store stock & sales. Three view modes (rows, rows+photo, gallery). Click any card to drill in.
STORES Per-store summary table. Click a store to open a modal with its full SKU list, sales, and back-office/commercial exports.
TRANSFERS Smart recommendations to move stock from low-velocity stores to high-velocity ones. Live transfers panel shows what's already in flight.
REPORTS One-click downloads of pre-built reports (low stock, dead stock, top sellers, etc.) as CSV or Excel.
Quick navigation
Top-bar tabs switch views. The ← Back button (top-left, when visible) returns to the previous view.
🖨 PDF prints the current view with photos. 📖 GUIDE opens this guide.
☀ LIGHT MODE toggles dark/light theme. Theme persists across sessions.
↩ LOGOUT ends your session.
The Dashboard has 8 multi-select filters along the top. Every chart, KPI, and the cross-tab matrix re-compute live from the filtered SKU × store rows.
Filters by the granular channel attribution from the stock.channels JSON: Store, Wholesale, Cons., popspot, CS, animespot, Bingo.eg, pokespot. When fewer than "all" are selected, qty is summed only from the selected sub-channels.
STORE
Narrows to specific physical/online stores.
BRAND / LICENSE / LINE / IP / CHARACTER
Narrows by product attributes from products table.
Behaviour
Selections update charts live — no Apply needed (Apply just closes the dropdown).
All / None buttons inside each dropdown clear or fill the selection instantly.
The donut chart "Channel Mix" is also a control — click a slice to filter to that channel; click again to restore all.
↻ Reset all restores every filter to "all selected".
⬇ Export CSV exports the current filtered universe + the channel × sub-channel cross-tab.
Stock Position KPIs — global stock figures (always unfiltered, by design).
Channel charts — combo, donut, and % share, all filtered.
Top Brands / Top Stores / Top IPs / Top Lines / Top Characters / Top Wholesale — ranked horizontal bars with Value/Qty toggles.
Channel × Sub-channel Cross-Tab — units (or EGP value) per group × sub-channel pair, with row & column totals.
The Catalog lists every active SKU with computed totals across all stores.
View modes
⊞ ROWS — compact table, no photos. Fastest for scanning.
📷 ROWS + PHOTO — table with a thumbnail column.
◫ GALLERY — 3-column card grid with large photos (best for visual browsing & PDF export).
Filters (top toolbar)
Search — fuzzy match across SKU, description, character, license, IP, brand, line.
Status — Available, Limited, Out of Stock, Pre-Order.
Line / IP / License — multi-select dropdowns.
Sort — pick a primary sort field; click again to flip direction.
Click any product row or card to open the Product Detail modal — gallery, per-store stock breakdown, sales history, and the option to download a single-product PDF.
The Stores tab shows one row per store with computed totals.
Columns
Store + channel group pill
SKUs — distinct SKUs present at the store (any stock or sales history)
Stock — total units on hand
Stock Value — Σ(SOH × price) in EGP
Lifetime Sales — total units ever sold
Recent Sales — units sold in the reporting period (from the 1st of the previous calendar month through today)
Sell-Through — sold ÷ (sold + on-hand), as a %
Turnover — recent ÷ on-hand (proxy for inventory velocity)
Dead Stock — units with no recent sales
Click any row to open the per-store modal: full SKU list with the same Back-Office / Commercial export options as the catalog.
The Transfer Engine recommends moves to rebalance stock between stores. You define every threshold — the engine just does the matching and ranking.
FROM criteria · what counts as movable
Days on shelf ≥ N — uses history.days_ofs (true age since release). Blank = no age filter. Recommended: 60–90 for retail dead stock.
Max sold (30d) at FROM ≤ N — defines "slow-moving". Set to 0 for true dead stock, 2–3 for slow movers. Blank = fall back to legacy heuristic (zero recent sales + lifetime ≤ 2, OR turnover < 5%).
Min SOH at FROM ≥ N — don't strip tiny piles. Default 3. Raise this if you want to ignore stores with low stock.
Include WH — when on, warehouse stock is always available as a source (bypasses dead-stock checks — warehouses exist to be pushed out).
Include Cons. — when on, consignment stores (Hamleys, Hedeya) are also valid sources. Off by default.
TO criteria · what counts as demand
Min sold (30d) at TO ≥ N — stores must be selling at least this much to qualify. Default 1. Raise to 5–10 for true high-velocity destinations only.
New-arrival (days ≤ N) — SKUs sitting ≤ N days on a store's shelf with thin SOH (< 5) become auto-demand even with zero sales yet. This is how you push fresh stock to stores that haven't had time to sell yet. Blank = off.
Standard demand rule: store is selling AND (SOH = 0 OR recent ≥ SOH).
Matching
Coverage — for each demand store, target max(recent × 2 − SOH, 2) units. New arrivals get a minimum of 3.
Source order — warehouses first, then oldest-on-shelf, then highest SOH.
Move cap — max 70% of any store's stock per recommendation (warehouses have no cap).
In-flight skip — any (SKU, FROM, TO) already in the pending/issued transfers above is filtered out.
Ranking modes (Rank By selector)
All three modes rank the same set of moves; the Priority column is shown as a 0–100 score (100 = the top-ranked move under the chosen mode), so it reads as a priority index rather than money — Revenue Lift is still shown in EGP. The base unit is "realistic quantity" — the smaller of qty_to_move and recent_sales × 2, so we don't credit overstocking a slow store. New arrivals get a floor of 2 units.
⏳ Days on Shelf — realistic_qty × price × max(1, age_in_months). Same revenue base, but multiplied by how long the FROM stock has been sitting. Clears old stock first.
🔥 Velocity — realistic_qty × price × max(1, turnover) where turnover = recent_sales / SOH at the destination. Pushes to stores that burn through stock fastest.
Live Transfers panel
Lists every pending and recently-issued transfer from the live system. The recommender skips any (SKU, from, to) tuple already in flight, so suggestions stay actionable.
Workflow tip: start broad (defaults), see the top recommendations, then tighten one criterion at a time. The Rank By selector re-sorts instantly — you don't need to press Recalculate just to change ranking mode.
Every metric in the portal is computed from four Supabase tables: products, stock_by_store, transfers, and history. Here's exactly what each term means and how it's calculated.
Stock metrics
SOH (Stock On Hand) stock_by_store.soh — units physically present at a (sku, store).
Total Stock Σ stock_by_store.soh across every store, including consignment.
Stock Value / RSP Σ (soh × products.price) in EGP — total retail value of inventory.
RSP (Ex-Tax) RSP ÷ 1.14 — RSP after removing the 14% Egyptian VAT.
Avg Unit Price Σ products.price ÷ COUNT(products). Mean catalog price, unweighted.
Sales metrics
Units Sold (Qty) Σ sales_orders.quantity_sold over the selected period (returns net out). Note (v4): the stock sheet no longer supplies ttl_sold, so unit sales now come from sales_orders.
Recent Sales / Sales Period Net units sold over a fixed calendar window that begins on the first day of the previous calendar month and runs through today (the latest available date in the period). E.g. run on 11 Jun 2026 → window is 1 May 2026 → 11 Jun 2026; run on 20 Apr 2026 → 1 Mar 2026 → 20 Apr 2026. Derived from sales_orders on transaction_date (returns subtract; per SKU·store floored at 0). This feeds Turnover, Dead Stock and Demand Score too.
Sales Value (EGP) — headline revenue Σ sales_orders.total_sales_ex (Price × Quantity, excluding 14% VAT), read straight from the source so it reconciles to the database. Return lines (quantity_sold < 0) carry a negative value and subtract; free / 100%-discount lines (price 0) add nothing. All-period total ≈ EGP 52.94M.
Revenue per SKU Sales Value ÷ Σ DISTINCT(sku) within the filtered set.
Sales Conversion % COUNT(DISTINCT sku with a non-return sale) ÷ COUNT(products) — share of the catalog that has sold at least one unit.
Sub-channel attribution stock_by_store.channels is a JSON like {"Store": 12, "Wholesale": 3}. We sum the keys you've selected. When all sub-channels are selected, we use ttl_sold directly (avoids missing rows where channels JSON is empty).
Per-store metrics
Sell-Through % ttl_sold ÷ (ttl_sold + soh). Shows how much of what arrived at the store has been sold.
Priority A 0–100 score (100 = the top-ranked move under the chosen ranking: Revenue Lift, Age-Weighted, or Velocity). It normalises the ranking value across the current result set, so higher = a more urgent/valuable transfer. Click any column header to re-sort.
Predicted Lift (EGP) min(qty_recommended, target_soh_at_to) × products.price. Conservative estimate of revenue gained by moving the stock.
Open Transfer MAX(0, quantity_ordered − quantity_received) on orders not yet "Xfr Out Closed" — units still pending in flight. Recommender excludes these from new suggestions.
Drop An initial release to a store (not a rebalance). Note (v4): the new transfers sheet has no is_drop flag, so drops aren't separated from rebalances.
Status taxonomy
Available total_soh ≥ 5 (every product is treated as active — the sheet has no inactive flag).
Limited 0 < total_soh < 5
Out of Stock total_soh = 0
Pre-Order products.classification_code contains "Pre Order" (e.g. "Pre Order 15-7-2026" → that date is the ETA). Overrides the SOH-based statuses.
Channel taxonomy
There are two layers, and they don't mean the same thing:
Channel (Group) — physical/operational grouping of stores. Comes from store metadata.
Bingo RetailSPOT UniverseE-CommerceWarehouseConsignmentPending ReleaseMaintenance
Sub-channel — sale attribution recorded in stock_by_store.channels JSON. Tells you HOW the unit was sold within a store.
StoreWholesaleCons.popspotCSanimespotBingo.egpokespot
Every working view has an export menu (⬇ button). Two formats × two layouts × two file types are usually available.
Format: Back Office vs Commercial
🏢 Back Office — all internal columns (SKU, line, IP, license, brand, per-store stock breakdown, warehouse stock, pending, maintenance, consignment, lifetime sales, recent sales, revenue, pre-order pipeline, stock value, photo URLs). For operations use only.
🏪 Commercial — customer-facing columns only (SKU, description, character, brand, license, line, price, status). Safe to share with retailers.
Layout: Grid vs Gallery
Grid (compact) — dense table. Best when you need many rows on one page.
Gallery (with photos) — 3-column card layout with product photos. Best as a sales catalog or visual reference.
PDF — opens the print dialog. Pick "Save as PDF" as the destination. Tip: choose Landscape orientation when exporting Grid layouts.
PDF tips
For Gallery PDFs, the portal preloads every photo before opening the print dialog — this can take 10–45 seconds for large catalogs. A progress bar shows status.
If photos are missing in your PDF, click "Save as PDF" again — the browser sometimes prints before all images decode.
In Chrome's print dialog, enable "Background graphics" for proper colours.