add order management: status tracking, notes, admin endpoints

This commit is contained in:
2026-06-20 17:46:17 +01:00
parent e73e39e306
commit 6a77649bd8
+57 -3
View File
@@ -11,6 +11,7 @@ from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
DB_PATH = os.environ.get("DB_PATH", "/srv/form-backend/submissions.db")
STATUSES = ["received", "confirmed", "hardware ready", "installing", "completed", "cancelled"]
# ---- DB Helpers ----
@@ -67,6 +68,7 @@ def init_schema(db):
CREATE TABLE IF NOT EXISTS submissions (
id INTEGER PRIMARY KEY AUTOINCREMENT,
form_id INTEGER NOT NULL DEFAULT 1 REFERENCES forms(id),
status TEXT NOT NULL DEFAULT 'received',
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
@@ -94,6 +96,13 @@ def init_schema(db):
token TEXT PRIMARY KEY,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE TABLE IF NOT EXISTS submission_notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
submission_id INTEGER NOT NULL REFERENCES submissions(id) ON DELETE CASCADE,
note TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
""")
db.commit()
@@ -326,7 +335,7 @@ def check_status(email: str = "", phone: str = ""):
raise HTTPException(400, "Email and phone are required")
db = get_db()
rows = db.execute("""
SELECT s.id, s.created_at
SELECT s.id, s.status, s.created_at
FROM submissions s
JOIN submission_data d1 ON d1.submission_id = s.id AND d1.field_label = 'Email' AND d1.field_value = ?
JOIN submission_data d2 ON d2.submission_id = s.id AND d2.field_label = 'Phone' AND d2.field_value = ?
@@ -336,7 +345,8 @@ def check_status(email: str = "", phone: str = ""):
if not rows:
raise HTTPException(404, "No submission found with that email and phone")
r = rows[0]
return {"id": r["id"], "created_at": r["created_at"], "status": "received"}
status_idx = STATUSES.index(r["status"]) if r["status"] in STATUSES else 0
return {"id": r["id"], "created_at": r["created_at"], "status": r["status"], "status_index": status_idx, "total_statuses": len(STATUSES)}
# ---- Delete Submission (verify with email + phone) ----
@@ -364,6 +374,50 @@ def delete_submission(email: str = "", phone: str = ""):
db.close()
return {"ok": True, "deleted_id": sub_id}
# ---- Admin: Update Status ----
class StatusUpdate(BaseModel):
submission_id: int
status: str
@app.post("/admin/status", status_code=200)
def update_status(body: StatusUpdate, request: Request):
check_auth(request)
if body.status not in STATUSES:
raise HTTPException(400, f"Invalid status. Must be one of: {', '.join(STATUSES)}")
db = get_db()
db.execute("UPDATE submissions SET status = ? WHERE id = ?", (body.status, body.submission_id))
db.commit()
db.close()
return {"ok": True}
# ---- Admin: Add Note ----
class NoteBody(BaseModel):
submission_id: int
note: str
@app.post("/admin/notes", status_code=201)
def add_note(body: NoteBody, request: Request):
check_auth(request)
if not body.note.strip():
raise HTTPException(400, "Note cannot be empty")
db = get_db()
db.execute("INSERT INTO submission_notes (submission_id, note) VALUES (?, ?)", (body.submission_id, body.note.strip()))
db.commit()
db.close()
return {"ok": True}
# ---- Admin: Get Notes ----
@app.get("/admin/notes/{submission_id}")
def get_notes(submission_id: int, request: Request):
check_auth(request)
db = get_db()
rows = db.execute("SELECT id, note, created_at FROM submission_notes WHERE submission_id = ? ORDER BY id DESC", (submission_id,)).fetchall()
db.close()
return [dict(r) for r in rows]
# ---- Admin Submissions ----
@app.get("/admin/submissions")
@@ -399,7 +453,7 @@ def admin_submissions(
).fetchone()
result.append({
"id": r["id"], "form_id": r["form_id"], "form_name": r["form_name"],
"created_at": r["created_at"],
"created_at": r["created_at"], "status": r["status"],
"data": [dict(d) for d in data],
"tags": [t["tag"] for t in tags],
"reply": dict(reply) if reply else None