feat: add is_disney column for reliable Disney/Non-Disney filtering
- Added is_disney INTEGER DEFAULT 0 column to assets table - Backfilled 996 Disney assets based on D- customer prefix - Server: is_disney in AssetCreate/AssetUpdate models, INSERT/UPDATE - Server: disney_filter query param now uses is_disney column (no JOIN needed) - import_cantaloupe.py: sets is_disney=1 when customer starts with D- - import_machines.py: sets is_disney=1 when customer starts with D- - disney_classify.py: sets is_disney=1 when classifying - Frontend: new Location Type dropdown with Disney/Non-Disney toggle (replaces the __disney__/__non_disney__ park dropdown pseudo-options)
This commit is contained in:
+1
-1
@@ -277,7 +277,7 @@ def classify_all_assets(db_path: str) -> dict:
|
||||
|
||||
if park:
|
||||
conn.execute(
|
||||
"UPDATE assets SET disney_park = ?, updated_at = datetime('now') WHERE id = ?",
|
||||
"UPDATE assets SET disney_park = ?, is_disney = 1, updated_at = datetime('now') WHERE id = ?",
|
||||
(park, row['id'])
|
||||
)
|
||||
results["classified"].append({
|
||||
|
||||
@@ -141,17 +141,18 @@ def import_assets():
|
||||
# Customer lookup
|
||||
customer_id = customer_map.get(customer_name)
|
||||
|
||||
is_disney = 1 if customer_name.startswith('D-') else 0
|
||||
try:
|
||||
cursor = conn.execute("""
|
||||
INSERT INTO assets
|
||||
(machine_id, name, description, category, status,
|
||||
make, model, serial_number, address, room,
|
||||
customer_id)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
customer_id, is_disney)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""", (
|
||||
machine_id, name, description, "Equipment", status,
|
||||
make, model, serial, full_address, place,
|
||||
customer_id,
|
||||
customer_id, is_disney,
|
||||
))
|
||||
inserted += 1
|
||||
except sqlite3.IntegrityError as e:
|
||||
|
||||
+4
-3
@@ -63,6 +63,7 @@ def main(xlsx_path):
|
||||
machine_id = _sanitize_machine_id(str(int(row[2])))
|
||||
location_str = str(row[1]) if row[1] else '' # "Company - Address"
|
||||
customer_name = str(row[21]) if row[21] else '' # Customer
|
||||
is_disney = 1 if customer_name.strip().startswith('D-') else 0
|
||||
address = str(row[6]) if row[6] else ''
|
||||
city = str(row[5]) if row[5] else ''
|
||||
state = str(row[33]) if row[33] else ''
|
||||
@@ -136,10 +137,10 @@ def main(xlsx_path):
|
||||
cursor = conn.execute("""
|
||||
INSERT INTO assets
|
||||
(machine_id, name, serial_number, make, model, category,
|
||||
status, address, customer_id, created_at, updated_at, description)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now'), ?)
|
||||
status, address, customer_id, is_disney, created_at, updated_at, description)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'), datetime('now'), ?)
|
||||
""", (machine_id, name, serial, make, model, cat,
|
||||
status, full_address, customer_id,
|
||||
status, full_address, customer_id, is_disney,
|
||||
device + ' | Branch: ' + branch if branch else device))
|
||||
aid = cursor.lastrowid
|
||||
existing_assets[machine_id] = aid
|
||||
|
||||
@@ -165,6 +165,7 @@ def _create_v2_tables(conn: sqlite3.Connection):
|
||||
longitude REAL DEFAULT NULL,
|
||||
geofence_radius_meters INTEGER DEFAULT 50,
|
||||
disney_park TEXT DEFAULT NULL,
|
||||
is_disney INTEGER DEFAULT 0,
|
||||
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
||||
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
|
||||
);
|
||||
@@ -629,6 +630,7 @@ class AssetCreate(BaseModel):
|
||||
latitude: Optional[float] = None
|
||||
longitude: Optional[float] = None
|
||||
geofence_radius_meters: Optional[int] = 50
|
||||
is_disney: Optional[bool] = None
|
||||
keys: Optional[List[AssetKey]] = []
|
||||
badges: Optional[List[str]] = []
|
||||
|
||||
@@ -658,6 +660,7 @@ class AssetUpdate(BaseModel):
|
||||
latitude: Optional[float] = None
|
||||
longitude: Optional[float] = None
|
||||
geofence_radius_meters: Optional[int] = None
|
||||
is_disney: Optional[bool] = None
|
||||
keys: Optional[List[AssetKey]] = None
|
||||
badges: Optional[List[str]] = None
|
||||
|
||||
@@ -867,7 +870,7 @@ def _build_asset_insert(body: AssetCreate, machine_id: str, name: str):
|
||||
"make", "model", "address", "building_name", "building_number", "floor",
|
||||
"room", "trailer_number", "walking_directions", "map_link",
|
||||
"parking_location", "photo_path", "customer_id", "location_id",
|
||||
"assigned_to", "latitude", "longitude", "geofence_radius_meters",
|
||||
"assigned_to", "latitude", "longitude", "geofence_radius_meters", "is_disney",
|
||||
]
|
||||
values = (
|
||||
machine_id, body.serial_number or "", name, body.description or "",
|
||||
@@ -880,6 +883,7 @@ def _build_asset_insert(body: AssetCreate, machine_id: str, name: str):
|
||||
body.customer_id, body.location_id, body.assigned_to,
|
||||
body.latitude, body.longitude,
|
||||
body.geofence_radius_meters if body.geofence_radius_meters is not None else 50,
|
||||
body.is_disney if body.is_disney is not None else None,
|
||||
)
|
||||
return columns, values
|
||||
|
||||
@@ -1010,9 +1014,9 @@ def list_assets(
|
||||
conditions.append("disney_park = ?")
|
||||
params.append(disney_park)
|
||||
if disney_filter == "disney":
|
||||
conditions.append("(disney_park IS NOT NULL OR c.name LIKE 'D-%')")
|
||||
conditions.append("is_disney = 1")
|
||||
elif disney_filter == "non_disney":
|
||||
conditions.append("(disney_park IS NULL AND (c.name IS NULL OR c.name NOT LIKE 'D-%'))")
|
||||
conditions.append("(is_disney IS NULL OR is_disney = 0)")
|
||||
if model:
|
||||
conditions.append("model = ?")
|
||||
params.append(model)
|
||||
@@ -1031,10 +1035,7 @@ def list_assets(
|
||||
params.extend([like, like, like, like])
|
||||
|
||||
where = " AND ".join(conditions)
|
||||
join_clause = ""
|
||||
if disney_filter:
|
||||
join_clause = " LEFT JOIN customers c ON assets.customer_id = c.id"
|
||||
sql = f"SELECT assets.* FROM assets{join_clause}"
|
||||
sql = "SELECT * FROM assets"
|
||||
if where:
|
||||
sql += f" WHERE {where}"
|
||||
sql += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
|
||||
@@ -1042,7 +1043,7 @@ def list_assets(
|
||||
|
||||
rows = conn.execute(sql, params).fetchall()
|
||||
# Get total count for pagination
|
||||
count_sql = f"SELECT COUNT(*) FROM assets{join_clause}"
|
||||
count_sql = "SELECT COUNT(*) FROM assets"
|
||||
if where:
|
||||
count_sql += f" WHERE {where}"
|
||||
total = conn.execute(count_sql, params[:len(params)-2]).fetchone()[0]
|
||||
@@ -1206,6 +1207,8 @@ def update_asset(asset_id: int, body: AssetUpdate):
|
||||
updates["longitude"] = body.longitude
|
||||
if body.geofence_radius_meters is not None:
|
||||
updates["geofence_radius_meters"] = body.geofence_radius_meters
|
||||
if body.is_disney is not None:
|
||||
updates["is_disney"] = 1 if body.is_disney else 0
|
||||
|
||||
# Auto-populate address from GPS when lat/lng are provided
|
||||
lat = updates.get("latitude") if "latitude" in updates else None
|
||||
|
||||
+19
-10
@@ -1129,13 +1129,22 @@
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fp-row">
|
||||
<div style="flex:1">
|
||||
<div class="fp-label">Location Type</div>
|
||||
<select id="filterDisneyFilter" class="input-field" onchange="onFilterChange()">
|
||||
<option value="">All locations</option>
|
||||
<option value="disney">🏰 Disney</option>
|
||||
<option value="non_disney">🏢 Non-Disney</option>
|
||||
</select>
|
||||
</div>
|
||||
<div style="flex:1"></div>
|
||||
</div>
|
||||
<div class="fp-row">
|
||||
<div style="flex:1">
|
||||
<div class="fp-label">Disney Park</div>
|
||||
<select id="filterDisneyPark" class="input-field" onchange="onFilterChange()">
|
||||
<option value="">All parks</option>
|
||||
<option value="__disney__">🏰 Disney only</option>
|
||||
<option value="__non_disney__">🏢 Non-Disney</option>
|
||||
<option disabled>──────────</option>
|
||||
<option value="magic-kingdom">🏰 Magic Kingdom</option>
|
||||
<option value="epcot">🌍 Epcot</option>
|
||||
@@ -3203,6 +3212,7 @@
|
||||
function onFilterChange() {
|
||||
var catEl = document.getElementById('filterCategory');
|
||||
var makeEl = document.getElementById('filterMake');
|
||||
var disneyFilterEl = document.getElementById('filterDisneyFilter');
|
||||
var parkEl = document.getElementById('filterDisneyPark');
|
||||
var custEl = document.getElementById('filterCustomer');
|
||||
var locEl = document.getElementById('filterLocation');
|
||||
@@ -3211,15 +3221,13 @@
|
||||
|
||||
assetFilters.category = catEl.value || null;
|
||||
assetFilters.make = makeEl.value || null;
|
||||
// Handle Disney/Non-Disney special options
|
||||
var parkVal = parkEl.value;
|
||||
if (parkVal === '__disney__') {
|
||||
// Location Type (Disney/Non-Disney) and specific park are mutually exclusive
|
||||
var disneyFilterVal = disneyFilterEl.value;
|
||||
if (disneyFilterVal) {
|
||||
assetFilters.disney_filter = disneyFilterVal;
|
||||
assetFilters.disney_park = null;
|
||||
assetFilters.disney_filter = 'disney';
|
||||
} else if (parkVal === '__non_disney__') {
|
||||
assetFilters.disney_park = null;
|
||||
assetFilters.disney_filter = 'non_disney';
|
||||
} else {
|
||||
var parkVal = parkEl.value;
|
||||
assetFilters.disney_park = parkVal || null;
|
||||
assetFilters.disney_filter = null;
|
||||
}
|
||||
@@ -3329,7 +3337,7 @@
|
||||
document.getElementById('filterDisneyPark').value = '';
|
||||
assetFilters.disney_park = null;
|
||||
} else if (key === 'disney_filter') {
|
||||
document.getElementById('filterDisneyPark').value = '';
|
||||
document.getElementById('filterDisneyFilter').value = '';
|
||||
assetFilters.disney_filter = null;
|
||||
} else if (key === 'customer_id') {
|
||||
document.getElementById('filterCustomer').value = '';
|
||||
@@ -3357,6 +3365,7 @@
|
||||
document.getElementById('filterCategory').value = '';
|
||||
document.getElementById('filterMake').value = '';
|
||||
document.getElementById('filterDisneyPark').value = '';
|
||||
document.getElementById('filterDisneyFilter').value = '';
|
||||
document.getElementById('filterCustomer').value = '';
|
||||
document.getElementById('filterLocation').innerHTML = '<option value="">All locations</option>';
|
||||
document.getElementById('filterLocation').disabled = true;
|
||||
|
||||
Reference in New Issue
Block a user