Add sync module: push seed data to main app DB (dev/prod)
- New sync.py: reads seed import's 39-col schema, maps to main app's customers/locations/assets schema with foreign keys - New POST /api/sync endpoint (target=dev|prod, dry_run=true/false) - New GET /api/sync/targets endpoint - Category mapping: Bev→Beverage, Snack→Snack, Food→Food, etc. - Automatically creates customers and locations from company/place - Idempotent: updates existing assets by machine_id - Dry-run mode: preview changes without writing
This commit is contained in:
@@ -37,6 +37,7 @@ sys.path.insert(0, str(PROJECT_ROOT))
|
||||
from parser import parse_excel
|
||||
from db_writer import write_seed, write_update, ALL_COLUMNS, PRESERVE_FIELDS, AUTO_FIELDS
|
||||
from backup import backup as do_backup, compare as compare_backup
|
||||
from sync import push as sync_push, TARGETS as SYNC_TARGETS
|
||||
|
||||
|
||||
# ─── Helpers ──────────────────────────────────────────────────────────────────
|
||||
@@ -550,6 +551,43 @@ async def api_db_wipe(db_path: str = Query(DEFAULT_DB_PATH)):
|
||||
raise HTTPException(500, f"Wipe error: {e}")
|
||||
|
||||
|
||||
# ─── Sync / Push to Main App ──────────────────────────────────────────────────
|
||||
|
||||
|
||||
@app.post("/api/sync")
|
||||
async def api_sync(
|
||||
target: str = Query("dev"),
|
||||
dry_run: bool = Query(False),
|
||||
):
|
||||
"""Push seed import data to the main app database."""
|
||||
if target not in SYNC_TARGETS:
|
||||
raise HTTPException(400, f"Unknown target: {target}. Options: {list(SYNC_TARGETS.keys())}")
|
||||
target_db = SYNC_TARGETS[target]["path"]
|
||||
source_db = DEFAULT_DB_PATH
|
||||
report = sync_push(source_db, target_db, dry_run=dry_run)
|
||||
if "error" in report:
|
||||
raise HTTPException(500, report["error"])
|
||||
return report
|
||||
|
||||
|
||||
@app.get("/api/sync/targets")
|
||||
async def api_sync_targets():
|
||||
"""Return available sync targets."""
|
||||
return {
|
||||
"targets": {
|
||||
name: {
|
||||
"path": info["path"],
|
||||
"exists": os.path.exists(info["path"]),
|
||||
}
|
||||
for name, info in SYNC_TARGETS.items()
|
||||
},
|
||||
"source": {
|
||||
"path": DEFAULT_DB_PATH,
|
||||
"exists": os.path.exists(DEFAULT_DB_PATH),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# ─── Static files ─────────────────────────────────────────────────────────────
|
||||
|
||||
STATIC_DIR = Path(__file__).parent / "static"
|
||||
|
||||
Reference in New Issue
Block a user