diff --git a/AttendanceMachineFaceTemplateDAO.cs b/AttendanceMachineFaceTemplateDAO.cs index 7c1798d..ef3187c 100644 --- a/AttendanceMachineFaceTemplateDAO.cs +++ b/AttendanceMachineFaceTemplateDAO.cs @@ -69,6 +69,7 @@ namespace HanvonF710XAttendanceService using (var cmd = new MySqlCommand(query, connection)) { + cmd.CommandTimeout = 300; for (int i = 0; i < chunk.Length; i++) { cmd.Parameters.AddWithValue(parameterNames[i], chunk[i]); @@ -178,6 +179,89 @@ namespace HanvonF710XAttendanceService return result.ToList(); } + /// + /// Active template serial numbers for employees in the given departments (HRMS employees table). + /// When department lookup is unavailable, returns an empty list and the caller should fall back. + /// + public List GetActiveSerialNumbersByDepartmentIds( + MySqlConnection connection, + IReadOnlyList departmentIds, + IReadOnlyList allowedMachineIds) + { + var result = new HashSet(StringComparer.OrdinalIgnoreCase); + if (departmentIds == null || departmentIds.Count == 0) + { + return new List(); + } + + var machineIds = (allowedMachineIds ?? Array.Empty()) + .Where(id => !string.IsNullOrWhiteSpace(id)) + .Select(id => id.Trim()) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + const int chunkSize = 80; + for (int offset = 0; offset < departmentIds.Count; offset += chunkSize) + { + var deptChunk = departmentIds.Skip(offset).Take(chunkSize).ToArray(); + var deptParamNames = new List(deptChunk.Length); + for (int i = 0; i < deptChunk.Length; i++) + { + deptParamNames.Add("@Dept" + i); + } + + string deptInClause = string.Join(",", deptParamNames); + string machineJoin = ""; + string machineFilter = ""; + if (machineIds.Count > 0) + { + var machineParamNames = new List(machineIds.Count); + for (int i = 0; i < machineIds.Count; i++) + { + machineParamNames.Add("@Mid" + i); + } + machineJoin = " INNER JOIN hrms.attendance_machine_user u ON u.serial_number = t.serial_no AND u.is_deleted = 0 "; + machineFilter = " AND u.machine_id IN (" + string.Join(",", machineParamNames) + ") "; + } + + string query = + "SELECT DISTINCT t.serial_no " + + "FROM hrms.attendance_machine_face_templates t " + + "INNER JOIN hrms.employee e ON CAST(e.emp_id AS CHAR) = t.serial_no " + + machineJoin + + "WHERE t.is_active = 1 AND e.department_id IN (" + deptInClause + ")" + + machineFilter; + + using (var cmd = new MySqlCommand(query, connection)) + { + cmd.CommandTimeout = 120; + for (int i = 0; i < deptChunk.Length; i++) + { + cmd.Parameters.AddWithValue(deptParamNames[i], deptChunk[i]); + } + for (int i = 0; i < machineIds.Count; i++) + { + cmd.Parameters.AddWithValue("@Mid" + i, machineIds[i]); + } + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + if (reader.IsDBNull(0)) continue; + var s = reader.GetString(0); + if (!string.IsNullOrWhiteSpace(s)) + { + result.Add(s.Trim()); + } + } + } + } + } + + return result.ToList(); + } + /// /// Active templates for employees registered on a specific Nedo machine. /// Registration-based target selection: attendance_machine_user (is_deleted=0) drives which employees are allowed.