🌱 Complete seed import tool — all 17 kanban tasks done

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
This commit is contained in:
2026-05-24 21:50:46 -04:00
parent 6743df6859
commit 457e7794a0
9 changed files with 4523 additions and 416 deletions
File diff suppressed because it is too large Load Diff
+615
View File
@@ -0,0 +1,615 @@
# reference_handbook
# 🌱 Seed Data Import — Reference Handbook
> This handbook documents all extraction rules, logic, and reference data
for the canteen seed data import pipeline.
>
>
> Sections marked **FILL_IN** need your domain expertise.
> Sections marked **✅ READY** Ive pre-filled from data analysis.
>
---
## 1. Customer Column → Company/Domain
**Status: ✅ READY**
The `Customer` column in the seed data maps directly to the `company` field in the database.
Its already clean — just the business name. No parsing needed.
### Disney Customers (prefix `D-`)
Customers starting with `D-` are Disney properties. These map to `disney_park`:
| Customer prefix / pattern | Disney Park | Category |
| --- | --- | --- |
| `D-Magic Kingdom` | `magic-kingdom` | Park |
| `D-Epcot` | `epcot` | Park |
| `D-Hollywood Studios` | `hollywood-studios` | Park |
| `D-Animal Kingdom` | `animal-kingdom` | Park |
| `D-Disney Springs` | `disney-springs` | Park |
| `D-ContemporaryHotel` | `resort` | Resort |
| `D-POLYNESIAN RESORT` | `resort` | Resort |
| `D-Port Orleans` | `resort` | Resort |
| `D-CORONADO SPRINGS` | `resort` | Resort |
| `D-ART OF ANIMATION` | `resort` | Resort |
| `D-POP CENTURY` | `resort` | Resort |
| `D-All Star ...` | `resort` | Resort |
| `D-DISNEY WORLD SS` | `office` | Support services |
**FILL_IN**: Add any Disney customer patterns I missed:
-
-
---
## 2. Place Column → Location Fields
**Status: ✅ READY** (patterns identified)
The `Place` column has **two main patterns** — the extraction engine must detect which pattern applies and parse accordingly.
### Pattern A: Simple — ~90% of rows
**Format:** `Venue Name-Venue Detail` (dash-separated, repetitive)
**Examples:**
```
Sygma - Vending-Sygma - Vending Breakroom
Imperial Dade-Imperial Dade- Breakroom
Ancora Apt.-Ancora Apt. Breakroom
Delamarre-Delamarre Breakroom
BMW Service-BMW Breakroom
Kisselback Ford-Kisselback Ford Breakroom
Sam's Club-Sam's Club
BREAK AREA-BREAK AREA
Building 1180-Building 1180
```
**Rule:** Take the last meaningful segment (after the last dash). Strip:
- `Breakroom`, `Br`, `Break Room`, `BREAKROOM`, `BREAK AREA`
- `Vending Area`, `Vending`
- Trailing whitespace and punctuation
### Pattern B: Complex Disney — ~10% of rows
**Format:** `PersonName - Address-G-Zone FLOOR`
**Examples:**
```
Todd J - 901 Tinberline Dr-G-REAR 6TH FL
Carrianne C - 1251 Riversida Dr-G-PO RIVERSIDE 80S
Justin M - 1536 Buena Vista-Team Disney North Win
Penny D - 3520 Ft Wilderness-G-BUS STOP
Sarah W - 4401 Floridian Way-G-BUILDING 9 LOBBY
Brenda G - 2101 Epcot Resorts-Hotel by Room 1290
Jeremy B - 1960 Broadway-2nd FL Brkrm Vacat Club D
```
**Extraction steps:**
1. Strip person name prefix: `<FirstName> <Initial>` or `<FirstName> <LastInit> -`
2. Strip address segment (number + street name)
3. Extract floor info: `NTH FL`, `Nth floor`, `FL N`, `1ST FL`, etc.
1. Extract Building info: `B N`, `Bldg N`, `Mermaid N`, etc
2. Whatever remains is the clean `place` name
### Edge Cases
```
FL8108-Vending Area → place="FL8108", no venue
1st FL Wing-1st Fl Breakroom → floor="1st Fl", place="Wing"
Epcot-Imagination → place="Imagination"
C-MK EASTGATE SECURITY-Be Our Guest → place="Be Our Guest"
Southern Tech University:Sun Life-Sun Life → place="Sun Life" (remove university prefix)
```
### Floor Extraction Patterns
| Pattern | Example | Normalized |
| --- | --- | --- |
| `NTH FL` | `6TH FL` | `6th Floor` |
| `Nth floor` | `7th floor` | `7th Floor` |
| `FL N` | `FL 2` | `Floor 2` |
| `NST FL` | `1ST FL` | `1st Floor` |
**FILL_IN**: Add any special Place patterns or corrections you know about:
-
-
-
---
## 3. GPS Derivation for Multi-Floor Machines
**Status: ⚠️ NEEDS FILL_IN**
### Base GPS Strategy
For machines with no GPS data, we need to derive coordinates:
1. Use existing GPS from other machines at the same address
### Floor Offset Rules
When a base GPS coordinate is found for the building, adjust for floor:
**FILL_IN**: What offset values should we use per floor?
- Does the lat/lng change measurably per floor? No, Machines are usually in the same area directly above. Usually, not always
### GPS Priority
When multiple machines exist at the same address:
1. Use existing GPS from the DB (field-collected is authoritative)
2. Look for other machines on the same floor, on floors above or below, and in the same building
3. Never overwrite existing GPS (preserve policy)
---
## 4. Serial Number Validation & OCR Correction
**Status: ✅ READY** (data analyzed)
### Standard Serial Formats
| Format | Count | Example | Notes |
| --- | --- | --- | --- |
| All digits (10-12 chars) | 1,220 | `168020939`, `471011958` | Crane standard format |
| Starts with `1` (10+ digits) | 175 | `1-16018993`, `112034419` | AMS/Crane prefixed |
| Starts with `222` | various | `222001280013` | Newer Crane format |
| Crane model-prefixed | various | `472-052119`, `449-011276` | Model + serial |
| All digits shorter | various | `124473010109` | USI/Mercato format |
### 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` |
### Known Character Confusions
| Mistyped | Should Be | Context |
| --- | --- | --- |
| `S` | `5` | In numeric serials — S looks like 5 in some fonts |
| `s` | `5` | Same — lowercase s scanned as 5 |
| `I` | `1` | Capital I looks like 1 |
| `O` | `0` | Letter O vs zero |
| `B` | `8` | B scanned as 8 (less common) |
| `G` | `6` | G scanned as 6 (less common) |
**FILL_IN**: Add any other character confusions youve seen:
- ___________ → ___________
- ___________ → ___________
### Placeholder / Invalid Serials
| Machine ID | Serial | Action |
| --- | --- | --- |
| 60031 | `520` | Flag — likely incomplete or placeholder |
| 68194 | `123` | Flag — clear placeholder |
| 99660 | `00` | Flag — clear placeholder |
**FILL_IN**: How should we handle flagged serials? clear it.
---
### Unknown Machine Identification by Serial
**FILL_IN**: How can we identify an unknown machine from its serial number?
- What do different serial prefixes mean? We can look at known good serials and compare with makes/models to determine structure
- Can we cross-reference with Make/Model/Type? We look at known good machines, and look at their serials to figure out structure
- Any known serial → machine type mappings?
---
---
## 5. Type/Class/Make/Model Consolidation
**Status: ✅ READY** (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 columns.
### Type Column Format
> `CLASS (MAKE MODEL)` — e.g., `Snack (AMS Sensit 3)`
>
**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"
"Unknown"
→ All three = "Unknown" (leave as-is)
```
Make sure that if the Class, make, model, etc has a GF prefix then strip it.
### Type Patterns Found
| Type Pattern | Count | Class | Make | Model |
| --- | --- | --- | --- | --- |
| `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 | GF Bev | DN | 5800 |
| `Snack (Crane 186)` | 34 | Snack | Crane | 186 |
| `GF Bev (DN BevMax 4)` | 34 | GF 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 | GF Bev | DN | 3800 BevMax 4 |
| `GF Bev (DN Baby BevMax)` | 19 | GF Bev | DN | Baby BevMax |
| `Bev (DN 501E)` | 18 | Bev | DN | 501E |
| `GF Bev (DN BevMax)` | 18 | GF 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 |
### Special Parse Cases
| Raw Type | Rule |
| --- | --- |
| `NATIONAL - 168 SERIES` | Class=Snack, Make=Crane (National=Crane brand), Model=168 |
| `VENDO - 721` | Class=Bev (if Type doesnt have Class), Make=Vendo, Model=721 |
| `Snack` (no parens) | Class=Snack, check Make/Model columns for fill |
| `Bev` (no parens) | Class=Bev, check Make/Model columns |
| `Unknown` | Leave all Unknown |
### Filling Unknowns
After parsing Type, check the standalone `Make` and `Model` columns to fill gaps.
If Type-based Make is empty but standalone Make has a value, use it.
If both are empty/Unknown, flag for review.
**FILL_IN**: Are there any Type→Make/Model mappings Ive missed?
-
-
### Make Normalization
**FILL_IN**: Consolidate these make variants:
| Raw Value | Normalized To |
| --- | --- |
| `Crane`, `Crane Co`, `Crane Nat`, `NATIONAL` | `Crane` |
| `DN`, `Dixie Narco` | `DN` |
| `Royal`, `Royal Vendors` | `Royal` |
| `Vendo`, `Vendo Co` | `Vendo` |
| `USI`, `U Select It` | `USI` |
| `AMS`, `Automatic Merchandising` | `AMS` |
| `VE`, `Vending Equipment` | ___________ |
| `AP`, `Automatic Products` | ___________ |
| `Faz`, `Fas` | ___________ |
### Class Normalization
| Raw Value | Normalized To |
| --- | --- |
| `Snack`, `Snack/Food` | `Snack` |
| `Bev` | `Bev` |
| `GF Food` | `GF Food` |
| `GF Bev` | `GF Bev` |
| `Snack/Bev` | `Snack/Bev` |
| `Food` | `GF Food` — verify this |
**FILL_IN**: Any other class consolidations?
-
---
## 6. Remote Pricing Status — Meanings
**Status: ✅ READY** (data analyzed)
### Distribution
| Status | Count | Meaning |
| --- | --- | --- |
| **On** | 614 | Remote pricing is active and working normally |
| **Action Required** | 718 | Remote pricing needs attention — may have failed, needs configuration, or other issue |
| **Incompatible** | 516 | Machine does not support remote pricing (older model, EEEPROM Upgrade Required) |
**FILL_IN**: Clarify what each status actually means in practice:
**On** — Working
**Action Required** — No Dex Passcode / Bad Coil Count
**Incompatible** — achine does not support remote pricing (older model, EEEPROM Upgrade Required
Are there any other status values not present in this data?
---
---
## 7. Telemetry ID → Card Reader Decoder
**Status: ✅ READY** (data analyzed)
### Telemetry Provider Patterns
| Telemetry ID Pattern | Provider | Card Reader Type |
| --- | --- | --- |
| `VJ... (ePort)` | ePort (USI/Crane) | ePort telemetry module |
| `K3CT... (ePort)` | ePort (Crane) | ePort telemetry module |
| `VK... (ePort)` | ePort | ePort telemetry module |
| `... (NAYAX)` | Nayax | Nayax card reader |
| `... (CMS)` | Crane Merchandising Systems | CMS telemetry/reader |
| All-numeric (no suffix) | Unknown | Unknown/other |
### Distribution
| Provider | Count |
| --- | --- |
| ePort | 924 |
| CMS | 628 |
| Nayax | 275 |
| Other/unknown | 21 |
**FILL_IN**: More detail on what each provider means for card readers:
**ePort** —Looknuo cantaloupe devices_______________________________________________________________
**NAYAX** — look up nayax devices_______________________________________________________________
**CMS** — Crane integrated and external solutions_________________________________________________________________
**FILL_IN**: Do these map to specific credit card reader models?
| Provider | Reader Brand | Reader Model |
| --- | --- | --- |
| ePort | Cantaloupe___________ | ___________ |
| NAYAX | Nayax___________ | ___________ |
| CMS | Crane___________ | ___________ |
---
## 8. Alert Meanings
**Status: ✅ READY** (data analyzed)
### Alert Types Found
| Alert Text | Count | Severity | Meaning |
| --- | --- | --- | --- |
| `(empty)` | majority | none | No alerts |
| `This machine has been scheduled for service on Monday, May 25, 2026` | many | ⚠️ info | Scheduled maintenance |
| `This machine is scheduled for service today` | several | ⚠️ info | Same-day service scheduled |
| `Out of touch for 19 hours - contact Crane Merchandising Systems for assistance` | several | 🔴 critical | Telemetry offline > 19 hours |
| `Out of touch for 19 hours...` (combined with service notice) | few | 🔴 critical | Multiple issues |
**FILL_IN**: Categorize these alerts properly. What severity should each get?
| Alert | Severity (Info/Warning/Critical) | Display in app? |
| --- | --- | --- |
| Scheduled service in future | ___________ | ___________ |
| Scheduled service today | ___________ | ___________ |
| Out of touch (telemetry lost) | ___________ | ___________ |
| Out of touch + service needed | ___________ | ___________ |
**FILL_IN**: Are there other alert patterns that could appear?
---
---
## 9. Sales Priority Scoring
**Status: ⚠️ NEEDS INPUT**
The current `import_seed.csv` has **no sales data columns** — theyre marked as “Deleted” in the header map.
### Available Alternative Signals
Without sales data, we can score priority using:
| Signal | What it tells us | Priority hint |
| --- | --- | --- |
| `Class = "GF Food"` | Perishable food — needs frequent service | Higher priority |
| `Class = "GF Bev"` | Perishable drinks — needs frequent service | Higher priority |
| `Remote Pricing = "Action Required"` | Needs technical attention | Higher priority |
| `Alerts = "Out of touch"` | Telemetry down | Higher priority |
| `Customer = Disney` | High-traffic, high-visibility | Higher priority |
| `Type = "Unknown"` | Unknown machine — needs identification | Lower priority |
**FILL_IN**: How do you want to score priority?
| Criteria | Priority (Low / Mid / High) |
| --- | --- |
| GF Food or GF Bev class | ___________ |
| Action Required pricing | ___________ |
| Critical alert (out of touch) | ___________ |
| Disney property | ___________ |
| Active pricing (On) + Snack class | ___________ |
| Unknown Type/Make/Model | ___________ |
| Incompatible pricing | ___________ |
**FILL_IN**: Do you have sales data from a separate export? Where does it come from?
---
**FILL_IN**: If sales data is available, what are the priority thresholds?
| Annual Sales Range | Priority |
| --- | --- |
| $_______ - $_______ | Low |
| $_______ - $_______ | Mid |
| $_______+ | High |
---
## 10. Asset List & Detail Screen Spec
**Status: ⚠️ NEEDS FILL_IN**
### Asset List Card
Each asset card in the main app list should show:
**FILL_IN**: What fields belong on the asset card?
- [ ] Machine ID
- [ ] Name
- [ ] Make / Model
- [ ] Location (place, building, floor)
- [ ] Priority badge (low/mid/high)
- [ ] Status badge (active/maintenance/retired)
- [ ] Remote Pricing status
- [ ] Disney park badge
- [ ] Alert indicator
- [ ] GPS coordinates badge (has/dont have)
- [ ] Last contact / last dex time
- [ ] Card reader type
- [ ] Other: _______________
**FILL_IN**: Priority badge colors?
| Priority | Color |
| --- | --- |
| Low | ___________ |
| Mid | ___________ |
| High | ___________ |
### Asset Detail Screen
Full detail view should show:
**FILL_IN**: Section layout for the detail screen (order and contents):
1.
2.
3.
4.
5.
6.
**FILL_IN**: Which sections should be editable?
-
-
**FILL_IN**: Should the approval workflow fields be editable here too?
---
---
## 11. Update Policy — Per-Field
**Status: ⚠️ NEEDS FILL_IN**
For each field, specify how updates from new seed data should be handled:
| DB Column | Source CSV Column | Update Policy | Notes |
| --- | --- | --- | --- |
| `machine_id` | Machine ID | preserve | Primary key, never changes |
| `serial_number` | Serial Number | ___________ | |
| `name` | — (generated) | ___________ | |
| `make` | Type→Make (parsed) | ___________ | |
| `model` | Type→Model (parsed) | ___________ | |
| `class`*) | Type→Class (parsed) | ___________ | |
| `company` | Customer | ___________ | |
| `place` | Place (parsed) | ___________ | |
| `building_name` | Place (parsed) | ___________ | |
| `building_number` | Place (parsed) | ___________ | |
| `floor` | Place (parsed) | ___________ | |
| `room` | Place (parsed) | ___________ | |
| `trailer_number` | Place (parsed) | ___________ | |
| `address` | Address | ___________ | |
| `location_area` | City | ___________ | |
| `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 | ___________ | |
| `install_date` | Added Date | ___________ | |
| `deployed` | — | ___________ | |
| `pulled_date` | — | ___________ | |
| `disney_park` | Customer (parsed) | ___________ | |
| `remote_pricing_status` | Remote Pricing | ___________ | |
| `alerts` | Alerts | ___________ | |
| `telemetry_provider` | Telemetry ID (parsed) | ___________ | |
| `card_reader_brand` | Telemetry ID (parsed) | ___________ | |
| `card_reader_model` | Telemetry ID (parsed) | ___________ | |
| `priority` | — (scored) | ___________ | |
| `prepick_group` | Prepick Group | ___________ | |
- `class` is not a current DB column — needs to be added via migration.
**Policy values:** `auto` (always overwrite), `approval` (queue for review), `preserve` (never touch)
**FILL_IN**: Add or change any policies above.
---
## Appendix: Column Mapping
### Raw Excel → CSV → DB Mapping
| Xlsx Column | CSV Column | DB Column | Notes |
| --- | --- | --- | --- |
| Device | Telemetry ID | — | Parsed to provider/brand |
| Location | Location | — | Redundant (Customer + Address) |
| Asset ID | Machine ID | `machine_id` | Primary key |
| Place | Place | `place` + derived fields | Main extraction target |
| Type | Type | — | Parsed to Class/Make/Model |
| City | City | `location_area` | Direct map |
| Address | Address | `address` | Direct map |
| Last Contact Time | Last Contact Time | — | Freshness indicator |
| Last Dex Report Time | Last Dex Report Time | `dex_report_date` | |
| Prepick Group | Prepick Group | — | Routing info |
| Customer | Customer | `company` | Direct map |
| Route | Route | — | Routing info |
| State | State | — | |
| Postal Code | Postal Code | — | |
| Serial Number | Serial Number | `serial_number` | Validate + correct |
| Class | Class | — | Source for `class` |
| Make | Make | `make` (fallback) | Type column takes priority |
| Model | Model | `model` (fallback) | Type column takes priority |
| Added Date | Added Date | `install_date` | |
| Status | Remote Pricing | — | Direct to app |
| Alerts | Alerts | — | Parsed to structured alerts |
**FILL_IN**: Any missing columns or corrections?
---
+618
View File
@@ -0,0 +1,618 @@
# 🛠️ Validation Report — Canteen Seed Import
**Generated:** 2026-05-24 21:49:34
**Source:** `Machine_List.xlsx`
**Total Machines:** 1848
---
## 1. Machine Count by Class
| Class | Count |
|-------|-------|
| Snack | 610 |
| Bev | 987 |
| Food | 166 |
| Unknown | 67 |
| Snack/Bev | 18 |
**Subtotal (Snack/Bev/Food):** 1763
## 2. Machine Count by Make
| Make | Count |
|------|-------|
| Crane | 711 |
| DN | 351 |
| Royal | 343 |
| Vendo | 267 |
| Unknown | 114 |
| VE | 25 |
| AMS | 19 |
| USI | 16 |
| AP | 1 |
| Faz | 1 |
## 3. Machine Count by Disney Property
**Total Disney machines:** 994
| Disney Property | Count |
|-----------------|-------|
| Port Orleans Riverside | 60 |
| D-Magic Kingdom | 54 |
| D-Hollywood Studios | 51 |
| D-Coronado Springs | 47 |
| Art of Animation Resort | 46 |
| D-Animal Kingdom | 45 |
| D-Epcot | 44 |
| Disney's Pop Century Resort | 44 |
| D-All Star Movie | 37 |
| Celebration (Admin) | 36 |
| Disney World Support Services | 35 |
| All-Star Sports Resort | 34 |
| All-Star Music Resort | 34 |
| Saratoga Springs Resort & Spa | 32 |
| Disney Support Services | 30 |
| Disney's Polynesian Village Resort | 30 |
| D-Animal Kngdm Lodge | 29 |
| Disney's BoardWalk Inn | 27 |
| Fort Wilderness Resort & Campground | 26 |
| Port Orleans French Quarter | 26 |
| Disney's Wilderness Lodge | 24 |
| D-Caribbean Beach Guest | 24 |
| Disney Springs | 22 |
| Disney's Contemporary Resort | 22 |
| ESPN Wide World of Sports | 19 |
| D-Kidani Village GUEST | 17 |
| Disney's Riviera Resort | 15 |
| D-Gran Destino | 13 |
| Disney's Yacht & Beach Club Resorts | 12 |
| Disney's Grand Floridian Resort | 11 |
| Disney Regional Center | 11 |
| D-Island Tower Polynesian | 8 |
| D-OLD KEY WEST GUEST | 7 |
| D-ESPN 2 CAST | 4 |
| Bay Lake Tower at Contemporary | 4 |
| Treehouse Villas (Saratoga Springs) | 3 |
| D-CARIBBEAN BEACH CAST | 2 |
| D-TYPHOON LAGOON CAST | 2 |
| Blizzard Beach Water Park | 2 |
| Winter Summerland Mini Golf | 2 |
| D-FANTASIA GOLF Guest | 2 |
| D-OLD KEY WEST CAST | 1 |
## 4. Invalid / Placeholder Serials
**Placeholder serials:** 14
Machine IDs with placeholder serials:
- `60031`
- `68194`
- `69148`
- `71369`
- `90009`
- `94132`
- `95337`
- `95418`
- `95433`
- `95435`
- `95440`
- `95441`
- `98271`
- `99660`
**Invalid serials:** 135
Machine IDs with invalid serials:
- `67638`
- `67670`
- `68571`
- `68711`
- `68722`
- `68795`
- `68796`
- `69005`
- `69007`
- `69009`
- `69010`
- `69015`
- `69017`
- `69033`
- `69034`
- `69036`
- `69037`
- `69039`
- `69052`
- `69062`
- `69079`
- `69084`
- `69094`
- `69098`
- `69104`
- `69105`
- `69112`
- `69141`
- `69146`
- `69147`
- `69245`
- `69251`
- `69281`
- `69284`
- `69286`
- `69294`
- `69308`
- `69333`
- `69339`
- `69342`
- `69343`
- `69354`
- `69355`
- `69358`
- `69366`
- `70001`
- `71404`
- `90001`
- `90013`
- `90018`
- `90115`
- `90117`
- `90122`
- `90130`
- `90187`
- `92121`
- `92123`
- `92129`
- `92298`
- `92591`
- `92593`
- `92610`
- `92683`
- `92706`
- `92947`
- `93435`
- `93437`
- `93771`
- `94126`
- `94131`
- `94605`
- `94706`
- `94803`
- `94860`
- `94870`
- `94959`
- `95042`
- `95051`
- `95054`
- `95055`
- `95056`
- `95058`
- `95098`
- `95099`
- `95100`
- `95279`
- `95313`
- `95358`
- `95361`
- `95364`
- `95368`
- `95395`
- `95410`
- `95432`
- `95457`
- `96752`
- `97007`
- `97013`
- `97016`
- `97017`
- `97022`
- `97024`
- `97063`
- `97065`
- `97113`
- `97138`
- `97159`
- `97166`
- `97168`
- `97172`
- `97179`
- `97188`
- `97208`
- `97215`
- `97256`
- `97258`
- `97271`
- `97273`
- `97274`
- `97277`
- `97292`
- `97326`
- `97331`
- `97358`
- `97359`
- `97398`
- `98007`
- `98038`
- `98040`
- `98059`
- `98060`
- `98085`
- `98197`
- `99672`
- `99719`
## 5. OCR Corrections Applied
**Serials corrected:** 184
| Machine ID | Raw (cleaned) | Corrected |
|------------|---------------|-----------|
| `60017` | `15S491811573` | `155491811573` |
| `60018` | `14S192104132` | `145192104132` |
| `60025` | `15S491811581` | `155491811581` |
| `60028` | `I5s331807595` | `155331807595` |
| `60032` | `I5SS331807593` | `1555331807593` |
| `69231` | `l200011201` | `1200011201` |
| `69282` | `112B01074049` | `112801074049` |
| `71369` | `pending` | `pendin6` |
| `90071` | `201735BA00056` | `2017358A00056` |
| `90079` | `28670149BT` | `286701498T` |
| `90083` | `201808BA0020` | `2018088A0020` |
| `90094` | `201915BA00062` | `2019158A00062` |
| `90097` | `201834BA00014` | `2018348A00014` |
| `90098` | `201746BA00801` | `2017468A00801` |
| `90119` | `69600142BC` | `696001428C` |
| `90129` | `200050BA00076` | `2000508A00076` |
| `90139` | `201915BA00027` | `2019158A00027` |
| `90140` | `201221BA00307` | `2012218A00307` |
| `90141` | `201132BA00307` | `2011328A00307` |
| `90526` | `201706BA00029` | `2017068A00029` |
| `92852` | `200844BA00008` | `2008448A00008` |
| `92853` | `200850BA00060` | `2008508A00060` |
| `92858` | `200844BA0007` | `2008448A0007` |
| `92912` | `200948BA00252` | `2009488A00252` |
| `92935` | `1509BL02978` | `15098L02978` |
| `93052` | `20115BA00199` | `201158A00199` |
| `93177` | `201210BA00178` | `2012108A00178` |
| `93217` | `202043BA00518` | `2020438A00518` |
| `93358` | `200226BA00220` | `2002268A00220` |
| `93360` | `199944BA02302` | `1999448A02302` |
| `93361` | `20303BA00619` | `203038A00619` |
| `93395` | `20124BA00132` | `201248A00132` |
| `93399` | `200108BA00354` | `2001088A00354` |
| `93533` | `199944ba00309` | `1999448a00309` |
| `93535` | `200122BA00429` | `2001228A00429` |
| `93551` | `201423BA00152` | `2014238A00152` |
| `93580` | `201523BA00086` | `2015238A00086` |
| `93630` | `20119BA00322` | `201198A00322` |
| `93786` | `30130092AO` | `30130092A0` |
| `93794` | `201706BA0039` | `2017068A0039` |
| `93796` | `201706BA00066` | `2017068A00066` |
| `94106` | `201026BA00093` | `2010268A00093` |
| `94114` | `201430BA00068` | `2014308A00068` |
| `94116` | `201243BA00158` | `2012438A00158` |
| `94118` | `01586206CS` | `01586206C5` |
| `94125` | `057666700BZ` | `0576667008Z` |
| `94127` | `200949BA00333` | `2009498A00333` |
| `94128` | `20030BA00176` | `200308A00176` |
| `94129` | `200307BA00600` | `2003078A00600` |
| `94131` | `1293776G` | `12937766` |
| `94136` | `201735BA00040` | `2017358A00040` |
| `94730` | `20114BA0060` | `201148A0060` |
| `94814` | `201222BA00084` | `2012228A00084` |
| `94823` | `201844BA00003` | `2018448A00003` |
| `94833` | `201433BA00308` | `2014338A00308` |
| `94886` | `201832BA00054` | `2018328A00054` |
| `94890` | `201832ba00060` | `2018328a00060` |
| `94891` | `201832ba00034` | `2018328a00034` |
| `94933` | `68800487BB` | `6880048788` |
| `94942` | `201037BA00032` | `2010378A00032` |
| `94957` | `1518BL02744` | `15188L02744` |
| `95033` | `200938BA00111` | `2009388A00111` |
| `95046` | `200251BA00995` | `2002518A00995` |
| `95064` | `201748BA00015` | `2017488A00015` |
| `95068` | `201049BA00006` | `2010498A00006` |
| `95069` | `200227BA00045` | `2002278A00045` |
| `95081` | `201222BA00079` | `2012228A00079` |
| `95082` | `200110BA00078` | `2001108A00078` |
| `95090` | `200042BA00218` | `2000428A00218` |
| `95091` | `201207BA00028` | `2012078A00028` |
| `95092` | `1522BL02325` | `15228L02325` |
| `95094` | `200050BA00119` | `2000508A00119` |
| `95095` | `201140BA00523` | `2011408A00523` |
| `95096` | `20112BA00044` | `201128A00044` |
| `95100` | `201037BA` | `2010378A` |
| `95117` | `200706BA00034` | `2007068A00034` |
| `95122` | `201210BA00140` | `2012108A00140` |
| `95123` | `201623BA00227P` | `2016238A00227P` |
| `95124` | `201433BA00249` | `2014338A00249` |
| `95138` | `201033BA00094` | `2010338A00094` |
| `95139` | `1518BL01680` | `15188L01680` |
| `95143` | `200837BA00101` | `2008378A00101` |
| `95144` | `1200118BA00500` | `12001188A00500` |
| `95148` | `201029BA00081` | `2010298A00081` |
| `95149` | `201717BA00017` | `2017178A00017` |
| `95150` | `201148BA00467` | `2011488A00467` |
| `95151` | `201204BA00041` | `2012048A00041` |
| `95152` | `201037BA00076` | `2010378A00076` |
| `95153` | `201624BA00092` | `2016248A00092` |
| `95154` | `201915BA00052` | `2019158A00052` |
| `95155` | `200225BA01283` | `2002258A01283` |
| `95156` | `200225BA012` | `2002258A012` |
| `95161` | `2001444BA00106` | `20014448A00106` |
| `95162` | `200209BA00806` | `2002098A00806` |
| `95165` | `201744BA00021` | `2017448A00021` |
| `95170` | `201243BA00531` | `2012438A00531` |
| `95171` | `201833BA00014` | `2018338A00014` |
| `95173` | `201147BA00021` | `2011478A00021` |
| `95183` | `201207BA00104` | `2012078A00104` |
| `95184` | `201133BA00049` | `2011338A00049` |
| `95214` | `200938BA00122` | `2009388A00122` |
| `95215` | `1482BK01614` | `14828K01614` |
| `95216` | `200120BA00012` | `2001208A00012` |
| `95217` | `201037BA00098` | `2010378A00098` |
| `95247` | `201122BA0010` | `2011228A0010` |
| `95254` | `201140BA00512` | `2011408A00512` |
| `95256` | `200225BA01301` | `2002258A01301` |
| `95257` | `201029BA00166` | `2010298A00166` |
| `95271` | `201037BA0030` | `2010378A0030` |
| `95276` | `201746BA00058` | `2017468A00058` |
| `95337` | `S` | `5` |
| `95397` | `201735BA00109` | `2017358A00109` |
| `95398` | `201833BA00021` | `2018338A00021` |
| `95399` | `201748BA00014` | `2017488A00014` |
| `95400` | `201807BA00022` | `2018078A00022` |
| `95401` | `201832BA00030` | `2018328A00030` |
| `95402` | `201748B00046` | `201748800046` |
| `95403` | `201746BA000109` | `2017468A000109` |
| `95405` | `201832BA00015` | `2018328A00015` |
| `97018` | `1381B12669` | `1381812669` |
| `97028` | `76820565BD` | `768205658D` |
| `97029` | `68980319BB` | `6898031988` |
| `97040` | `68870563BB` | `6887056388` |
| `97052` | `0876666ODY` | `08766660DY` |
| `97055` | `08006617BY` | `080066178Y` |
| `97082` | `68080567BA` | `680805678A` |
| `97084` | `52060152BK` | `520601528K` |
| `97086` | `200048BA00073` | `2000488A00073` |
| `97087` | `24110016BN` | `241100168N` |
| `97095` | `69030300CB` | `69030300C8` |
| `97099` | `06196697BZ` | `061966978Z` |
| `97102` | `201207BA00098` | `2012078A00098` |
| `97104` | `201836BA00016` | `2018368A00016` |
| `97111` | `201706BA00026` | `2017068A00026` |
| `97124` | `69000450CB` | `69000450C8` |
| `97125` | `69000449CB` | `69000449C8` |
| `97126` | `68780229BB` | `6878022988` |
| `97128` | `69000125CB` | `69000125C8` |
| `97142` | `200042BA00376` | `2000428A00376` |
| `97145` | `201204BA00060` | `2012048A00060` |
| `97158` | `084D6157BX` | `084D61578X` |
| `97161` | `201526BA00159` | `2015268A00159` |
| `97171` | `24120073BN` | `241200738N` |
| `97218` | `10496607BY` | `104966078Y` |
| `97219` | `200043BA00809` | `2000438A00809` |
| `97221` | `20144BA00304` | `201448A00304` |
| `97222` | `30376500BW` | `303765008W` |
| `97223` | `15086793BA` | `150867938A` |
| `97237` | `69620140BC` | `696201408C` |
| `97240` | `77270226BE` | `772702268E` |
| `97246` | `69700435BC` | `697004358C` |
| `97265` | `200225BA01086` | `2002258A01086` |
| `97268` | `52060005BK` | `520600058K` |
| `97280` | `50890236DI` | `50890236D1` |
| `97285` | `76920191BD` | `769201918D` |
| `97291` | `201744BA00052` | `2017448A00052` |
| `97295` | `69010283CB` | `69010283C8` |
| `97307` | `07856700BZ` | `078567008Z` |
| `97320` | `6891076BB` | `689107688` |
| `97330` | `200050BA0018` | `2000508A0018` |
| `97344` | `24120064BN` | `241200648N` |
| `97346` | `200323ba00511` | `2003238a00511` |
| `97355` | `201444ba00201` | `2014448a00201` |
| `97374` | `28806471BW` | `288064718W` |
| `97381` | `07866614BY` | `078666148Y` |
| `98056` | `23166489BW` | `231664898W` |
| `98062` | `86890056AG` | `86890056A6` |
| `98074` | `201836BA00010` | `2018368A00010` |
| `98076` | `200209BA00134` | `2002098A00134` |
| `98077` | `201915BA00067` | `2019158A00067` |
| `98080` | `200220BA00544` | `2002208A00544` |
| `98104` | `69700369BC` | `697003698C` |
| `98110` | `69620270BC` | `696202708C` |
| `98130` | `76830252B0` | `7683025280` |
| `98132` | `69620206BC` | `696202068C` |
| `98140` | `68450456AB` | `68450456A8` |
| `98163` | `15266532BX` | `152665328X` |
| `98164` | `19876551BX` | `198765518X` |
| `98192` | `69100439CB` | `69100439C8` |
| `98194` | `76820625BD` | `768206258D` |
| `98195` | `69600228BC` | `696002288C` |
| `98196` | `69700313BC` | `697003138C` |
| `98198` | `69680622BC` | `696806228C` |
| `99704` | `94310050BJ` | `943100508J` |
## 6. Unknown Type / Class / Make / Model
**Machines with unknowns:** 143
| Machine ID | Class | Make | Model |
|------------|-------|------|-------|
| `60015` | Unknown | Unknown | Unknown |
| `60017` | Snack | Unknown | Unknown |
| `60018` | Unknown | Unknown | Unknown |
| `60021` | Snack | USI | Unknown |
| `60025` | Snack | Unknown | Unknown |
| `60028` | Snack | Unknown | Unknown |
| `60031` | Snack | Unknown | Unknown |
| `60032` | Snack | Unknown | Unknown |
| `65536` | Snack | VE | Unknown |
| `67529` | Snack | Unknown | Unknown |
| `68617` | Snack | Unknown | Unknown |
| `68653` | Unknown | Unknown | Unknown |
| `68654` | Snack | Crane | Unknown |
| `68664` | Unknown | Unknown | Unknown |
| `68699` | Snack | Unknown | Unknown |
| `69008` | Snack | Unknown | Unknown |
| `69012` | Snack | Unknown | Unknown |
| `69032` | Snack | Unknown | Unknown |
| `69039` | Snack | VE | Unknown |
| `69070` | Snack | VE | Unknown |
| `69089` | Snack | Unknown | Unknown |
| `69102` | Snack | VE | Unknown |
| `69104` | Snack | VE | Unknown |
| `69146` | Snack | VE | Unknown |
| `69231` | Snack | VE | Unknown |
| `69235` | Snack | Unknown | Unknown |
| `69280` | Snack | VE | Unknown |
| `69287` | Snack | VE | Unknown |
| `69296` | Snack | Unknown | Unknown |
| `69308` | Snack | VE | Unknown |
| `69332` | Snack | Faz | Unknown |
| `69342` | Snack | VE | Unknown |
| `69357` | Snack | Unknown | Unknown |
| `69360` | Snack | Unknown | Unknown |
| `90003` | Unknown | Unknown | Unknown |
| `90010` | Unknown | Unknown | Unknown |
| `90042` | Unknown | Unknown | Unknown |
| `90048` | Unknown | Unknown | Unknown |
| `90053` | Unknown | Unknown | Unknown |
| `90054` | Unknown | Unknown | Unknown |
| `90055` | Unknown | Unknown | Unknown |
| `90074` | Bev | Vendo | Unknown |
| `90090` | Unknown | Unknown | Unknown |
| `90109` | Unknown | Unknown | Unknown |
| `90160` | Bev | Unknown | Unknown |
| `90162` | Bev | Unknown | Unknown |
| `90166` | Unknown | Unknown | Unknown |
| `90168` | Unknown | Unknown | Unknown |
| `90170` | Unknown | Unknown | Unknown |
| `90172` | Unknown | Unknown | Unknown |
| `90175` | Bev | Unknown | Unknown |
| `90176` | Bev | Unknown | Unknown |
| `90177` | Bev | Unknown | Unknown |
| `90178` | Bev | Unknown | Unknown |
| `90183` | Bev | Royal | Unknown |
| `90184` | Unknown | Unknown | Unknown |
| `90186` | Bev | Unknown | Unknown |
| `90199` | Unknown | Unknown | Unknown |
| `90200` | Unknown | Unknown | Unknown |
| `90205` | Bev | Unknown | Unknown |
| `93177` | Bev | Royal | Unknown |
| `93243` | Bev | DN | Unknown |
| `93399` | Unknown | Unknown | Unknown |
| `93552` | Bev | DN | Unknown |
| `93555` | Bev | DN | Unknown |
| `94121` | Bev | Royal | Unknown |
| `94706` | Bev | DN | Unknown |
| `94910` | Unknown | Unknown | Unknown |
| `95033` | Bev | Royal | Unknown |
| `95084` | Unknown | Unknown | Unknown |
| `95090` | Unknown | Unknown | Unknown |
| `95097` | Unknown | Unknown | Unknown |
| `95150` | Snack | VE | Unknown |
| `95256` | Unknown | Unknown | Unknown |
| `95324` | Unknown | Unknown | Unknown |
| `95330` | Unknown | Unknown | Unknown |
| `95365` | Unknown | Unknown | Unknown |
| `95366` | Unknown | Unknown | Unknown |
| `95367` | Unknown | Unknown | Unknown |
| `95368` | Unknown | Unknown | Unknown |
| `95369` | Unknown | Unknown | Unknown |
| `95370` | Unknown | Unknown | Unknown |
| `95371` | Unknown | Unknown | Unknown |
| `95372` | Unknown | Unknown | Unknown |
| `95373` | Unknown | Unknown | Unknown |
| `95374` | Unknown | Unknown | Unknown |
| `95378` | Unknown | Unknown | Unknown |
| `95379` | Unknown | Unknown | Unknown |
| `95380` | Bev | Royal | Unknown |
| `95381` | Unknown | Unknown | Unknown |
| `95382` | Unknown | Unknown | Unknown |
| `95383` | Unknown | Unknown | Unknown |
| `95384` | Unknown | Unknown | Unknown |
| `95387` | Unknown | Unknown | Unknown |
| `95388` | Unknown | Unknown | Unknown |
| `95389` | Bev | Unknown | Unknown |
| `95390` | Unknown | Unknown | Unknown |
| `95391` | Unknown | Unknown | Unknown |
| `95392` | Unknown | Unknown | Unknown |
| `95414` | Unknown | Unknown | Unknown |
| `95416` | Unknown | Unknown | Unknown |
| `95431` | Unknown | Unknown | Unknown |
| `95434` | Unknown | Unknown | Unknown |
| `95435` | Unknown | Unknown | Unknown |
| `95436` | Unknown | Unknown | Unknown |
| `95498` | Unknown | Unknown | Unknown |
| `96728` | Bev | Unknown | Unknown |
| `97015` | Bev | Unknown | Unknown |
| `97082` | Bev | Unknown | Unknown |
| `97084` | Bev | DN | Unknown |
| `97086` | Bev | Unknown | Unknown |
| `97106` | Bev | Unknown | Unknown |
| `97115` | Bev | Unknown | Unknown |
| `97117` | Bev | Unknown | Unknown |
| `97138` | Bev | DN | Unknown |
| `97187` | Snack | Unknown | Unknown |
| `97188` | Bev | Unknown | Unknown |
| `97268` | Bev | DN | Unknown |
| `97326` | Bev | DN | Unknown |
| `97392` | Bev | Unknown | Unknown |
| `98006` | Unknown | Unknown | Unknown |
| `98023` | Unknown | Unknown | Unknown |
| `98029` | Bev | Unknown | Unknown |
| `98030` | Bev | Unknown | Unknown |
| `98032` | Unknown | Unknown | Unknown |
| `98033` | Unknown | Unknown | Unknown |
| `98034` | Unknown | Unknown | Unknown |
| `98035` | Bev | Unknown | Unknown |
| `98045` | Bev | Unknown | Unknown |
| `98060` | Bev | Unknown | Unknown |
| `98065` | Bev | Unknown | Unknown |
| `98092` | Unknown | Unknown | Unknown |
| `98093` | Unknown | Unknown | Unknown |
| `98094` | Unknown | Unknown | Unknown |
| `98099` | Bev | Unknown | Unknown |
| `98106` | Unknown | Unknown | Unknown |
| `98112` | Bev | Unknown | Unknown |
| `98125` | Bev | Unknown | Unknown |
| `99651` | Bev | Unknown | Unknown |
| `99653` | Bev | Unknown | Unknown |
| `99660` | Bev | Unknown | Unknown |
| `99662` | Unknown | Unknown | Unknown |
| `99688` | Unknown | Unknown | Unknown |
## 7. Machines Lacking Any GPS / Location Data
**Machines with no address data:** 0
## 8. Priority Distribution
| Priority | Count |
|----------|-------|
| Low | 469 |
| Mid | 1163 |
| High | 194 |
| Unknown | 22 |
## 9. Alert Severity Breakdown
| Severity | Count |
|----------|-------|
| critical | 43 |
| info | 1183 |
| none | 622 |
## 10. Telemetry Provider Breakdown
| Provider | Count |
|----------|-------|
| ePort | 924 |
| CMS | 628 |
| NAYAX | 275 |
| AIRVEND | 11 |
| None | 10 |
---
*Report generated automatically by `reporter.py`*