Modules: - parser.py: Full Excel parser (1,848 machines, Disney mapping, Pattern A+B parsing) - db_writer.py: SQLite writer with per-field update policy (seed + update modes) - backup.py: GPS/photo backup, restore, and compare - reporter.py: Comprehensive validation report generator - main.py: CLI entry point Database: assets.db with 1,848 machines across 36 columns Handbook: reference_handbook.md v2.0 — all sections finalized Report: validation_report.md — 184 OCR corrections, 143 unknown machines
31 KiB
🌱 Seed Data Import — Reference Handbook
Source data: Machine_List.xlsx (raw Cantaloupe export, 1,848 machines, 62 columns) Seed subset: import_seed.csv (headers stripped, sales columns = "Deleted") Handbook version: 2.0 — merged with Excel analysis + Disney address lookup
1. Customer Column → Company / Disney Park
Status: ✅ COMPLETE
The Customer column maps to company in the database. For non-Disney customers, it's the direct business name.
Disney Customers (prefix D-)
Customers starting with D- are Disney properties. 469 machines (25% of fleet) are at Disney locations. The customer name tells us which property:
| Customer Prefix | Property Name | Category | Base GPS |
|---|---|---|---|
D-ART OF ANIMATION |
Art of Animation Resort | resort | 28.3499, -81.5678 |
D-All Star Music |
All-Star Music Resort | resort | 28.3362, -81.5735 |
D-All Star Sports |
All-Star Sports Resort | resort | 28.3379, -81.5740 |
D-BAY LAKE TOWER |
Bay Lake Tower at Contemporary | resort | 28.4145, -81.5714 |
D-BLIZZARD BEACH |
Blizzard Beach Water Park | park | 28.3507, -81.5734 |
D-Boardwalk |
Disney's BoardWalk Inn | resort | 28.3680, -81.5577 |
D-Celebration |
Celebration (Admin) | office | 28.3248, -81.5364 |
D-ContemporaryHotel |
Disney's Contemporary Resort | resort | 28.4145, -81.5714 |
D-DISNEY VENDING |
Disney Support Services | support | 28.4100, -81.5800 |
D-DISNEY WORLD SS |
Disney World Support Services | support | 28.3720, -81.5610 |
D-DRC |
Disney Regional Center | office | 28.4666, -81.4305 |
D-Disney Springs |
Disney Springs | park | 28.3705, -81.5175 |
D-FORT WILDERNESS |
Fort Wilderness Resort & Campground | resort | 28.4100, -81.5480 |
D-GRAND FLORIDIAN |
Disney's Grand Floridian Resort | resort | 28.4105, -81.5890 |
D-POLYNESIAN RESORT |
Disney's Polynesian Village Resort | resort | 28.4085, -81.5715 |
D-POP CENTURY |
Disney's Pop Century Resort | resort | 28.3460, -81.5710 |
D-PORT ORLEANS FrQt |
Port Orleans French Quarter | resort | 28.3985, -81.5480 |
D-Port Orleans Rvsd |
Port Orleans Riverside | resort | 28.3950, -81.5450 |
D-RIVIERA RESORT |
Disney's Riviera Resort | resort | 28.3680, -81.5493 |
D-Saratoga Springs |
Saratoga Springs Resort & Spa | resort | 28.3655, -81.5250 |
D-Treehouse Villas |
Treehouse Villas (Saratoga Springs) | resort | 28.3650, -81.5250 |
D-WIDE WORLD SPORTS |
ESPN Wide World of Sports | park | 28.3275, -81.5920 |
D-WILDERNESS LODGE |
Disney's Wilderness Lodge | resort | 28.4120, -81.5860 |
D-Winter Summerland |
Winter Summerland Mini Golf | park | 28.3510, -81.5750 |
D-YACHT AND BEACH |
Disney's Yacht & Beach Club Resorts | resort | 28.3665, -81.5560 |
Match rule: Case-insensitive prefix match. D-Art of Animation Guest → Art of Animation. D-Port Orleans Rvsd GUEST → Port Orleans Riverside.
2. Place Column → Location Fields
Status: ✅ COMPLETE (Excel data analyzed)
The Place column has two distinct patterns — the parser must detect which applies.
Pattern A: Simple (~1,379 rows, 75%)
Format: Venue Name-Venue Detail-Venue Detail (dash-separated)
The last meaningful segment after the last dash is the place. Common suffixes to strip:
Breakroom,Br,Break Room,BREAKROOM,BREAK AREAVending Area,VendingBreak,Breakroom(with trailing spaces)
Examples:
Sygma - Vending-Sygma - Vending Breakroom → place = "Sygma - Vending"
Imperial Dade-Imperial Dade- Breakroom → place = "Imperial Dade"
Ancora Apt.-Ancora Apt. Breakroom → place = "Ancora Apt."
Delamarre-Delamarre Breakroom → place = "Delamarre"
BMW Service-BMW Breakroom → place = "BMW"
Kisselback Ford-Kisselback Ford Breakroom → place = "Kisselback Ford"
Sam's Club-Sam's Club → place = "Sam's Club"
BREAK AREA-BREAK AREA → place = "BREAK AREA"
Building 1180-Building 1180 → place = "Building 1180"
136 unique Pattern A tails in the data. Many have floor/building prefixed:
BLDG10/11 - Hilton Worldwide
2ND FL CARDIO WAITING ROOM
13th St-BREAKROOM
1ST FL BREAK
2nd Floor Front Tower
AHS - Flamingo
Extraction rule:
- Split on
- - Take the last non-empty segment
- Strip known suffixes (
Breakroom,Vending,Break, etc.) - Extract floor info if present:
NTH FL,Floor N,Nth Floor - Extract building info:
BLDG #,Building N - Remaining text is the
placename
Pattern B: Complex Disney (~469 rows, 25%)
Format: PersonName - Address-G-Zone FLOOR
Structure breakdown:
[Person Name] - [Address]-[G-][Zone] [FLOOR]
Todd J - 901 Tinberline Dr -G- REAR 6TH FL
Becky N - 200 Celebration - Disney Park & Tickets Ki
Sarah W - 4401 Floridian Way-G- BUILDING 9 LOBBY
Extraction steps:
-
Strip person prefix:
<FirstName> <Initial> -or<FirstName> <LastInit> -- Pattern:
^[A-Z][a-z]+\s+[A-Z]?\s*-\s* - Removes:
Todd J -,Sarah W -,Justin M -,Brenda G -
- Pattern:
-
Strip address: Typically a building number + street name at the start
- Must identify by pattern:
^\d+\s+\w+\s+\w+\s*(?:Dr|Blvd|Way|Ct|Ln|Ave) - Addresses seen: 901 Timberline Dr, 4401 Floridian Way, 2101 Epcot Resorts Blvd, etc.
- Must identify by pattern:
-
Strip
G-prefix if present (it's a zone/location marker) -
Extract floor info from the remainder using patterns:
NTH FL→1ST FL,6TH FL,3RD FL,4TH FLNth FLOOR→1ST FLOOR,2nd FLOOR,4th FLOORFL N→FL 2Nth floor→7th floorNST FL→1ST FL
-
Extract building info:
BLDG #N,Building N,Bldg NDAAR N,DAAR B-N(Disney building codes)TOWER N,Loop N
-
Extract zone/area (the remaining text after stripping floor/building):
LOBBY,BUS STOP,POOL,Cafeteria,Wardrobe- ePort/NAYAX/CMS structure details
Disney place suffix examples (after stripping person + address):
| Customer | Cleaned Place Suffix | Building | Floor | Zone |
|---|---|---|---|---|
| Wilderness Lodge | G-REAR 6TH FL | REAR | 6TH FL | — |
| Wilderness Lodge | G-South End 7th floor | South End | 7th floor | — |
| Wilderness Lodge | G-CENTER 3RD FL | CENTER | 3RD FL | — |
| Wilderness Lodge | G-FW VILLAS 1ST FL | FW VILLAS | 1ST FL | — |
| Pop Century | G-BLDG 1 50A 1ST FL | BLDG 1 50A | 1ST FL | — |
| Pop Century | G-BLDG 10 70B 2ND FL | BLDG 10 70B | 2ND FL | — |
| Art of Animation | G-DAAR 1-1ST FL | DAAR 1 | 1ST FL | — |
| Art of Animation | G-DAAR 10-2ND FL | DAAR 10 | 2ND FL | — |
| Art of Animation | G-COZY CONE POOL | — | — | COZY CONE POOL |
| Art of Animation | G-NEMO POOL | — | — | NEMO POOL |
| All Star Sports | G-Sports #1 - 2ND FL | SPORTS #1 | 2ND FL | — |
| All Star Sports | G-SPORTS GRAND SLAM POOL | — | — | GRAND SLAM POOL |
| All Star Sports | G-SPORT SURF'S UP LAUNDRY | — | — | SURF'S UP LAUNDRY |
| Contemporary Hotel | G-CONT HOTEL TOWER 10 | TOWER 10 | — | — |
| Contemporary Hotel | G-CONT HOTEL SA FRONT | — | — | SA FRONT |
| Boardwalk | Hotel 2nd Floor Left | — | 2nd Floor | Left |
| Boardwalk | Villas 3 FL by room | — | 3 FL | by room |
| Grand Floridian | G-BUILDING 5 LOBBY | BUILDING 5 | — | LOBBY |
| Grand Floridian | G-GF 2nd Floor | — | 2nd Floor | GF |
| Riviera | G-2ND FLOOR NORTH | — | 2ND FLOOR | NORTH |
| Saratoga Springs | Carousel Bldg 7501 | Carousel 7501 | — | — |
| Saratoga Springs | Congress Bldg 1101-1436 | Congress 1101-1436 | — | — |
| Fort Wilderness | G-FW LOOP 1400 | FW LOOP 1400 | — | — |
| Fort Wilderness | G-FW Meadows POOL 1400 | — | — | Meadows POOL |
| Polynesian | G-POLY BLDG 10 MOOREA 1ST | MOOREA | 1ST | BLDG 10 |
| Polynesian | G-POLY BLDG 4 TUVALU-2ND | TUVALU | 2ND | BLDG 4 |
| French Quarter | G-PO FRENCH QTR B2 | BLDG B2 | — | — |
| French Quarter | G-Bus Stop A | — | — | Bus Stop A |
| Riverside | G-PO RIVERSIDE 80S | 80S | — | — |
| Riverside | G-PO RIVERSIDE BLD | — | — | — |
| Riverside | G-WEST DEPOT BUS STOP | — | — | WEST DEPOT BUS |
| Port Orleans | Bus Stop A | — | — | Bus Stop A |
| Yacht & Beach | G-Beach Club Laundry | — | — | Beach Club Laundry |
| Yacht & Beach | G-Yacht Laundry | — | — | Yacht Laundry |
Zone Prefixes (Disney)
Many Disney place suffixes have a G- prefix (Guest) or C- prefix (Cast). These indicate audience:
G-= Guest area (hotel lobbies, pools, bus stops)C-= Cast/Backstage area (wardrobe, breakrooms, maintenance)
Strip G- and C- from the place field but store them as a zone_type metadata field.
Floor Extraction — Unified Rules
The data has floors expressed in these formats:
| Raw | Normalized | Digestible |
|---|---|---|
6TH FL |
6th Floor |
6 |
7th floor |
7th Floor |
7 |
FL 2 |
Floor 2 |
2 |
1ST FL |
1st Floor |
1 |
2ND FLOOR |
2nd Floor |
2 |
3 RD FLOOR |
3rd Floor |
3 |
4th FLOOR |
4th Floor |
4 |
14th FLOOR |
14th Floor |
14 |
5T (Contemporary tower) |
Floor 5 |
5 |
2N, 2 fl |
Floor 2 |
2 |
Note: Contemporary Resort uses tower suffix notation: 5T, 6T, 7T, 8T, 9T, 10, 11, 12, 14 — the T suffix stands for Tower.
3. GPS Derivation for Multi-Floor Machines
Status: ✅ COMPLETE
Key insight: It varies by building. Some buildings have machines stacked in the same spot across floors, others have multiple machines on one floor in different locations, or machines in different spots on different floors. GPS derivation must be conservative — never assume two machines share GPS without verification.
Considerations from the data:
- Disney resorts: 469 machines across 25 properties, many multi-floor (4-14 floors)
- Pop Century: 42 machines across 4 floors in 10 buildings (BLDG 1-10)
- Art of Animation: 46 machines across 4 floors in 10 buildings (DAAR 1-10)
- Wilderness Lodge: 20 machines across 3 zones (CENTER, REAR, DOCK) × multiple floors
- Contemporary Resort: Bay Lake Tower (4 floors), Contemporary Tower (floors 5-14), multiple zones
- All Star Sports: Building 9 has a machine on each floor — same spot
- All Star Sports: Has separate pool/laundry machines (different location entirely)
- Saratoga Springs: Multiple buildings spread across the property (Carousel, Congress, Grandstand, etc.)
- Port Orleans Riverside: Machines at bus stops and in buildings — same address, different spots
Base GPS Strategy
- Property GPS — Use the Disney property GPS from the mapping table as the starting point for address geocoding
- Existing GPS is authoritative — If a machine already has GPS in the database, preserve it (field-collected is authoritative)
- Floor assumption — If machine A at
901 Tinberline Dr - REAR 6TH FLhas GPS, that GPS is usable for machine B at901 Tinberline Dr - REAR 5TH FL(same zone, adjacent floor) - Zone distinction — Do NOT share GPS across zones. REAR → REAR only. CENTER → CENTER only. Pool → Pool only.
- Building distinction — Do NOT share GPS across different buildings on the same property. BLDG 1 → BLDG 1 only, not BLDG 2.
- Bus stops — Each bus stop at Fort Wilderness / Port Orleans needs its own GPS
- Non-Disney machines — Use geocoded address coordinates from the address column
GPS Proximity Confidence Levels
| Situation | Confidence | Action |
|---|---|---|
| Same building + same zone + adjacent floor (±1 floor) | ✅ High | Auto-apply GPS |
| Same building + same zone + far floor | ⚠️ Medium | Auto-apply with flag for review |
| Same building + different zone | ❌ Low | Do NOT auto-apply |
| Same address + different building | ❌ Low | Do NOT auto-apply |
| Non-Disney, exact same address | ✅ High | Auto-apply with address geocode |
4. Serial Number Validation & OCR Correction
Status: ✅ COMPLETE (data analyzed from Excel + import_seed.csv)
Standard Serial Formats Found
| Format | Example | Likely Make | Notes |
|---|---|---|---|
| All digits, 9-12 chars | 168020939, 471011958 |
Crane / AMS | Standard numeric format |
Starts with 1- prefix |
1-16018993, 1-1711-0396 |
AMS | Dash-separated |
Starts with 1 (10+ digits) |
112034419, 145192104106 |
Crane / USI | All digits, no dashes |
Starts with 222 (12 digits) |
222001280013 |
Newer Crane | Telemetry-equipped |
###-###### format |
472-052119, 449-011276 |
Crane | Model-prefixed serial |
124473010109 (12 digits) |
124473010109 |
USI Mercato | USI standard |
15S49... (suspect OCR) |
15S491811573 |
Crane | S→5 correction needed |
Likely OCR Errors Found
| Machine ID | Raw Serial | Suspected Correct | Pattern |
|---|---|---|---|
| 60017 | 15S491811573 |
155491811573 |
S → 5 |
| 60025 | 15S491811581 |
155491811581 |
S → 5 |
| 60028 | I5s331807595 |
155331807595 |
I → 1, s → 5 |
| 60032 | I5SS331807593 |
1555331807593 |
I5SS → 1555 |
| 60035 | 15S491811599 |
(check — likely same S→5) | S → 5 |
OCR Character Confusion Table
| Mistyped | Should Be | Context |
|---|---|---|
S |
5 |
S looks like 5 in some fonts |
s |
5 |
Lowercase s scanned as 5 |
I |
1 |
Capital I is indistinguishable from 1 |
O |
0 |
Letter O vs digit zero |
B |
8 |
B scanned as 8 (less common) |
G |
6 |
G scanned as 6 (less common) |
Validation Algorithm
For each serial:
- Strip non-alphanumeric chars (dashes, spaces, dots)
- Apply OCR correction:
S→5,s→5,I→1,O→0,B→8,G→6 - Check length: valid serials are 9-14 characters after cleaning
- Flag as placeholder if serial is < 5 characters after cleaning
- Flag as invalid if all chars are the same (e.g.,
0000000000)
Placeholder / Invalid Serials
| Machine ID | Serial | Action |
|---|---|---|
| 60031 | 520 |
Clear to blank |
| 68194 | 123 |
Clear to blank |
| 99660 | 00 |
Clear to blank |
Rule: Any serial < 5 characters after cleaning → set to blank and flag for manual entry.
5. Type/Class/Make/Model Consolidation
Status: ✅ COMPLETE (Excel data analyzed)
The Priority Rule
The Type column is the best source for Class/Make/Model. Parse it first, then fill gaps from the standalone Class, Make, Model columns.
Type Column Format
CLASS (MAKE MODEL)
Extraction:
"Snack (AMS Sensit 3)" → Class=Snack, Make=AMS, Model=Sensit 3
"GF Food (Crane 472)" → Class=Food, Make=Crane, Model=472
"Bev (Royal GIII)" → Class=Bev, Make=Royal, Model=GIII
"NATIONAL - 168 SERIES" → Class=Snack, Make=Crane, Model=168
"VENDO - 721" → Class=Bev, Make=Vendo, Model=721
"Unknown" → All three = Unknown
Full Type Pattern Distribution
| Type Pattern | Count | Class → DB | Make → DB | Model → DB |
|---|---|---|---|---|
Bev (Royal GIII) |
299 | Bev | Royal | GIII |
Snack (Crane Merchant Media) |
287 | Snack | Crane | Merchant Media |
Bev (Vendo 621/721/821) |
235 | Bev | Vendo | 621/721/821 |
GF Food (Crane 472) |
151 | Food | Crane | 472 |
Snack (Crane 15x/16x) |
76 | Snack | Crane | 15x/16x |
Unknown |
67 | Unknown | Unknown | Unknown |
GF Bev (DN 200E) |
49 | Bev | DN | 200E |
GF Bev (DN 5800) |
35 | Bev | DN | 5800 |
Snack (Crane 186) |
34 | Snack | Crane | 186 |
GF Bev (DN BevMax 4) |
34 | Bev | DN | BevMax 4 |
Bev (DN 501E/600E/276E) |
34 | Bev | DN | 501E/600E/276E |
Snack (Crane 472) |
26 | Snack | Crane | 472 |
Bev (DN 276E) |
25 | Bev | DN | 276E |
GF Bev (DN 3800 BevMax 4) |
20 | Bev | DN | 3800 BevMax 4 |
GF Bev (DN Baby BevMax) |
19 | Bev | DN | Baby BevMax |
Bev (DN 501E) |
18 | Bev | DN | 501E |
GF Bev (DN BevMax) |
18 | Bev | DN | BevMax |
Snack/Bev (Crane 472) |
16 | Snack/Bev | Crane | 472 |
Snack (Crane 187) |
16 | Snack | Crane | 187 |
NATIONAL - 168 SERIES |
16 | Snack | Crane | 168 |
VENDO - 721 |
14 | Bev | Vendo | 721 |
Snack (AMS 3561) |
12 | Snack | AMS | 3561 |
Snack (USI Mercato) |
10 | Snack | USI | Mercato |
Snack (VE) |
10 | Snack | VE | Unknown |
NATIONAL - 186 |
10 | Snack | Crane | 186 |
NATIONAL - 187 |
10 | Snack | Crane | 187 |
Total unique Type patterns in data: 30+
GF Prefix Rule
Strip GF prefix from the Class field. The GF prefix means "Glass Front" — it's a physical descriptor, not a class.
| Raw Class | DB Class |
|---|---|
GF Food |
Food |
GF Bev |
Bev |
GF Snack |
Snack (if present) |
The GF prefix IS useful — it tells us the machine has a glass front. Store it as a boolean field is_glass_front = true.
Make Normalization
| Raw Value | Normalized To |
|---|---|
Crane, Crane Co, Crane Nat, NATIONAL, Crane National |
Crane |
DN, Dixie Narco |
DN |
Royal, Royal Vendors |
Royal |
Vendo, Vendo Co |
Vendo |
USI, U Select It |
USI |
AMS, Automatic Merchandising |
AMS |
VE |
VE |
AP, Automatic Products |
AP (if present) |
Faz, Fas |
Fas (if present) |
Class Normalization
| Raw Value | DB Class |
|---|---|
Snack, Snack/Food |
Snack |
Bev |
Bev |
GF Food |
Food (strip GF) |
GF Bev |
Bev (strip GF) |
Food |
Food |
Snack/Bev |
Snack/Bev (combo machine) |
Special/Non-standard Type Parses
| Raw Type | Rule |
|---|---|
NATIONAL - 168 SERIES |
Make=Crane (National IS Crane), Model=168, Class=Snack |
NATIONAL - 186 |
Make=Crane, Model=186, Class=Snack |
NATIONAL - 187 |
Make=Crane, Model=187, Class=Snack |
VENDO - 721 |
Make=Vendo, Model=721, Class=Bev |
Snack/Bev (Crane 472) |
Special combo class. Splits to Class=Snack/Bev |
Snack (VE) |
Make=VE, let Model = Unknown or check standalone Model column |
Snack (no parens) |
Class=Snack. Check standalone Make and Model columns |
Bev (no parens) |
Class=Bev. Check standalone columns |
Unknown |
Leave all three as Unknown — flag for manual identification |
6. Remote Pricing Status — Meanings
Status: ✅ COMPLETE (Excel data analyzed)
Distribution (from 1,848 machines)
| Status | Count | Meaning |
|---|---|---|
| On | 614 (33%) | Remote pricing is active and working. CMS/ePort can push price changes. |
| Action Required | 718 (39%) | Issue preventing remote pricing: No Dex Passcode configured, Bad Coil Count mismatch, or configuration error. Needs technician attention. |
| Incompatible | 516 (28%) | Machine does not support remote pricing. Older model requiring EEEPROM upgrade, or pre-telemetry machine. |
Practical Meanings
"On" — Working normally. Prices can be updated remotely. No action needed.
"Action Required" — Common causes:
- No Dex Passcode configured for the control board
- Coil count mismatch (machine has physically different coils than what's configured)
- Connection issue between telemetry module and vending controller
- Action: Technician needs to check the DEX cable, passcode, or coil configuration
"Incompatible" — Hardware limitation:
- Machine pre-dates remote pricing support
- Requires EEEPROM upgrade to support remote pricing
- Some older Crane 472, 167, 168 models
- May still accept DEX data for sales — just can't receive price changes
- Action: If revenue justifies it, consider EEEPROM upgrade kit. Otherwise, accept as-is.
Update Policy
When re-importing: auto-overwrite pricing status from the export. This is dynamic data.
7. Telemetry ID → Card Reader Decoder
Status: ✅ COMPLETE (Excel data analyzed)
Telemetry Provider Patterns
The Device column (Telemetry ID) contains the telemetry module identifier. The suffix in parentheses reveals the provider:
| Telemetry ID Pattern | Provider | Reader Type | Count |
|---|---|---|---|
VJ... (ePort) |
ePort (USI/Crane) | Cantaloupe ePort telemetry | ~400 |
K3CT... (ePort) |
ePort (Crane) | Cantaloupe ePort telemetry | ~300 |
VK... (ePort) |
ePort | Cantaloupe ePort telemetry | ~200 |
... (NAYAX) |
Nayax | Nayax card reader (Myna, Topper, VPOS Touch) | 275 |
... (CMS) |
Crane Merchandising Systems | CMS telemetry/reader | 628 |
| All-numeric (no suffix) | Unknown | Unknown/other | 21 |
Provider Detail
- ePort — Cantaloupe (formerly USI/ePort) telemetry module. These connect to the machine's control board via DEX/MDB and report sales, inventory, and health data. Supports remote pricing when compatible. Predicts card reader: Cantaloupe ePort built-in or external.
- NAYAX — Nayax cellular telemetry device. Connects via MDB and supports cashless payments. Models: Myna, Topper, VPOS Touch. Nayax devices typically have their own cellular connection and work independently of the machine's control board.
- CMS — Crane Merchandising Systems integrated telemetry. Crane's proprietary system built into Crane machines (Merchant Media, 472, 167/168, etc.). May be integrated or external.
Card Reader Mapping (Rule-Based)
| Provider | Reader Brand | Notes |
|---|---|---|
| ePort | Cantaloupe | Cantaloupe ePort module includes card reader |
| NAYAX | Nayax | Nayax reader (Myna, Topper, VPOS Touch) |
| CMS | CMS | Crane integrated reader |
Distribution (1,848 machines)
| Provider | Count |
|---|---|
| ePort | 924 (50%) |
| CMS | 628 (34%) |
| Nayax | 275 (15%) |
| Other/unknown | 21 (1%) |
Update Policy
Telemetry provider is relatively stable — auto-overwrite if changed, but changes are rare between exports.
8. Alert Meanings
Status: ✅ COMPLETE (4 alert types categorized)
Alert Types Found
The raw export (Excel) has a Coil Alerts and Product Alerts column in addition to the general Alerts column.
| Alert Text | Severity | Meaning |
|---|---|---|
| (empty / none) | — | No alerts |
| Scheduled service on Monday, May 25, 2026 | Info | Future service scheduled |
| Scheduled for service today | Info/Warning | Same-day service scheduled |
| Out of touch for 19 hours | Critical | Telemetry offline > 19 hours |
| Out of touch... (combined with service notice) | Critical | Multiple issues |
Coil Alerts (from Excel)
The raw export has a Coil Alerts column (count of coil issues) and Product Alerts column (out-of-stock or jammed products). These are numeric counts, not text strings.
Alert Categorization
| Alert | Severity | Show in app list? | Meaning |
|---|---|---|---|
| Scheduled service (future date) | Info | ✅ Yes, show badge | A tech has been scheduled to visit. No action needed — informational. |
| Scheduled service today | Info | ✅ Yes, show badge | A tech has been scheduled for today. Nothing to action — heads up. |
| Out of touch (telemetry lost >19h) | Critical | ✅ Yes, show badge | Telemetry offline for 19+ hours. Machine can't report sales or receive price changes. Needs investigation. |
| Out of touch + service needed | Critical | ✅ Yes, show both icons | Combined: critical telemetry issue + info service notice. Both badges shown. Overall state = Critical. |
9. Sales Priority Scoring
Status: ✅ COMPLETE (1,826 of 1,848 machines have yearly sales data)
Sales Data Available in Excel
| Column | Description | Range |
|---|---|---|
| Yearly Sales | Primary — Total annual sales per machine | $10.50 - $206,230 |
| Monthly Sales | Last 30 days sales | varies |
| Weekly Sales | Last 7 days sales | $1.50 - $18,314.50 |
| Daily Average Sales | Per-day average | $0.22 - ~$565 |
| Today Sales | Current day sales | varies |
| Yesterday Sales | Previous day sales | varies |
| Sales (Restock) | Sales since last restock | varies |
| Days Since Restock | Days since last service | 0 - 30+ |
Rule: Priority is computed from Yearly Sales only. Use the standalone columns in the Excel export.
Yearly Sales Distribution (1,826 machines with data)
| Percentile | Yearly Sales ($) |
|---|---|
| 10th | $818.50 |
| 25th | $1,948.50 |
| 50th (median) | $4,425.50 |
| 75th | $8,357.30 |
| 90th | $15,848.50 |
| 95th | $23,747.75 |
| 99th | $64,118.50 |
| Max | $206,230.00 |
Priority Tiers
| Priority | Yearly Sales Range | % of Fleet |
|---|---|---|
| Low | ≤ $2,000 | ~25% (456 machines) |
| Mid | $2,001 - $15,000 | ~65% (1,187 machines) |
| High | $15,001+ | ~10% (183 machines) |
Update Policy
Priority is a computed field — recalculate on every import. Always auto-overwrite.
10. Asset List & Detail Screen Spec
Status: ✅ COMPLETE
Asset List Card
Each asset card in the main app list should show:
- Machine ID
- Class badge (Snack / Bev / GF Food)
- Make · Model
- Location (place, address)
- Yearly sales ($)
- Priority badge (Low / Mid / High)
- Alert indicator (A badge with the text or count)
- Remote pricing status (On / Action Required / Incompatible)
Not shown on card:
- Disney park badge — in detail view only
- GPS badge — in detail view only
- Card reader type — in detail view only
- Last contact / dex time — in detail view only
Asset Detail Screen
The detail view sections in order:
- Identity — Machine ID, Make · Model, Class badge, Serial number, Photo (if available)
- Location — Place, Building, Floor, Zone, Address, City, Disney park badge, GPS coordinates
- Sales & Priority — Yearly sales, Priority badge, Monthly/Weekly/Daily sales
- Technical — Remote pricing status, Telemetry provider, Card reader type, Glass front indicator
- Alerts & Status — Alert text, Pricing status badge, Last contact time, Days since restock
- History — Install date, Last DEX report, Deployed/Pulled dates, Route info
Editable sections (from admin panel):
- Location fields (place, building, floor, GPS)
- Photo upload
- Serial number (manual correction)
Read-only (from import):
- Make, Model, Class
- Sales data & priority
- Telemetry / card reader info
- Alerts
11. Update Policy — Per-Field
Status: ✅ COMPLETE (all per-field policies defined)
For each field, specify how updates from new seed data should be handled:
| DB Column | Source | Policy | Notes |
|---|---|---|---|
machine_id |
Machine ID | preserve | Primary key, never changes |
serial_number |
Serial Number | auto (+ flag) | Accept with OCR correction. Flag placeholder/invalid |
name |
Generated (Make + Place) | auto | Build from Make + Place fields |
make |
Type→Make (parsed) | auto | ✅ |
model |
Type→Model (parsed) | auto | ✅ |
class |
Type→Class (parsed) | auto | Strip GF prefix |
is_glass_front |
Type→Class | auto | true if raw Class starts with GF |
company |
Customer | auto | Direct map |
place |
Place (parsed) | auto | Stripped of breakroom/vending suffixes |
building_name |
Place (parsed) | auto | From Pattern A/B extraction |
floor |
Place (parsed) | auto | Normalized floor |
zone |
Place (parsed) | auto | Lobby, pool, bus stop, etc. |
zone_type |
Place (parsed) | auto | guest vs cast (G- vs C-) |
address |
Address | auto | Direct map |
location_area |
City | auto | Direct map |
latitude |
Derived | preserve | Field-collected is authoritative |
longitude |
Derived | preserve | Field-collected is authoritative |
photo_path |
— | preserve | Never overwrite |
dex_report_date |
Last Dex Report Time | auto | Fresh data replaces old |
install_date |
Added Date | preserve | Set once on first import |
deployed |
— | preserve | Set by field operations |
pulled_date |
— | preserve | Set by field operations |
disney_park |
Customer (parsed) | auto | From Disney mapping table |
remote_pricing_status |
Status (Remote Pricing) | auto | Dynamic data |
alerts |
Alerts | auto | Fresh alerts replace old |
telemetry_provider |
Telemetry ID (parsed) | auto | Parsed from suffix |
card_reader_brand |
Telemetry ID (parsed) | auto | From provider mapping |
priority |
Computed from sales | auto | Recalculated on every import |
yearly_sales |
Yearly Sales | auto | ✅ |
monthly_sales |
Monthly Sales | auto | ✅ |
weekly_sales |
Weekly Sales | auto | ✅ |
days_since_restock |
Days Since Restock | auto | ✅ |
prepick_group |
Prepick Group | auto | ✅ |
has_cashless |
Has Cashless | auto | Direct map |
Policy values: auto = always overwrite from new data, preserve = never touch existing value
Appendix A: Column Mapping (Raw Excel → DB)
| Excel Column | DB Column | Extract Type |
|---|---|---|
| Device (Telemetry ID) | telemetry_provider, card_reader_brand |
Parse suffix (ePort) / (NAYAX) / (CMS) |
| Location | — | Redundant (Customer + Address) |
| Asset ID | machine_id |
Direct (primary key) |
| Place | place, building_name, floor, zone, zone_type |
Complex parse (Pattern A or B) |
| Type | class, make, model, is_glass_front |
Parse CLASS (MAKE MODEL) |
| City | location_area |
Direct |
| Address | address |
Direct |
| Last Contact Time | — | Freshness indicator (not stored) |
| Last Dex Report Time | dex_report_date |
Direct |
| Last Restock | — | Not stored |
| Sales (Restock) | — | Not stored |
| Daily Average Sales | — | Not stored |
| Today Sales | — | Not stored |
| Yesterday Sales | — | Not stored |
| Weekly Sales | — | Not stored |
| Monthly Sales | — | Not stored |
| Yearly Sales | yearly_sales |
Used for priority scoring |
| Days Since Restock | days_since_restock |
Used for priority scoring |
| Prepick Group | prepick_group |
Direct |
| Customer | company (non-Disney) or disney_park + company=Disney |
Direct + Disney parsing |
| Management Company | — | Not stored |
| Route | — | Not stored (routing info) |
| State | — | Not stored |
| Postal Code | — | Not stored |
| Serial Number | serial_number |
Validate + OCR correct |
| Class | class (fallback) |
Type column takes priority |
| Make | make (fallback) |
Type column takes priority |
| Model | model (fallback) |
Type column takes priority |
| Has Cashless | has_cashless |
Direct (Yes/No → bool) |
| Added Date | install_date |
Direct (set once) |
| Status | remote_pricing_status |
On / Action Required / Incompatible |
| Alerts | alerts |
Parsed to structured alerts |
| Deployed | deployed |
Yes/No |
| Pulled Date | pulled_date |
Direct |
Appendix B: Non-Disney Customers (sample identifying patterns)
Many non-Disney customers follow recognizable patterns:
- The Sygma Network — food distribution/manufacturing
- Imperial Dade — janitorial supply distributor
- Wood Springs Suites — hotel
- Ancora Apartments — apartment complex
- Southern Technical College — educational
- AdventHealth — hospital/medical
- BMW Service — automotive
- Kisselback Ford — automotive
- Hilton Worldwide — hotel chain (multiple buildings: BLDG2/3 through BLDG19/12)
- Sam's Club — retail
- Finfrock — manufacturer
- Walt Disney World Cast Credit Union — credit union
Version 2.0 — Complete reference handbook for the seed data import pipeline. All sections reviewed and finalized.