feat: add disney_area column and resort area mapping

- Add DISNEY_AREA_MAP in parser.py mapping 40+ Disney properties to 8 resort areas
- Add disney_area to parse_customer() output, resolver after disney_park
- Update db_writer.py schema: ORDERED_COLUMNS, AUTO_COLUMNS, COLUMN_TYPES
- Add /api/status endpoint query for by_disney_area distribution
- Add area row to web dashboard UI
- Auto-migration adds column to existing databases
This commit is contained in:
2026-05-24 23:36:41 -04:00
parent af566bc368
commit 0205866e7a
4 changed files with 97 additions and 1 deletions
+89
View File
@@ -87,6 +87,89 @@ DISNEY_CUSTOMER_PREFIXES = [
]
# ─── Disney Resort Area Mapping (Section 2) ────────────────────────────────────
#
# Maps cleaned disney_park values to their Walt Disney World resort area.
# Based on official WDW geography: resorts grouped by proximity to parks
# and transportation access (monorail, Skyliner, boat, bus).
#
# Areas:
# Magic Kingdom Resort Area — Monorail loop & Seven Seas Lagoon
# Epcot Resort Area — Crescent Lake, Skyliner to Epcot/HS
# Animal Kingdom Resort Area — Near Animal Kingdom park
# Disney Springs Resort Area — Near shopping/dining district
# Wide World of Sports Area — All-Star/Pop Century corridor (SE)
# Parks & Attractions — Theme parks, ESPN, cast areas
# Water Parks — Blizzard Beach, Typhoon Lagoon, golf
# Admin & Support — Corporate/admin locations
DISNEY_AREA_MAP = {
# ──── Magic Kingdom Resort Area ─────────────────────────────────────────────
# Hotels along the monorail loop and Seven Seas Lagoon / Bay Lake
"Disney's Contemporary Resort": "Magic Kingdom Resort Area",
"Disney's Polynesian Village Resort": "Magic Kingdom Resort Area",
"Disney's Grand Floridian Resort": "Magic Kingdom Resort Area",
"Bay Lake Tower at Contemporary": "Magic Kingdom Resort Area",
"Disney's Wilderness Lodge": "Magic Kingdom Resort Area",
"Fort Wilderness Resort & Campground": "Magic Kingdom Resort Area",
"D-Island Tower Polynesian": "Magic Kingdom Resort Area",
# ──── Epcot Resort Area ─────────────────────────────────────────────────────
# Hotels along Crescent Lake — walk/Skyliner/boat to Epcot & Hollywood Studios
"Disney's BoardWalk Inn": "Epcot Resort Area",
"Disney's Yacht & Beach Club Resorts": "Epcot Resort Area",
"Disney's Riviera Resort": "Epcot Resort Area",
# ──── Animal Kingdom Resort Area ────────────────────────────────────────────
# Near Animal Kingdom park (Jambo House, Kidani Village)
"D-Animal Kngdm Lodge": "Animal Kingdom Resort Area",
"D-Kidani Village GUEST": "Animal Kingdom Resort Area",
"D-Coronado Springs": "Animal Kingdom Resort Area",
"D-Gran Destino": "Animal Kingdom Resort Area", # At Coronado Springs
# ──── Disney Springs Resort Area ────────────────────────────────────────────
# Near the shopping/dining district
"Saratoga Springs Resort & Spa": "Disney Springs Resort Area",
"Treehouse Villas (Saratoga Springs)": "Disney Springs Resort Area",
"Disney Springs": "Disney Springs Resort Area",
"Port Orleans Riverside": "Disney Springs Resort Area",
"Port Orleans French Quarter": "Disney Springs Resort Area",
"D-Caribbean Beach Guest": "Disney Springs Resort Area",
"D-CARIBBEAN BEACH CAST": "Disney Springs Resort Area",
"D-OLD KEY WEST GUEST": "Disney Springs Resort Area",
"D-OLD KEY WEST CAST": "Disney Springs Resort Area",
# ──── Wide World of Sports Resort Area ──────────────────────────────────────
# All-Star Resorts & Pop Century / Art of Animation corridor (southeastern)
"Art of Animation Resort": "Wide World of Sports Resort Area",
"Disney's Pop Century Resort": "Wide World of Sports Resort Area",
"All-Star Sports Resort": "Wide World of Sports Resort Area",
"All-Star Music Resort": "Wide World of Sports Resort Area",
"D-All Star Movie": "Wide World of Sports Resort Area",
# ──── Parks & Attractions ───────────────────────────────────────────────────
# Theme parks, cast-member areas, sports complex
"D-Magic Kingdom": "Parks & Attractions",
"D-Hollywood Studios": "Parks & Attractions",
"D-Animal Kingdom": "Parks & Attractions",
"D-Epcot": "Parks & Attractions",
"ESPN Wide World of Sports": "Parks & Attractions",
"D-ESPN 2 CAST": "Parks & Attractions",
# ──── Water Parks ───────────────────────────────────────────────────────────
"Blizzard Beach Water Park": "Water Parks",
"D-TYPHOON LAGOON CAST": "Water Parks",
"Winter Summerland Mini Golf": "Water Parks",
"D-FANTASIA GOLF Guest": "Water Parks",
# ──── Admin & Support ───────────────────────────────────────────────────────
"Celebration (Admin)": "Admin & Support",
"Disney Regional Center": "Admin & Support",
"Disney World Support Services": "Admin & Support",
"Disney Support Services": "Admin & Support",
}
# ─── Make Normalization Table (Section 5) ─────────────────────────────────────
MAKE_NORMALIZATION = {
@@ -1029,6 +1112,7 @@ def parse_customer(customer_val):
result = {
"company": None,
"disney_park": None,
"disney_area": None,
}
if not raw:
@@ -1065,6 +1149,10 @@ def parse_customer(customer_val):
else:
result["company"] = raw
# Resolve Disney resort area from disney_park
if result["disney_park"] and result["disney_park"] in DISNEY_AREA_MAP:
result["disney_area"] = DISNEY_AREA_MAP[result["disney_park"]]
return result
@@ -1489,6 +1577,7 @@ def parse_excel(filepath):
# Customer
"company": customer_info["company"],
"disney_park": customer_info["disney_park"],
"disney_area": customer_info["disney_area"],
# Telemetry
"telemetry_provider": device_info["telemetry_provider"],