feat: add location_slots to job_reservations for full slot persistence and update version to 0.9.1

Fix: modems do not show as "missing" any more, cleans up the dashboard.
This commit is contained in:
2026-03-24 01:06:37 +00:00
parent 8694282dd0
commit bb5387c194
8 changed files with 81 additions and 7 deletions

View File

@@ -30,7 +30,7 @@ Base.metadata.create_all(bind=engine)
ENVIRONMENT = os.getenv("ENVIRONMENT", "production")
# Initialize FastAPI app
VERSION = "0.9.0"
VERSION = "0.9.1"
if ENVIRONMENT == "development":
_build = os.getenv("BUILD_NUMBER", "0")
if _build and _build != "0":

View File

@@ -0,0 +1,24 @@
"""
Migration: Add location_slots column to job_reservations table.
Stores the full ordered slot list (including empty/unassigned slots) as JSON.
Run once per database.
"""
import sqlite3
import os
DB_PATH = os.environ.get("DB_PATH", "/app/data/seismo_fleet.db")
def run():
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
existing = [r[1] for r in cursor.execute("PRAGMA table_info(job_reservations)").fetchall()]
if "location_slots" not in existing:
cursor.execute("ALTER TABLE job_reservations ADD COLUMN location_slots TEXT")
conn.commit()
print("Added location_slots column to job_reservations.")
else:
print("location_slots column already exists, skipping.")
conn.close()
if __name__ == "__main__":
run()

View File

@@ -482,6 +482,10 @@ class JobReservation(Base):
quantity_needed = Column(Integer, nullable=True) # e.g., 8 units
estimated_units = Column(Integer, nullable=True)
# Full slot list as JSON: [{"location_name": "North Gate", "unit_id": null}, ...]
# Includes empty slots (no unit assigned yet). Filled slots are authoritative in JobReservationUnit.
location_slots = Column(Text, nullable=True)
# Metadata
notes = Column(Text, nullable=True)
color = Column(String, default="#3B82F6") # For calendar display (blue default)

View File

@@ -212,6 +212,7 @@ async def create_reservation(
if estimated_end_date and estimated_end_date < start_date:
raise HTTPException(status_code=400, detail="Estimated end date must be after start date")
import json as _json
reservation = JobReservation(
id=str(uuid.uuid4()),
name=data["name"],
@@ -224,6 +225,7 @@ async def create_reservation(
device_type=data.get("device_type", "seismograph"),
quantity_needed=data.get("quantity_needed"),
estimated_units=data.get("estimated_units"),
location_slots=_json.dumps(data["location_slots"]) if data.get("location_slots") is not None else None,
notes=data.get("notes"),
color=data.get("color", "#3B82F6")
)
@@ -275,6 +277,9 @@ async def get_reservation(
# Build per-unit lookups from assignments
assignment_map = {a.unit_id: a for a in assignments_sorted}
import json as _json
stored_slots = _json.loads(reservation.location_slots) if reservation.location_slots else None
return {
"id": reservation.id,
"name": reservation.name,
@@ -287,6 +292,7 @@ async def get_reservation(
"device_type": reservation.device_type,
"quantity_needed": reservation.quantity_needed,
"estimated_units": reservation.estimated_units,
"location_slots": stored_slots,
"notes": reservation.notes,
"color": reservation.color,
"assigned_units": [
@@ -336,6 +342,9 @@ async def update_reservation(
reservation.quantity_needed = data["quantity_needed"]
if "estimated_units" in data:
reservation.estimated_units = data["estimated_units"]
if "location_slots" in data:
import json as _json
reservation.location_slots = _json.dumps(data["location_slots"]) if data["location_slots"] is not None else None
if "notes" in data:
reservation.notes = data["notes"]
if "color" in data: