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.
main
SYED MUSTUFA AHMED NAQVI 2026-09-11 15:07:54 +05:00
parent 4f84d8834f
commit 8939e9d49c
5 changed files with 46 additions and 8 deletions

View File

@ -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);
}
}

View File

@ -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; } = "";
}

View File

@ -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/"
}

View File

@ -238,6 +238,13 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
[DataMember]
public List<string> ScopedMachineIps { get; set; } = new List<string>();
/// <summary>
/// Machine IPs whose attendance is always written to hrms.terry_attendance_log
/// (no employee/worker_type lookup). Compared to attendance event machine_ip.
/// </summary>
[DataMember]
public List<string> TerryAttendanceMachineIps { get; set; } = new List<string>();
/// <summary>DeviceId (from <see cref="DeviceConfig.DeviceId"/>) to treat as the authoritative user source.</summary>
[DataMember]
public string SourceDeviceId { get; set; } = "";
@ -314,6 +321,7 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
TemplateFetchIntervalHours = 4,
MachineScopeMode = "CENTRAL",
ScopedMachineIps = new List<string>(),
TerryAttendanceMachineIps = new List<string>(),
EnableUserSync = false,
SyncIntervalMinutes = 60,
SourceDeviceId = "",
@ -402,6 +410,7 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
TemplateFetchIntervalHours = 4,
MachineScopeMode = "CENTRAL",
ScopedMachineIps = new List<string>(),
TerryAttendanceMachineIps = new List<string>(),
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<string>(overlay.ScopedMachineIps);
if (overlay.TerryAttendanceMachineIps != null)
cfg.TerryAttendanceMachineIps = new List<string>(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<string>();
for (int i = 0; i < cfg.ScopedMachineIps.Count; i++)
cfg.ScopedMachineIps[i] = (cfg.ScopedMachineIps[i] ?? "").Trim();
cfg.TerryAttendanceMachineIps ??= new List<string>();
for (int i = 0; i < cfg.TerryAttendanceMachineIps.Count; i++)
cfg.TerryAttendanceMachineIps[i] = (cfg.TerryAttendanceMachineIps[i] ?? "").Trim();
if (cfg.TargetDeviceIds == null)
cfg.TargetDeviceIds = new List<string>();
else
@ -666,6 +680,12 @@ public sealed class HikvisionAttendanceWindowsService : ServiceBase
[DataMember]
public List<string> ScopedMachineIps { get; set; } = new List<string>();
/// <summary>
/// IPs whose punches always go to terry_attendance_log (no worker_type lookup).
/// </summary>
[DataMember]
public List<string> TerryAttendanceMachineIps { get; set; } = new List<string>();
[DataMember]
public bool EnableTemplateDeviceToDbSync { get; set; }

View File

@ -316,6 +316,8 @@ internal enum AttendancePersistOutcome
{
Duplicate,
SkippedNoEmployee,
UnmappedEmployee,
UnsupportedWorkerType,
DbInserted,
DbFailed,
PersistedWithoutDb