feat: skip already-registered users and emit DB_TO_DEVICE summary

Skip active attendance_machine_user rows; produce per-target summary report.
main
SYED MUSTUFA AHMED NAQVI 2026-09-04 12:35:46 +05:00
parent c41950a22a
commit 5e80e11b0e
2 changed files with 270 additions and 0 deletions

133
DbToDeviceSummary.cs Normal file
View File

@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace HanvonF710XAttendanceService
{
internal sealed class DbToDeviceFailedEmployee
{
public string SerialNumber { get; set; } = "";
public string Name { get; set; } = "";
public string Department { get; set; } = "";
public string MachineId { get; set; } = "";
public string MachineIp { get; set; } = "";
public string MachineType { get; set; } = "";
public string Reason { get; set; } = "";
}
internal sealed class DbToDeviceMissingMappingEmployee
{
public string SerialNumber { get; set; } = "";
public string MachineId { get; set; } = "";
public string MachineIp { get; set; } = "";
public string MachineType { get; set; } = "";
}
internal sealed class DbToDeviceTargetSummary
{
public string MachineId { get; set; } = "";
public string MachineIp { get; set; } = "";
public string MachineType { get; set; } = "";
public int AlreadyRegistered { get; set; }
public int NewlyRegistered { get; set; }
public int Failed { get; set; }
public List<DbToDeviceFailedEmployee> FailedEmployees { get; } = new List<DbToDeviceFailedEmployee>();
public List<DbToDeviceMissingMappingEmployee> MissingMappings { get; } = new List<DbToDeviceMissingMappingEmployee>();
public void AddFailure(string serial, string name, string department, string reason)
{
Failed++;
FailedEmployees.Add(new DbToDeviceFailedEmployee
{
SerialNumber = serial ?? "",
Name = name ?? "",
Department = department ?? "",
MachineId = MachineId,
MachineIp = MachineIp,
MachineType = MachineType,
Reason = reason ?? ""
});
}
public void AddMissingMapping(string serial)
{
MissingMappings.Add(new DbToDeviceMissingMappingEmployee
{
SerialNumber = serial ?? "",
MachineId = MachineId,
MachineIp = MachineIp,
MachineType = MachineType
});
}
public string FormatReport()
{
var sb = new StringBuilder();
sb.AppendLine("=================================");
sb.AppendLine("DB_TO_DEVICE SUMMARY");
sb.AppendLine("=================================");
sb.AppendLine();
sb.AppendLine("Target:");
sb.AppendLine("Machine ID: " + MachineId);
sb.AppendLine("IP: " + MachineIp);
sb.AppendLine("Type: " + MachineType);
sb.AppendLine();
sb.AppendLine("Already Registered: " + AlreadyRegistered);
sb.AppendLine();
sb.AppendLine("Newly Registered: " + NewlyRegistered);
sb.AppendLine();
sb.AppendLine("Failed: " + Failed);
sb.AppendLine();
sb.AppendLine("Missing Employee Mapping: " + MissingMappings.Count);
if (MissingMappings.Count > 0)
{
sb.AppendLine();
foreach (var miss in MissingMappings)
{
sb.AppendLine("Serial: " + miss.SerialNumber);
sb.AppendLine("Machine ID: " + miss.MachineId);
sb.AppendLine("Machine IP: " + miss.MachineIp);
sb.AppendLine("Machine Type: " + miss.MachineType);
sb.AppendLine("Reason: No employee row for serial_number_int");
sb.AppendLine();
}
}
else
{
sb.AppendLine();
}
if (FailedEmployees.Count > 0)
{
sb.AppendLine("Failed Employees:");
sb.AppendLine();
foreach (var fail in FailedEmployees)
{
sb.AppendLine("Serial: " + fail.SerialNumber);
sb.AppendLine("Name: " + fail.Name);
sb.AppendLine("Department: " + fail.Department);
sb.AppendLine("Machine ID: " + fail.MachineId);
sb.AppendLine("Machine IP: " + fail.MachineIp);
sb.AppendLine("Machine Type: " + fail.MachineType);
sb.AppendLine("Reason: " + fail.Reason);
sb.AppendLine();
}
}
return sb.ToString().TrimEnd() + Environment.NewLine;
}
}
internal static class DbToDeviceSkipLogic
{
public static bool ShouldSkipAlreadyRegistered(ISet<string> registeredSerials, string employeeSerial)
{
if (registeredSerials == null || string.IsNullOrWhiteSpace(employeeSerial))
{
return false;
}
return registeredSerials.Contains(employeeSerial.Trim());
}
}
}

137
DbToDeviceSummaryTests.cs Normal file
View File

@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
namespace HanvonF710XAttendanceService
{
internal static class DbToDeviceSummaryTests
{
public static int RunAll()
{
int failed = 0;
failed += Run("existing user is skipped", TestExistingUserSkipped);
failed += Run("missing user is enrolled", TestMissingUserEnrolled);
failed += Run("summary contains required fields", TestSummaryContainsRequiredFields);
failed += Run("multiple machines produce separate summaries", TestMultipleMachineSummaries);
return failed;
}
private static int Run(string name, Func<bool> test)
{
try
{
if (!test())
{
Console.WriteLine("FAIL: " + name);
return 1;
}
Console.WriteLine("PASS: " + name);
return 0;
}
catch (Exception ex)
{
Console.WriteLine("FAIL: " + name + " err=" + ex.Message);
return 1;
}
}
private static bool TestExistingUserSkipped()
{
var registered = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "15057", "6401" };
return DbToDeviceSkipLogic.ShouldSkipAlreadyRegistered(registered, "15057")
&& DbToDeviceSkipLogic.ShouldSkipAlreadyRegistered(registered, " 6401 ")
&& !DbToDeviceSkipLogic.ShouldSkipAlreadyRegistered(registered, "99999");
}
private static bool TestMissingUserEnrolled()
{
var registered = new HashSet<string>(StringComparer.OrdinalIgnoreCase) { "15057" };
var summary = new DbToDeviceTargetSummary
{
MachineId = "105",
MachineIp = "192.168.90.223",
MachineType = "HANVON"
};
// Existing -> skip
if (DbToDeviceSkipLogic.ShouldSkipAlreadyRegistered(registered, "15057"))
{
summary.AlreadyRegistered++;
}
// Missing -> enroll
if (!DbToDeviceSkipLogic.ShouldSkipAlreadyRegistered(registered, "99999"))
{
summary.NewlyRegistered++;
}
return summary.AlreadyRegistered == 1 && summary.NewlyRegistered == 1;
}
private static bool TestSummaryContainsRequiredFields()
{
var summary = new DbToDeviceTargetSummary
{
MachineId = "105",
MachineIp = "192.168.90.223",
MachineType = "HANVON",
AlreadyRegistered = 620,
NewlyRegistered = 30
};
summary.AddMissingMapping("88888");
summary.AddFailure("15057", "John Smith", "Production", "Employee photo not found");
summary.AddFailure("6401", "ABC XYZ", "Quality", "DUPLICATE_FACE existing_device_id=6400");
string report = summary.FormatReport();
return report.Contains("DB_TO_DEVICE SUMMARY")
&& report.Contains("Machine ID: 105")
&& report.Contains("IP: 192.168.90.223")
&& report.Contains("Type: HANVON")
&& report.Contains("Already Registered: 620")
&& report.Contains("Newly Registered: 30")
&& report.Contains("Failed: 2")
&& report.Contains("Missing Employee Mapping: 1")
&& report.Contains("Serial: 15057")
&& report.Contains("Name: John Smith")
&& report.Contains("Department: Production")
&& report.Contains("Reason: Employee photo not found")
&& report.Contains("DUPLICATE_FACE existing_device_id=6400");
}
private static bool TestMultipleMachineSummaries()
{
var a = new DbToDeviceTargetSummary
{
MachineId = "105",
MachineIp = "192.168.90.223",
MachineType = "HANVON",
AlreadyRegistered = 10,
NewlyRegistered = 2
};
var b = new DbToDeviceTargetSummary
{
MachineId = "106",
MachineIp = "10.0.1.7",
MachineType = "HANVON",
AlreadyRegistered = 5,
NewlyRegistered = 7
};
b.AddFailure("6401", "ABC XYZ", "Quality", "DUPLICATE_FACE existing_device_id=6400");
string reportA = a.FormatReport();
string reportB = b.FormatReport();
return reportA.Contains("Machine ID: 105")
&& reportA.Contains("IP: 192.168.90.223")
&& reportA.Contains("Already Registered: 10")
&& reportA.Contains("Newly Registered: 2")
&& !reportA.Contains("10.0.1.7")
&& reportB.Contains("Machine ID: 106")
&& reportB.Contains("IP: 10.0.1.7")
&& reportB.Contains("Already Registered: 5")
&& reportB.Contains("Newly Registered: 7")
&& reportB.Contains("Failed: 1")
&& !reportB.Contains("192.168.90.223");
}
}
}