Add Employee Timeclock feature with kiosk, attendance report, and payroll CSV export
- New EmployeeClockEntry entity (facility-level attendance, separate from job time entries) - KioskPin added to ApplicationUser; TimeclockKioskToken added to Company - TimeclockController: clock in/out, who's in, 14-day history, manager edit/delete, tablet kiosk with device-cookie auth, PIN management via Users edit page - Kiosk UI: employee tile grid + 4-digit PIN pad + auto-detect clock-in vs clock-out - Attendance report at /Reports/Attendance with weekly subtotal rows - Payroll CSV export at /Reports/AttendanceCsv (flat, one row per segment) - AllowCustomFormulas wired through PlatformSubscriptionController + subscription views - Fix soft-delete bug on CustomItemTemplate (missing HasQueryFilter in OnModelCreating) - Help article (Help/Timeclock.cshtml) and AI knowledge base updated - Migrations: AddEmployeeTimeclock, AddTimeclockKioskToken Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,7 @@ public class SubscriptionPlanConfigDto
|
||||
public bool AllowAiInventoryAssist { get; set; }
|
||||
public bool AllowAiCatalogPriceCheck { get; set; }
|
||||
public bool AllowSms { get; set; }
|
||||
public bool AllowCustomFormulas { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
}
|
||||
@@ -74,6 +75,7 @@ public class UpdateSubscriptionPlanConfigDto
|
||||
public bool AllowAiInventoryAssist { get; set; }
|
||||
public bool AllowAiCatalogPriceCheck { get; set; }
|
||||
public bool AllowSms { get; set; }
|
||||
public bool AllowCustomFormulas { get; set; }
|
||||
|
||||
public bool IsActive { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
namespace PowderCoating.Application.DTOs.Timeclock;
|
||||
|
||||
public class EmployeeClockEntryDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
public string UserDisplayName { get; set; } = string.Empty;
|
||||
public DateTime ClockInTime { get; set; }
|
||||
public DateTime? ClockOutTime { get; set; }
|
||||
public decimal? HoursWorked { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
public bool IsOpen => ClockOutTime == null;
|
||||
}
|
||||
|
||||
public class ClockInRequest
|
||||
{
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
public class ClockOutRequest
|
||||
{
|
||||
public int EntryId { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Request sent from the kiosk tablet — employee taps their tile and enters a PIN.
|
||||
/// The server determines whether to clock in or clock out based on the employee's open entry.
|
||||
/// </summary>
|
||||
public class KioskPunchRequest
|
||||
{
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
public string Pin { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class EditClockEntryRequest
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public DateTime ClockInTime { get; set; }
|
||||
public DateTime? ClockOutTime { get; set; }
|
||||
public string? Notes { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Employee tile shown on the kiosk employee-selection grid.</summary>
|
||||
public class KioskEmployeeDto
|
||||
{
|
||||
public string UserId { get; set; } = string.Empty;
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public string Initials { get; set; } = string.Empty;
|
||||
/// <summary>True when the employee has an open clock entry right now.</summary>
|
||||
public bool IsClockedIn { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user