dtr_system/
│
├── main.py # App entry point
│
├── views/ # VIEW layer — PySide6 UI widgets
│ ├── main_window.py # Root window, sidebar, topbar, theme toggle
│ ├── dashboard_view.py # Stat cards + line/bar charts (QtCharts)
│ ├── dtr_view.py # DTR table + printable CSF-48 preview
│ ├── employees_view.py # Employee table + register modal
│ └── settings_view.py # Calendar config + ZKTeco biometrics
│
├── controllers/ # CONTROLLER layer — event ↔ service bridge
│ ├── dashboard_controller.py
│ ├── dtr_controller.py
│ ├── employees_controller.py
│ └── settings_controller.py
│
├── services/ # SERVICE layer — business logic & validation
│ └── __init__.py
│
├── dao/ # DAO layer — data access (swap per DB)
│ └── __init__.py
│
├── models/ # MODEL layer — pure dataclasses
│ └── __init__.py
│
├── resources/
│ └── styles/
│ └── theme.py # Light + Dark QSS stylesheets
│
└── utils/
└── widgets.py # Shared widget helpers
UI Event → Controller → Service → DAO → Database
↑ |
└────────────────────────────────────────┘
(response flows back up)
- Python 3.11+
- Windows 10/11 (64-bit)
# 1. Create virtual environment
python -m venv venv
venv\Scripts\activate # Windows
# 2. Install dependencies
pip install -r requirements.txt
# 3. Run the application
python main.py- 4 real-time stat cards: Total Employees, Present Today, Late Today, Absent Today
- Monthly attendance line chart (QtCharts / QSplineSeries)
- Weekly attendance bar chart (QBarSeries)
- Month/year filter dropdown
- Employee selector dropdown
- 12-hour clock format throughout
- Color-coded table: 🔴 Weekends | 🔵 Holidays | 🟡 Late
- Period filter: 1–15 | 16–31 | Full Month
- Printable CSF No. 48 preview (HTML-rendered in QTextEdit)
- Print via system printer (QPrintDialog)
- Export PDF hook (wires to PDF service)
- Searchable, filterable employee table
- Department, Status, Supervisor columns
- Edit / Deactivate action buttons
- Register Employee modal with full validation
- Pagination bar
- Section 1: Interactive month calendar
- Click any weekday to toggle it as a holiday (blue)
- Weekends auto-highlighted in red
- Navigate months with ‹ / › buttons
- Section 2: ZKTeco Biometrics configuration
- IP Address, Port, Device Name, Timeout fields
- Test Connection (async — runs in QThread, shows success/error status)
- Save Configuration button
- Device status info panel (model, last sync, records, firmware)
- Sync Attendance Logs button
- ⏰ Real-time clock in topbar (updates every second)
- 🌙 Smooth dark mode toggle (custom animated ToggleSwitch widget)
- Full dark/light QSS theme with matching colour palette
- Minimum 1280×780 window
All DAO classes in dao/__init__.py have abstract base classes (EmployeeDAO,
DTRDAO, etc.). To add SQLite or PostgreSQL support:
- Create a new file e.g.
dao/sqlite_dao.py - Implement the abstract methods using
sqlite3orpsycopg2 - Pass your concrete DAO to the service constructor:
# services/DAO.py
from dao.sqlite_dao import SQLiteEmployeeDAO
class EmployeeService:
def __init__(self, dao=None):
self._dao = dao or SQLiteEmployeeDAO("dtr.db")The BiometricsService.test_connection() already performs a raw TCP socket
check. For full attendance log retrieval, install the zk library:
pip install zkThen update services/__init__.py:
from zk import ZK
zk = ZK(ip, port=port, timeout=timeout)
conn = zk.connect()
attendance = conn.get_attendance()
conn.disconnect()