using MySql.Data.MySqlClient; using System; namespace HanvonF710XAttendanceService { /// /// HRMS employee row used for Hanvon display name and portal photo URL. /// Device enroll/serial must NOT be treated as employee.id. /// internal sealed class HrmsEmployeeInfo { public HrmsEmployeeInfo(string employeeId, string serialNumberInt, string concatenatedName, string department = "") { EmployeeId = employeeId ?? ""; SerialNumberInt = serialNumberInt ?? ""; ConcatenatedName = concatenatedName ?? ""; Department = department ?? ""; } /// employee.id — used for portal photo URL only. public string EmployeeId { get; } /// employee.serial_number_int — matches device / attendance_machine_user.serial_number. public string SerialNumberInt { get; } /// employee.concatenated_name — Hanvon user display name. public string ConcatenatedName { get; } /// Department display name when available; otherwise department_id. public string Department { get; } } internal sealed class HrmsEmployeeDAO { /// /// Match device serial (attendance_machine_user.serial_number) to employee.serial_number_int. /// public bool TryGetByDeviceSerial(MySqlConnection connection, string deviceSerial, out HrmsEmployeeInfo employee) { employee = null; if (connection == null || string.IsNullOrWhiteSpace(deviceSerial)) { return false; } string serial = deviceSerial.Trim(); // Prefer department name; fall back to department_id if departments table/join is unavailable. const string queryWithDeptName = "SELECT e.id, e.serial_number_int, e.concatenated_name, " + "COALESCE(NULLIF(TRIM(d.name), ''), CAST(e.department_id AS CHAR), '') AS department " + "FROM hrms.employee e " + "LEFT JOIN hrms.departments d ON d.id = e.department_id " + "WHERE CAST(e.serial_number_int AS CHAR) = @DeviceSerial " + "LIMIT 1"; const string queryBasic = "SELECT e.id, e.serial_number_int, e.concatenated_name, " + "CAST(e.department_id AS CHAR) AS department " + "FROM hrms.employee e " + "WHERE CAST(e.serial_number_int AS CHAR) = @DeviceSerial " + "LIMIT 1"; try { if (TryReadEmployee(connection, queryWithDeptName, serial, out employee)) { return true; } } catch { // departments table/column may differ; fall back. } return TryReadEmployee(connection, queryBasic, serial, out employee); } private static bool TryReadEmployee(MySqlConnection connection, string query, string serial, out HrmsEmployeeInfo employee) { employee = null; using (var cmd = new MySqlCommand(query, connection)) { cmd.CommandTimeout = 60; cmd.Parameters.AddWithValue("@DeviceSerial", serial); using (var reader = cmd.ExecuteReader()) { if (!reader.Read()) { return false; } string id = reader.IsDBNull(0) ? "" : Convert.ToString(reader.GetValue(0))?.Trim(); string serialInt = reader.IsDBNull(1) ? "" : Convert.ToString(reader.GetValue(1))?.Trim(); string name = reader.IsDBNull(2) ? "" : Convert.ToString(reader.GetValue(2))?.Trim(); string department = reader.FieldCount > 3 && !reader.IsDBNull(3) ? Convert.ToString(reader.GetValue(3))?.Trim() : ""; if (string.IsNullOrWhiteSpace(id)) { return false; } employee = new HrmsEmployeeInfo(id, serialInt, name, department); return true; } } } public string ResolveDisplayName( MySqlConnection connection, string deviceSerial, string fallbackName = null) { if (TryGetByDeviceSerial(connection, deviceSerial, out HrmsEmployeeInfo employee) && !string.IsNullOrWhiteSpace(employee.ConcatenatedName)) { return employee.ConcatenatedName; } if (!string.IsNullOrWhiteSpace(fallbackName)) { return fallbackName.Trim(); } return string.IsNullOrWhiteSpace(deviceSerial) ? "" : deviceSerial.Trim(); } } }