Sync prod: customer_name JOIN, search debounce, parent company filter, asset detail card with map
This commit is contained in:
@@ -72,13 +72,12 @@ TEST_PLAN_MAP.md # Map test plan
|
|||||||
|---------|-------------|
|
|---------|-------------|
|
||||||
| `canteen-admin-server` | Admin CRUD API, shares same SQLite DB |
|
| `canteen-admin-server` | Admin CRUD API, shares same SQLite DB |
|
||||||
| `canteen-seed-import` | Seed data import from Cantaloupe CSVs |
|
| `canteen-seed-import` | Seed data import from Cantaloupe CSVs |
|
||||||
| `photo-geotagger` | Batch GPS updater using same `assets.db` |
|
|
||||||
| `exif-test` | EXIF/OCR validation against this DB |
|
| `exif-test` | EXIF/OCR validation against this DB |
|
||||||
| `cantaloupe-downloader` | CLI to export machine data from Cantaloupe |
|
| `cantaloupe-downloader` | CLI to export machine data from Cantaloupe |
|
||||||
|
|
||||||
## Pitfalls
|
## Pitfalls
|
||||||
|
|
||||||
- **Single-file backend** — server.py is ~2.5K lines; routes, DB, and OCR all in one file
|
- **Single-file backend** — server.py is ~2.5K lines; routes, DB, and OCR all in one file
|
||||||
- **DB shared** across canteen-admin-server, photo-geotagger, seed-import, exif-test — schema changes must be coordinated
|
- **DB shared** across canteen-admin-server, seed-import, exif-test — schema changes must be coordinated
|
||||||
- **HTTPS** — start.sh generates self-signed cert every restart; ports 8901 (production) vs 8904 (dev)
|
- **HTTPS** — start.sh generates self-signed cert every restart; ports 8901 (production) vs 8904 (dev)
|
||||||
- **OCR** requires Tesseract installed system-wide (`apt install tesseract-ocr`)
|
- **OCR** requires Tesseract installed system-wide (`apt install tesseract-ocr`)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -1052,23 +1052,24 @@ def list_assets(
|
|||||||
conditions.append("assigned_to = ?")
|
conditions.append("assigned_to = ?")
|
||||||
params.append(assigned_to)
|
params.append(assigned_to)
|
||||||
if q:
|
if q:
|
||||||
conditions.append("(name LIKE ? OR machine_id LIKE ? OR serial_number LIKE ? OR description LIKE ?)")
|
conditions.append("(a.name LIKE ? OR a.machine_id LIKE ? OR a.serial_number LIKE ? OR a.description LIKE ? OR a.company LIKE ?)")
|
||||||
like = f"%{q}%"
|
like = f"%{q}%"
|
||||||
params.extend([like, like, like, like])
|
params.extend([like, like, like, like, like])
|
||||||
if no_dex_days is not None:
|
if no_dex_days is not None:
|
||||||
conditions.append("(dex_report_date IS NULL OR REPLACE(dex_report_date, 'T', ' ') < datetime('now', '-' || ? || ' days'))")
|
conditions.append("(dex_report_date IS NULL OR REPLACE(dex_report_date, 'T', ' ') < datetime('now', '-' || ? || ' days'))")
|
||||||
params.append(no_dex_days)
|
params.append(no_dex_days)
|
||||||
|
|
||||||
where = " AND ".join(conditions)
|
where = " AND ".join(conditions)
|
||||||
sql = "SELECT * FROM assets"
|
from_clause = "FROM assets a LEFT JOIN customers c ON a.customer_id = c.id"
|
||||||
|
sql = f"SELECT a.*, c.name AS customer_name {from_clause}"
|
||||||
if where:
|
if where:
|
||||||
sql += f" WHERE {where}"
|
sql += f" WHERE {where}"
|
||||||
sql += " ORDER BY created_at DESC LIMIT ? OFFSET ?"
|
sql += " ORDER BY a.created_at DESC LIMIT ? OFFSET ?"
|
||||||
params.extend([limit, offset])
|
params.extend([limit, offset])
|
||||||
|
|
||||||
rows = conn.execute(sql, params).fetchall()
|
rows = conn.execute(sql, params).fetchall()
|
||||||
# Get total count for pagination
|
# Get total count for pagination (use same FROM with alias for unambiguous conditions)
|
||||||
count_sql = "SELECT COUNT(*) FROM assets"
|
count_sql = f"SELECT COUNT(a.id) {from_clause}"
|
||||||
if where:
|
if where:
|
||||||
count_sql += f" WHERE {where}"
|
count_sql += f" WHERE {where}"
|
||||||
total = conn.execute(count_sql, params[:len(params)-2]).fetchone()[0]
|
total = conn.execute(count_sql, params[:len(params)-2]).fetchone()[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user