| """ |
| CONSTABLE – SQLite database helpers. |
| Tables: |
| employees – id (TEXT PK), name (TEXT), registered_at (TEXT) |
| attendance – id (INTEGER PK), employee_id (TEXT FK), timestamp (TEXT), date (TEXT) |
| """ |
|
|
| import sqlite3 |
| import os |
| from datetime import datetime, date |
|
|
| DB_DIR = os.path.join(os.path.dirname(__file__)) |
| DB_PATH = os.path.join(DB_DIR, "constable.db") |
|
|
|
|
| def get_connection(): |
| conn = sqlite3.connect(DB_PATH, check_same_thread=False) |
| conn.row_factory = sqlite3.Row |
| return conn |
|
|
|
|
| def init_db(): |
| """Create tables if they don't exist.""" |
| os.makedirs(DB_DIR, exist_ok=True) |
| conn = get_connection() |
| cur = conn.cursor() |
| cur.executescript(""" |
| CREATE TABLE IF NOT EXISTS employees ( |
| id TEXT PRIMARY KEY, |
| name TEXT NOT NULL, |
| registered_at TEXT NOT NULL |
| ); |
| |
| CREATE TABLE IF NOT EXISTS attendance ( |
| id INTEGER PRIMARY KEY AUTOINCREMENT, |
| employee_id TEXT NOT NULL, |
| timestamp TEXT NOT NULL, |
| date TEXT NOT NULL, |
| FOREIGN KEY (employee_id) REFERENCES employees(id) |
| ); |
| """) |
| conn.commit() |
| conn.close() |
|
|
|
|
| |
| |
| |
|
|
| def add_employee(employee_id: str, name: str) -> bool: |
| """Insert or replace an employee record. Returns True on success.""" |
| conn = get_connection() |
| try: |
| conn.execute( |
| "INSERT OR REPLACE INTO employees (id, name, registered_at) VALUES (?, ?, ?)", |
| (employee_id, name, datetime.now().isoformat(timespec="seconds")), |
| ) |
| conn.commit() |
| return True |
| except Exception as e: |
| print(f"[DB] add_employee error: {e}") |
| return False |
| finally: |
| conn.close() |
|
|
|
|
| def get_employee(employee_id: str): |
| """Return employee row or None.""" |
| conn = get_connection() |
| try: |
| row = conn.execute( |
| "SELECT * FROM employees WHERE id = ?", (employee_id,) |
| ).fetchone() |
| return dict(row) if row else None |
| finally: |
| conn.close() |
|
|
|
|
| def get_all_employees(): |
| conn = get_connection() |
| try: |
| rows = conn.execute("SELECT * FROM employees ORDER BY registered_at DESC").fetchall() |
| return [dict(r) for r in rows] |
| finally: |
| conn.close() |
|
|
|
|
| def delete_employee(employee_id: str) -> bool: |
| """Delete an employee and their attendance records. Returns True on success.""" |
| conn = get_connection() |
| try: |
| conn.execute("DELETE FROM attendance WHERE employee_id = ?", (employee_id,)) |
| conn.execute("DELETE FROM employees WHERE id = ?", (employee_id,)) |
| conn.commit() |
| return True |
| except Exception as e: |
| print(f"[DB] delete_employee error: {e}") |
| return False |
| finally: |
| conn.close() |
|
|
|
|
| |
| |
| |
|
|
| def mark_attendance(employee_id: str) -> dict: |
| """ |
| Log attendance for today. |
| Returns {'status': 'success'|'already_marked', 'timestamp': ...} |
| """ |
| today = date.today().isoformat() |
| conn = get_connection() |
| try: |
| existing = conn.execute( |
| "SELECT id FROM attendance WHERE employee_id = ? AND date = ?", |
| (employee_id, today), |
| ).fetchone() |
| if existing: |
| return {"status": "already_marked"} |
|
|
| ts = datetime.now().strftime("%I:%M %p") |
| conn.execute( |
| "INSERT INTO attendance (employee_id, timestamp, date) VALUES (?, ?, ?)", |
| (employee_id, ts, today), |
| ) |
| conn.commit() |
| return {"status": "success", "timestamp": ts} |
| finally: |
| conn.close() |
|
|
|
|
| def get_today_attendance(): |
| today = date.today().isoformat() |
| conn = get_connection() |
| try: |
| rows = conn.execute( |
| """SELECT a.timestamp, e.id, e.name |
| FROM attendance a |
| JOIN employees e ON a.employee_id = e.id |
| WHERE a.date = ? |
| ORDER BY a.id DESC""", |
| (today,), |
| ).fetchall() |
| return [dict(r) for r in rows] |
| finally: |
| conn.close() |
|
|