Files
xenia-pos-local/local_backend/wipe_database.py
bonamin 79bd3b0f41 feat(local_backend): reservations, print analytics, workday summary, zone-PIN management
- New reservations module: model, schema, router (CRUD + status updates + upcoming alerts)
  and background task for auto-expiring stale reservations
- Reports: print_products, print_categories, print_tables analytics endpoints
  plus meta_products and business_day_summary for workday close/view flow
- printer_service: configurable font sizes/weights, donut/bar chart print layout helpers,
  analytics print blocks per printer
- tables/schemas: surfaced color, zone, and other new fields on Table, Product, User, Printer
- demo_seed.py for quick dev DB population; wipe_database.py utility

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-07 20:25:22 +03:00

120 lines
7.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
Wipes the POS database completely and re-applies the schema + default seed data.
Usage:
python wipe_database.py
Safe to run even if the backend is stopped. Does NOT delete the .db file —
it drops all tables and recreates them so the file path stays intact.
After running this, run demo_seed.py to populate with demo data.
"""
import sys
# ── Confirmation prompt ───────────────────────────────────────────────────────
print("=" * 60)
print(" WARNING: This will PERMANENTLY DELETE all data in the")
print(" POS database including orders, products, users, etc.")
print("=" * 60)
answer = input("\nType YES to confirm: ").strip()
if answer != "YES":
print("Aborted.")
sys.exit(0)
# ── Imports (after confirmation, so we don't waste time if user bails) ────────
from sqlalchemy import text, inspect
from database import engine, Base, SessionLocal
# Import all models so Base.metadata knows about every table
import models.user # noqa: F401
import models.table # noqa: F401
import models.printer # noqa: F401
import models.product # noqa: F401
import models.order # noqa: F401
import models.business_day # noqa: F401
import models.shift # noqa: F401
import models.settings # noqa: F401
import models.flag # noqa: F401
import models.message # noqa: F401
print("\nDropping all tables...")
# SQLite doesn't support DROP TABLE ... CASCADE, so we disable FK checks,
# drop every table we know about, then re-enable them.
with engine.connect() as conn:
conn.execute(text("PRAGMA foreign_keys = OFF"))
conn.commit()
# Reflect the actual DB to catch any tables we might have missed in models
inspector = inspect(engine)
existing_tables = inspector.get_table_names()
# Drop in reverse dependency order using reflected metadata
with engine.connect() as conn:
for table_name in existing_tables:
conn.execute(text(f"DROP TABLE IF EXISTS [{table_name}]"))
print(f" dropped: {table_name}")
conn.execute(text("PRAGMA foreign_keys = ON"))
conn.commit()
print("\nRecreating schema...")
Base.metadata.create_all(bind=engine)
# Re-run the same migration/seed SQL from main.py so default settings,
# flags, and quick message templates are present after the wipe.
print("Applying seed migrations...")
seed_migrations = [
# pos_settings defaults
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('shifts.waiter_self_start', 'true', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('shifts.waiter_self_end', 'true', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('business_day.force_close_allowed', 'true', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('flags.display_mode', 'both', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.ticket_mode', 'detailed', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_order_number', '48:1:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_meta', '0:0:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_item_name', '16:1:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_quick', '0:0:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_pref', '0:0:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_extra', '0:0:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_ingredient', '0:0:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_item_note', '0:0:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('print.font_order_note', '0:1:0', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('venue.name', '', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('venue.type', '', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('security.login_method', 'password', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('security.autofill_username', 'true', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('security.auto_lock', 'false', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('security.auto_lock_seconds', '300', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('security.auto_logout', 'false', CURRENT_TIMESTAMP)",
"INSERT OR IGNORE INTO pos_settings (key, value, updated_at) VALUES ('security.auto_logout_seconds', '1800', CURRENT_TIMESTAMP)",
# Default table flag definitions
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (1, 'Χρειάζεται καθάρισμα', '🧹', '#ef4444', 1)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (2, 'Χρειάζεται Βοήθεια', '🆘', '#f97316', 2)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (3, 'Χρειάζεται Σερβιτόρο', '🔔', '#eab308', 3)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (4, 'Περιμένει να πληρώσει', '💳', '#3b82f6', 4)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (5, 'VIP', '', '#8b5cf6', 5)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (6, 'Ευγενικός Πελάτης', '😊', '#22c55e', 6)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (7, 'Αγενής Πελάτης', '😤', '#dc2626', 7)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (8, 'Αλλεργίες', '⚠️', '#f59e0b', 8)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (9, 'Παιδιά στο τραπέζι', '👶', '#06b6d4', 9)",
"INSERT OR IGNORE INTO table_flag_defs (id, name, emoji, color, sort_order) VALUES (10, 'Επέτειος / Γενέθλια', '🎂', '#ec4899', 10)",
# Default quick message templates
"INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (1, 'Σε χρειάζομαι τώρα', 1)",
"INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (2, 'Πάρε διάλειμμα', 2)",
"INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (3, 'Ετοιμάσου για κλείσιμο', 3)",
"INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (4, 'Ήρθε νέος πελάτης', 4)",
"INSERT OR IGNORE INTO quick_message_templates (id, body, sort_order) VALUES (5, 'Ο πελάτης περιμένει να πληρώσει', 5)",
]
for sql in seed_migrations:
try:
with engine.connect() as conn:
conn.execute(text(sql))
conn.commit()
except Exception as e:
print(f" [skip] {e}")
print("\nDone. Database is clean and ready.")
print("Run python demo_seed.py to populate with demo data.")