feat: Add Cantaloupe sync API with staged import workflow

- New cantaloupe_sync.py module with complete pipeline
- Heuristic Excel column mapping (20+ keyword patterns)
- Diff engine: detects new/changed/removed/unchanged assets
- 5 API endpoints: sync, list batches, view batch, approve, reject
- cantaloupe_sync_batches table with status workflow
- Admin server port changed to 8090
- openpyxl added to requirements.txt
This commit is contained in:
Leo
2026-05-21 19:00:19 -04:00
parent 377b3868cb
commit d2c76aea7f
4 changed files with 892 additions and 2 deletions
+20
View File
@@ -26,6 +26,8 @@ from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, StreamingResponse
from pydantic import BaseModel
from cantaloupe_sync import router as cantaloupe_router, create_sync_tables
# ─── Config ─────────────────────────────────────────────────────────────────
VALID_CATEGORIES = {"Furniture", "Appliances", "Utensils & Serveware", "Equipment", "Other"}
@@ -241,10 +243,24 @@ def _create_tables(conn: sqlite3.Connection):
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS cantaloupe_sync_batches (
id INTEGER PRIMARY KEY AUTOINCREMENT,
status TEXT NOT NULL DEFAULT 'pending',
created_at TEXT NOT NULL DEFAULT (datetime('now')),
approved_at TEXT,
file_path TEXT,
row_count INTEGER DEFAULT 0,
diff_summary TEXT,
raw_data TEXT,
error_message TEXT
);
CREATE INDEX IF NOT EXISTS idx_checkins_asset_id ON checkins(asset_id);
CREATE INDEX IF NOT EXISTS idx_checkins_created_at ON checkins(created_at);
CREATE INDEX IF NOT EXISTS idx_assets_category ON assets(category);
CREATE INDEX IF NOT EXISTS idx_assets_machine_id ON assets(machine_id);
CREATE INDEX IF NOT EXISTS idx_csb_status ON cantaloupe_sync_batches(status);
CREATE INDEX IF NOT EXISTS idx_csb_created ON cantaloupe_sync_batches(created_at);
""")
@@ -293,6 +309,7 @@ def _seed_data(conn: sqlite3.Connection):
def init_db(conn: sqlite3.Connection):
"""Ensure all tables exist, run migrations if needed, seed default data."""
_create_tables(conn)
create_sync_tables(conn)
_seed_data(conn)
# Add lat/lng columns if missing (v3 migration)
cursor = conn.execute("PRAGMA table_info(assets)")
@@ -334,6 +351,9 @@ app.add_middleware(
allow_headers=["*"],
)
# Mount Cantaloupe sync routes
app.include_router(cantaloupe_router)
# ─── Auth Middleware ────────────────────────────────────────────────────────