From 8939e9d49cb3e2e2d4d4f581f2c64cd3bee02933 Mon Sep 17 00:00:00 2001 From: "mustafa.ahmed" Date: Fri, 11 Sep 2026 15:07:54 +0500 Subject: [PATCH] feat: route Terry machine punches to terry_attendance_log Add TerryAttendanceMachineIps config and persist punches from those IPs directly to terry_attendance_log without worker_type lookup. Add employee worker_type lookup and persist outcomes for unmapped/unsupported workers on non-Terry machines. --- BusinessLogging.cs | 8 ++++++-- Data/DbModels.cs | 6 ++++++ DeviceSettings.config | 18 ++++++++++++------ HikvisionAttendanceWindowsService.cs | 20 ++++++++++++++++++++ OpsLogging.cs | 2 ++ 5 files changed, 46 insertions(+), 8 deletions(-) diff --git a/BusinessLogging.cs b/BusinessLogging.cs index e7b822d..bff134d 100644 --- a/BusinessLogging.cs +++ b/BusinessLogging.cs @@ -83,6 +83,10 @@ internal static class BizFriendlyReasons } } - public static string FormatTime(DateTime dt) => - dt.ToString("M/d/yyyy h:mm:ss tt", CultureInfo.InvariantCulture); + public static string FormatTime(DateTime dt) + { + if (dt.Kind == DateTimeKind.Utc) + dt = dt.ToLocalTime(); + return dt.ToString("M/d/yyyy h:mm:ss tt", CultureInfo.InvariantCulture); + } } diff --git a/Data/DbModels.cs b/Data/DbModels.cs index 3befcaf..24a9730 100644 --- a/Data/DbModels.cs +++ b/Data/DbModels.cs @@ -34,3 +34,9 @@ internal sealed class AttendanceMachineFaceTemplateRow public string SourceMachineId { get; set; } = ""; public string SourceMachineIp { get; set; } = ""; } + +internal sealed class EmployeeWorkerTypeRow +{ + public int SerialNumberInt { get; set; } + public string WorkerType { get; set; } = ""; +} diff --git a/DeviceSettings.config b/DeviceSettings.config index b7a9bf3..b0dacd1 100644 --- a/DeviceSettings.config +++ b/DeviceSettings.config @@ -1,16 +1,22 @@ { "MachineScopeMode": "SITE", "ScopedMachineIps": [ -"192.168.91.80" +"192.168.90.184", +"192.168.86.7", +"192.168.40.225", +"192.168.40.226" +], + +"TerryAttendanceMachineIps": [ +"192.168.40.225", +"192.168.40.226" ], "EnableTemplateDeviceToDbSync": false, "EnableTemplateDbToDeviceSync": false, -"SourceMachineIp": "192.168.91.80", -"TargetMachineIps": [ -"192.168.91.80" -], +"SourceMachineIp": "", +"TargetMachineIps": [], "SyncEmployeeIds": [], "SyncDepartmentIds": [], @@ -18,7 +24,7 @@ "EnableInitialDepartmentSync": false, "InitialSyncDepartmentIds": [], "InitialSyncEmployeeIds": [], -"InitialSyncLocationSiteId": 2, +"InitialSyncLocationSiteId":2, "EnableEmployeePhotoSource": true, "EmployeePhotoBaseUrl": "https://portal.utopiaindustries.pk/uind/employee-photo/" } diff --git a/HikvisionAttendanceWindowsService.cs b/HikvisionAttendanceWindowsService.cs index db039dc..dabf489 100644 --- a/HikvisionAttendanceWindowsService.cs +++ b/HikvisionAttendanceWindowsService.cs @@ -238,6 +238,13 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase [DataMember] public List ScopedMachineIps { get; set; } = new List(); + /// + /// Machine IPs whose attendance is always written to hrms.terry_attendance_log + /// (no employee/worker_type lookup). Compared to attendance event machine_ip. + /// + [DataMember] + public List TerryAttendanceMachineIps { get; set; } = new List(); + /// DeviceId (from ) to treat as the authoritative user source. [DataMember] public string SourceDeviceId { get; set; } = ""; @@ -314,6 +321,7 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase TemplateFetchIntervalHours = 4, MachineScopeMode = "CENTRAL", ScopedMachineIps = new List(), + TerryAttendanceMachineIps = new List(), EnableUserSync = false, SyncIntervalMinutes = 60, SourceDeviceId = "", @@ -402,6 +410,7 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase TemplateFetchIntervalHours = 4, MachineScopeMode = "CENTRAL", ScopedMachineIps = new List(), + TerryAttendanceMachineIps = new List(), EnableUserSync = false, SyncIntervalMinutes = 60, SourceDeviceId = "", @@ -574,6 +583,8 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase cfg.MachineScopeMode = overlay.MachineScopeMode; if (overlay.ScopedMachineIps != null) cfg.ScopedMachineIps = new List(overlay.ScopedMachineIps); + if (overlay.TerryAttendanceMachineIps != null) + cfg.TerryAttendanceMachineIps = new List(overlay.TerryAttendanceMachineIps); cfg.EnableTemplateDeviceToDbSync = overlay.EnableTemplateDeviceToDbSync; cfg.EnableTemplateDbToDeviceSync = overlay.EnableTemplateDbToDeviceSync; if (overlay.SourceMachineIp != null) @@ -618,6 +629,9 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase cfg.ScopedMachineIps ??= new List(); for (int i = 0; i < cfg.ScopedMachineIps.Count; i++) cfg.ScopedMachineIps[i] = (cfg.ScopedMachineIps[i] ?? "").Trim(); + cfg.TerryAttendanceMachineIps ??= new List(); + for (int i = 0; i < cfg.TerryAttendanceMachineIps.Count; i++) + cfg.TerryAttendanceMachineIps[i] = (cfg.TerryAttendanceMachineIps[i] ?? "").Trim(); if (cfg.TargetDeviceIds == null) cfg.TargetDeviceIds = new List(); else @@ -666,6 +680,12 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase [DataMember] public List ScopedMachineIps { get; set; } = new List(); + /// + /// IPs whose punches always go to terry_attendance_log (no worker_type lookup). + /// + [DataMember] + public List TerryAttendanceMachineIps { get; set; } = new List(); + [DataMember] public bool EnableTemplateDeviceToDbSync { get; set; } diff --git a/OpsLogging.cs b/OpsLogging.cs index eae3bf0..e459fa2 100644 --- a/OpsLogging.cs +++ b/OpsLogging.cs @@ -316,6 +316,8 @@ internal enum AttendancePersistOutcome { Duplicate, SkippedNoEmployee, + UnmappedEmployee, + UnsupportedWorkerType, DbInserted, DbFailed, PersistedWithoutDb