TIFNJK_E41222030/app/services/attendance.py

102 lines
3.3 KiB
Python

from dataclasses import dataclass
from datetime import datetime
from typing import Optional
from database import Database
@dataclass
class AttendanceResult:
status: str
message: str
attendance_id: Optional[int]
student_id: Optional[int]
student_name: Optional[str]
class_id: Optional[int]
class AttendanceService:
def __init__(self, db: Database) -> None:
self.db = db
def can_mark_attendance(self, recognized_name: str) -> tuple[bool, str, Optional[int], Optional[str]]:
"""Check if a student can mark attendance today (not already attended).
Returns: (can_attend, message, student_id, student_name)
"""
student = self.db.find_student_by_name(recognized_name)
if not student:
return False, f"Siswa '{recognized_name}' tidak ditemukan di database.", None, None
student_id = int(student["id"])
id_class = int(student["id_class"])
student_name = student["name"]
if self.db.has_attendance_today(student_id=student_id, id_class=id_class):
return False, "Absensi hari ini sudah tercatat untuk kelas ini.", student_id, student_name
return True, "Siswa bisa absensi.", student_id, student_name
def mark_attendance(
self,
recognized_name: str,
confidence: float,
source: str,
picture_filename: str,
status: str = "tepat waktu",
) -> AttendanceResult:
"""Mark attendance from recognized face.
Args:
- recognized_name: Student name recognized by model (must match student name in DB)
- confidence: Model confidence score
- source: Source of detection ('camera' or 'upload')
- picture_filename: Filename/path of the picture being processed
- status: 'tepat waktu' (on-time) or 'terlambat' (late)
Returns: AttendanceResult with details of the attendance record
"""
student = self.db.find_student_by_name(recognized_name)
if not student:
return AttendanceResult(
status="not_found",
message=f"Siswa '{recognized_name}' tidak ditemukan di database.",
attendance_id=None,
student_id=None,
student_name=None,
class_id=None,
)
student_id = int(student["id"])
id_class = int(student["id_class"])
student_name = student["name"]
if self.db.has_attendance_today(student_id=student_id, id_class=id_class):
return AttendanceResult(
status="duplicate",
message="Absensi hari ini sudah tercatat untuk kelas ini.",
attendance_id=None,
student_id=student_id,
student_name=student_name,
class_id=id_class,
)
attendance_id = self.db.insert_attendance(
id_student=student_id,
id_class=id_class,
picture_filename=picture_filename,
status=status,
)
return AttendanceResult(
status="marked",
message=f"Absensi {student_name} berhasil dicatat ({status}).",
attendance_id=attendance_id,
student_id=student_id,
student_name=student_name,
class_id=id_class,
)