Sep 16 - Optimize code, part 2
This commit is contained in:
+62
-12
@@ -35,6 +35,38 @@ from openpyxl.utils import get_column_letter
|
||||
|
||||
from routes.attendance import bp # shared blueprint — do not redefine
|
||||
|
||||
# Employee IDs typed on the edit / manual-add forms follow the same rule as a
|
||||
# check-in: 1 to 4 digits, optionally carrying a work-type code.
|
||||
MANUAL_EMPLOYEE_ID_MAX_DIGITS = 4
|
||||
|
||||
|
||||
def _normalize_manual_employee_id(raw_employee_id):
|
||||
"""
|
||||
(canonical_id, base_id, work_type) for an ID typed on a form, or
|
||||
(None, None, None) when it is not a valid employee ID.
|
||||
|
||||
"1234" -> ("1234", "1234", "regular")
|
||||
"1234sp" -> ("1234SP", "1234", "SP")
|
||||
"1234 . PW"-> ("1234PW", "1234", "PW")
|
||||
"12345", "abc", "" -> (None, None, None)
|
||||
|
||||
Manual entry used to do int(employee_id), so an extra-work record such as
|
||||
"1234SP" could not be added by hand at all, and edit accepted any text,
|
||||
which created pseudo-employees in the exports (§13).
|
||||
"""
|
||||
from working_hours_calculator import parse_employee_id_for_work_type
|
||||
|
||||
raw = str(raw_employee_id or '').strip()
|
||||
if not raw:
|
||||
return None, None, None
|
||||
|
||||
base_id, work_type = parse_employee_id_for_work_type(raw)
|
||||
if not re.fullmatch(r'[0-9]+', base_id) or len(base_id) > MANUAL_EMPLOYEE_ID_MAX_DIGITS:
|
||||
return None, None, None
|
||||
|
||||
canonical = base_id if work_type == 'regular' else f"{base_id}{work_type}"
|
||||
return canonical, base_id, work_type
|
||||
|
||||
|
||||
@bp.route('/attendance/<int:record_id>/edit', methods=['GET', 'POST'], endpoint='edit_attendance')
|
||||
@login_required
|
||||
@@ -74,7 +106,16 @@ def edit_attendance(record_id):
|
||||
}
|
||||
|
||||
# Update attendance record fields
|
||||
new_employee_id = request.form['employee_id'].strip().upper()
|
||||
new_employee_id, _base_id, _work_type = _normalize_manual_employee_id(
|
||||
request.form.get('employee_id', ''))
|
||||
if not new_employee_id:
|
||||
flash('Employee ID must be 1 to 4 digits, optionally with a work type '
|
||||
'(for example 1234 or 1234SP).', 'error')
|
||||
projects = Project.query.filter_by(active_status=True).order_by(Project.name).all()
|
||||
return render_template('edit_attendance.html',
|
||||
attendance_record=attendance_record,
|
||||
projects=projects,
|
||||
qr_codes=QRCode.query.filter_by(active_status=True).all())
|
||||
new_check_in_date = datetime.strptime(request.form['check_in_date'], '%Y-%m-%d').date()
|
||||
new_check_in_time = datetime.strptime(request.form['check_in_time'], '%H:%M').time()
|
||||
new_location_name = request.form['location_name'].strip()
|
||||
@@ -120,10 +161,12 @@ def edit_attendance(record_id):
|
||||
attendance_record.check_in_time = new_check_in_time
|
||||
attendance_record.location_name = new_location_name
|
||||
attendance_record.qr_code_id = int(new_qr_code_id)
|
||||
attendance_record.updated_timestamp = datetime.utcnow()
|
||||
|
||||
# Local time throughout (§18): check-in dates and times are local, so
|
||||
# a UTC audit stamp read hours apart from the record it describes.
|
||||
attendance_record.updated_timestamp = datetime.now()
|
||||
|
||||
# Store the audit note with timestamp and user info
|
||||
timestamp = datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC')
|
||||
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
username = session.get('username', 'Unknown')
|
||||
role = session.get('role', 'unknown')
|
||||
|
||||
@@ -262,10 +305,17 @@ def save_manual_attendance():
|
||||
flash('All fields are required.', 'error')
|
||||
return redirect(url_for('attendance.add_manual_attendance'))
|
||||
|
||||
# Validate employee exists
|
||||
employee = Employee.query.filter_by(id=int(employee_id)).first()
|
||||
# Validate the ID, and keep any work-type code ("1234SP") on the stored value
|
||||
canonical_employee_id, base_employee_id, work_type = _normalize_manual_employee_id(employee_id)
|
||||
if not canonical_employee_id:
|
||||
flash('Employee ID must be 1 to 4 digits, optionally with a work type '
|
||||
'(for example 1234 or 1234SP).', 'error')
|
||||
return redirect(url_for('attendance.add_manual_attendance'))
|
||||
|
||||
# Validate employee exists (by the numeric base ID)
|
||||
employee = Employee.query.filter_by(id=int(base_employee_id)).first()
|
||||
if not employee:
|
||||
flash(f'Employee with ID {employee_id} not found.', 'error')
|
||||
flash(f'Employee with ID {base_employee_id} not found.', 'error')
|
||||
return redirect(url_for('attendance.add_manual_attendance'))
|
||||
|
||||
# Get QR code (location)
|
||||
@@ -285,7 +335,7 @@ def save_manual_attendance():
|
||||
|
||||
# Check if record already exists for this employee, location, date, and time
|
||||
existing_record = AttendanceData.query.filter_by(
|
||||
employee_id=str(employee_id),
|
||||
employee_id=canonical_employee_id,
|
||||
qr_code_id=qr_code.id,
|
||||
check_in_date=check_date_obj,
|
||||
check_in_time=check_time_obj
|
||||
@@ -300,7 +350,7 @@ def save_manual_attendance():
|
||||
# Set fixed distance of 0.010 miles
|
||||
new_attendance = AttendanceData(
|
||||
qr_code_id=qr_code.id,
|
||||
employee_id=str(employee_id),
|
||||
employee_id=canonical_employee_id,
|
||||
check_in_date=check_date_obj,
|
||||
check_in_time=check_time_obj,
|
||||
location_name=qr_code.location,
|
||||
@@ -320,8 +370,8 @@ def save_manual_attendance():
|
||||
status='present',
|
||||
verification_required=False,
|
||||
verification_status='approved',
|
||||
created_timestamp=datetime.utcnow(),
|
||||
updated_timestamp=datetime.utcnow()
|
||||
created_timestamp=datetime.now(),
|
||||
updated_timestamp=datetime.now()
|
||||
)
|
||||
|
||||
db.session.add(new_attendance)
|
||||
@@ -330,7 +380,7 @@ def save_manual_attendance():
|
||||
# Log the manual entry
|
||||
logger_handler.logger.info(
|
||||
f"Manual attendance record created by {session.get('username')} ({user_role}): "
|
||||
f"Employee {employee.firstName} {employee.lastName} (ID: {employee_id}), "
|
||||
f"Employee {employee.firstName} {employee.lastName} (ID: {canonical_employee_id}), "
|
||||
f"Location: {qr_code.location}, Event: {qr_code.location_event}, "
|
||||
f"Date: {check_date}, Time: {check_time}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user