LAST 13/06/2025
This commit is contained in:
parent
efd69601ec
commit
4e7c5757e0
@ -28,11 +28,6 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Controllers
|
|||||||
return View();
|
return View();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IActionResult OtApproval()
|
|
||||||
{
|
|
||||||
return View();
|
|
||||||
}
|
|
||||||
|
|
||||||
public IActionResult Settings()
|
public IActionResult Settings()
|
||||||
{
|
{
|
||||||
return View();
|
return View();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using PSTW_CentralSystem.Areas.OTcalculate.Models;
|
using PSTW_CentralSystem.Areas.OTcalculate.Models;
|
||||||
using PSTW_CentralSystem.Models;
|
using PSTW_CentralSystem.Models;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using PSTW_CentralSystem.DBContext;
|
using PSTW_CentralSystem.DBContext;
|
||||||
|
|
||||||
@ -27,7 +27,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
decimal userRate,
|
decimal userRate,
|
||||||
DateTime? selectedMonth = null,
|
DateTime? selectedMonth = null,
|
||||||
byte[]? logoImage = null,
|
byte[]? logoImage = null,
|
||||||
bool isHoU = false,
|
bool isRestrictedUser = false,
|
||||||
string? flexiHour = null,
|
string? flexiHour = null,
|
||||||
List<ApprovalSignatureData>? approvedSignatures = null)
|
List<ApprovalSignatureData>? approvedSignatures = null)
|
||||||
{
|
{
|
||||||
@ -45,7 +45,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
var publicHolidaysForUser = _centralDbContext.Holidays
|
var publicHolidaysForUser = _centralDbContext.Holidays
|
||||||
.Where(h => userSetting != null && h.StateId == userSetting.State.StateId && h.HolidayDate.Month == displayMonth.Month && h.HolidayDate.Year == displayMonth.Year)
|
.Where(h => userSetting != null && h.StateId == userSetting.State.StateId && h.HolidayDate.Month == displayMonth.Month && h.HolidayDate.Year == displayMonth.Year)
|
||||||
.OrderBy(h => h.HolidayDate)
|
.OrderBy(h => h.HolidayDate)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
records = records.OrderBy(r => r.OtDate).ToList();
|
records = records.OrderBy(r => r.OtDate).ToList();
|
||||||
@ -117,7 +117,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
column.Item().PaddingVertical(10).LineHorizontal(0.5f).LineColor(Colors.Grey.Lighten2);
|
column.Item().PaddingVertical(10).LineHorizontal(0.5f).LineColor(Colors.Grey.Lighten2);
|
||||||
|
|
||||||
column.Item().Element(container => ComposeTable(container, records, user, userRate, showStationColumn, allDatesInMonth, isHoU, publicHolidaysForUser.Select(h => h.HolidayDate.Date).ToList()));
|
// Pass the new isRestrictedUser flag to ComposeTable
|
||||||
|
column.Item().Element(container => ComposeTable(container, records, user, userRate, showStationColumn, allDatesInMonth, isRestrictedUser, publicHolidaysForUser.Select(h => h.HolidayDate.Date).ToList()));
|
||||||
|
|
||||||
column.Item().PaddingTop(20).Element(container =>
|
column.Item().PaddingTop(20).Element(container =>
|
||||||
{
|
{
|
||||||
@ -153,7 +154,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
if (approval.ApprovedDate.HasValue)
|
if (approval.ApprovedDate.HasValue)
|
||||||
{
|
{
|
||||||
individualApprovalColumn.Item().PaddingTop(2)
|
individualApprovalColumn.Item().PaddingTop(2)
|
||||||
.Text(approval.ApprovedDate.Value.ToString("dd MMMM yyyy"))
|
.Text(approval.ApprovedDate.Value.ToString("dd MMMM yyyy"))
|
||||||
.FontSize(8).AlignCenter();
|
.FontSize(8).AlignCenter();
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
@ -173,8 +174,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
{
|
{
|
||||||
table.ColumnsDefinition(columns =>
|
table.ColumnsDefinition(columns =>
|
||||||
{
|
{
|
||||||
columns.RelativeColumn(1);
|
columns.RelativeColumn(1);
|
||||||
columns.RelativeColumn(2);
|
columns.RelativeColumn(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
table.Header(header =>
|
table.Header(header =>
|
||||||
@ -194,7 +195,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
table.Cell().ColumnSpan(2).Border(0.25f).Padding(2)
|
table.Cell().ColumnSpan(2).Border(0.25f).Padding(2)
|
||||||
.Text($"No public holidays found for {userSetting?.State?.StateName ?? "this state"} in {displayMonth:MMMM yyyy}.")
|
.Text($"No public holidays found for {userSetting?.State?.StateName ?? "this state"} in {displayMonth:MMMM yyyy}.")
|
||||||
.FontSize(7).Italic().AlignCenter();
|
.FontSize(7).Italic().AlignCenter();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -216,7 +217,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ComposeTable(IContainer container, List<OtRegisterModel> records, UserModel user, decimal userRate, bool showStationColumn, List<DateTime> allDatesInMonth, bool isHoU, List<DateTime> publicHolidays)
|
// Update the signature of ComposeTable to accept the new flag
|
||||||
|
private void ComposeTable(IContainer container, List<OtRegisterModel> records, UserModel user, decimal userRate, bool showStationColumn, List<DateTime> allDatesInMonth, bool hideSalaryDetails, List<DateTime> publicHolidays)
|
||||||
{
|
{
|
||||||
var recordsGroupedByDate = records
|
var recordsGroupedByDate = records
|
||||||
.GroupBy(r => r.OtDate.Date)
|
.GroupBy(r => r.OtDate.Date)
|
||||||
@ -230,7 +232,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
{
|
{
|
||||||
table.ColumnsDefinition(columns =>
|
table.ColumnsDefinition(columns =>
|
||||||
{
|
{
|
||||||
if (!isHoU)
|
// Conditionally add salary columns based on hideSalaryDetails
|
||||||
|
if (!hideSalaryDetails)
|
||||||
{
|
{
|
||||||
columns.RelativeColumn(0.25f); // Basic Salary
|
columns.RelativeColumn(0.25f); // Basic Salary
|
||||||
columns.RelativeColumn(0.2f); // ORP
|
columns.RelativeColumn(0.2f); // ORP
|
||||||
@ -259,7 +262,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
columns.RelativeColumn(0.3f);
|
columns.RelativeColumn(0.3f);
|
||||||
columns.RelativeColumn(0.2f);
|
columns.RelativeColumn(0.2f);
|
||||||
columns.RelativeColumn(0.2f);
|
columns.RelativeColumn(0.2f);
|
||||||
if (!isHoU)
|
if (!hideSalaryDetails) // Conditionally add Total Amt column
|
||||||
{
|
{
|
||||||
columns.RelativeColumn(0.25f);
|
columns.RelativeColumn(0.25f);
|
||||||
}
|
}
|
||||||
@ -274,7 +277,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
table.Header(header =>
|
table.Header(header =>
|
||||||
{
|
{
|
||||||
if (!isHoU)
|
// Conditionally add salary headers based on hideSalaryDetails
|
||||||
|
if (!hideSalaryDetails)
|
||||||
{
|
{
|
||||||
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("Basic Salary\n(RM)").FontSize(6).Bold().AlignCenter();
|
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("Basic Salary\n(RM)").FontSize(6).Bold().AlignCenter();
|
||||||
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("ORP").FontSize(6).Bold().AlignCenter();
|
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("ORP").FontSize(6).Bold().AlignCenter();
|
||||||
@ -299,7 +303,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total\nRD").FontSize(6).Bold().AlignCenter();
|
header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total\nRD").FontSize(6).Bold().AlignCenter();
|
||||||
header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total\nPH").FontSize(6).Bold().AlignCenter();
|
header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total\nPH").FontSize(6).Bold().AlignCenter();
|
||||||
|
|
||||||
if (!isHoU)
|
if (!hideSalaryDetails) // Conditionally add Total Amt header
|
||||||
{
|
{
|
||||||
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("OT Amt\n(RM)").FontSize(6).Bold().AlignCenter();
|
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("OT Amt\n(RM)").FontSize(6).Bold().AlignCenter();
|
||||||
}
|
}
|
||||||
@ -413,14 +417,15 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
if (center) text.AlignCenter();
|
if (center) text.AlignCenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isHoU)
|
// Conditionally render salary details
|
||||||
|
if (!hideSalaryDetails)
|
||||||
{
|
{
|
||||||
// Display the calculated values here
|
// Display the calculated values here
|
||||||
AddCell(!hasPrintedSalaryDetails ? $"{basicSalary:F2}" : "");
|
AddCell(!hasPrintedSalaryDetails ? $"{basicSalary:F2}" : "");
|
||||||
AddCell(!hasPrintedSalaryDetails ? $"{orp:F2}" : "");
|
AddCell(!hasPrintedSalaryDetails ? $"{orp:F2}" : "");
|
||||||
AddCell(!hasPrintedSalaryDetails ? $"{hrp:F2}" : "");
|
AddCell(!hasPrintedSalaryDetails ? $"{hrp:F2}" : "");
|
||||||
}
|
}
|
||||||
hasPrintedSalaryDetails = true;
|
hasPrintedSalaryDetails = true;
|
||||||
|
|
||||||
if (date.Date != previousDate?.Date)
|
if (date.Date != previousDate?.Date)
|
||||||
{
|
{
|
||||||
@ -455,7 +460,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
AddCell(totalNdOd);
|
AddCell(totalNdOd);
|
||||||
AddCell(totalRd);
|
AddCell(totalRd);
|
||||||
AddCell(totalPh);
|
AddCell(totalPh);
|
||||||
if (!isHoU)
|
if (!hideSalaryDetails) // Conditionally render Total Amt column
|
||||||
{
|
{
|
||||||
AddCell(otAmt == "0.00" ? "" : otAmt);
|
AddCell(otAmt == "0.00" ? "" : otAmt);
|
||||||
}
|
}
|
||||||
@ -473,7 +478,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isHoU)
|
// Adjust column span for the TOTAL row based on visibility
|
||||||
|
if (!hideSalaryDetails)
|
||||||
{
|
{
|
||||||
table.Cell().ColumnSpan(5).Background("#d8d1f5").Border(0.80f).Padding(3)
|
table.Cell().ColumnSpan(5).Background("#d8d1f5").Border(0.80f).Padding(3)
|
||||||
.Text("TOTAL").Bold().FontSize(6).AlignCenter();
|
.Text("TOTAL").Bold().FontSize(6).AlignCenter();
|
||||||
@ -540,10 +546,10 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
|
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
|
||||||
.Text($"{grandTotalPh:N2}").Bold().FontSize(6).AlignCenter();
|
.Text($"{grandTotalPh:N2}").Bold().FontSize(6).AlignCenter();
|
||||||
|
|
||||||
if (!isHoU)
|
if (!hideSalaryDetails) // Conditionally render Total Amt in footer
|
||||||
{
|
{
|
||||||
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
|
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
|
||||||
.Text($"{Math.Round(grandTotalOtAmount, MidpointRounding.AwayFromZero):F2}").Bold().FontSize(6).AlignCenter();
|
.Text($"{Math.Round(grandTotalOtAmount, MidpointRounding.AwayFromZero):F2}").Bold().FontSize(6).AlignCenter();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showStationColumn)
|
if (showStationColumn)
|
||||||
@ -556,7 +562,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
public MemoryStream GenerateSimpleOvertimeTablePdf(
|
public MemoryStream GenerateSimpleOvertimeTablePdf(
|
||||||
List<OtRegisterModel> records,
|
List<OtRegisterModel> records,
|
||||||
UserModel user,
|
UserModel user,
|
||||||
decimal userRate,
|
decimal userRate,
|
||||||
DateTime? selectedMonth = null,
|
DateTime? selectedMonth = null,
|
||||||
byte[]? logoImage = null,
|
byte[]? logoImage = null,
|
||||||
@ -576,8 +582,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
var publicHolidaysForUser = _centralDbContext.Holidays
|
var publicHolidaysForUser = _centralDbContext.Holidays
|
||||||
.Where(h => userSetting != null && h.StateId == userSetting.State.StateId && h.HolidayDate.Month == displayMonth.Month && h.HolidayDate.Year == displayMonth.Year)
|
.Where(h => userSetting != null && h.StateId == userSetting.State.StateId && h.HolidayDate.Month == displayMonth.Month && h.HolidayDate.Year == displayMonth.Year)
|
||||||
.OrderBy(h => h.HolidayDate)
|
.OrderBy(h => h.HolidayDate)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
records = records.OrderBy(r => r.OtDate).ToList();
|
records = records.OrderBy(r => r.OtDate).ToList();
|
||||||
var stream = new MemoryStream();
|
var stream = new MemoryStream();
|
||||||
@ -666,8 +672,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
{
|
{
|
||||||
table.ColumnsDefinition(columns =>
|
table.ColumnsDefinition(columns =>
|
||||||
{
|
{
|
||||||
columns.RelativeColumn(1);
|
columns.RelativeColumn(1);
|
||||||
columns.RelativeColumn(2);
|
columns.RelativeColumn(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
table.Header(header =>
|
table.Header(header =>
|
||||||
@ -687,7 +693,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
table.Cell().ColumnSpan(2).Border(0.25f).Padding(2)
|
table.Cell().ColumnSpan(2).Border(0.25f).Padding(2)
|
||||||
.Text($"No public holidays found for {userSetting?.State?.StateName ?? "this state"} in {displayMonth:MMMM yyyy}.") // Changed format
|
.Text($"No public holidays found for {userSetting?.State?.StateName ?? "this state"} in {displayMonth:MMMM yyyy}.")
|
||||||
.FontSize(7).Italic().AlignCenter();
|
.FontSize(7).Italic().AlignCenter();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -788,7 +794,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
decimal totalHours = 0;
|
decimal totalHours = 0;
|
||||||
decimal totalBreak = 0;
|
decimal totalBreak = 0;
|
||||||
bool alternate = false;
|
bool alternate = false;
|
||||||
DateTime? previousDate = null;
|
DateTime? previousDate = null;
|
||||||
|
|
||||||
foreach (var date in allDatesInMonth)
|
foreach (var date in allDatesInMonth)
|
||||||
{
|
{
|
||||||
@ -821,7 +827,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
AddCell("", true, backgroundColor);
|
AddCell("", true, backgroundColor);
|
||||||
AddCell("", true, backgroundColor);
|
AddCell("", true, backgroundColor);
|
||||||
}
|
}
|
||||||
previousDate = date;
|
previousDate = date;
|
||||||
|
|
||||||
var officeHours = CalculateOfficeOtHours(record);
|
var officeHours = CalculateOfficeOtHours(record);
|
||||||
var afterHours = CalculateAfterOfficeOtHours(record);
|
var afterHours = CalculateAfterOfficeOtHours(record);
|
||||||
@ -845,7 +851,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
AddCell(FormatAsHourMinute(totalTime, isMinutes: false));
|
AddCell(FormatAsHourMinute(totalTime, isMinutes: false));
|
||||||
AddCell(FormatAsHourMinute(breakTime, isMinutes: true));
|
AddCell(FormatAsHourMinute(breakTime, isMinutes: true));
|
||||||
|
|
||||||
// Station
|
// Station
|
||||||
if (showStationColumn)
|
if (showStationColumn)
|
||||||
{
|
{
|
||||||
AddCell(record.Stations?.StationName ?? "");
|
AddCell(record.Stations?.StationName ?? "");
|
||||||
@ -902,7 +908,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
var lastDate = records.Last().OtDate;
|
var lastDate = records.Last().OtDate;
|
||||||
|
|
||||||
if (firstDate.Month == lastDate.Month && firstDate.Year == lastDate.Year)
|
if (firstDate.Month == lastDate.Month && firstDate.Year == lastDate.Year)
|
||||||
return firstDate.ToString("MMMM yyyy");
|
return firstDate.ToString("MMMM yyyy");
|
||||||
|
|
||||||
return $"{firstDate:MMM yyyy} - {lastDate:MMM yyyy}";
|
return $"{firstDate:MMM yyyy} - {lastDate:MMM yyyy}";
|
||||||
}
|
}
|
||||||
@ -941,14 +947,14 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
DayOfWeek dayOfWeek = date.DayOfWeek;
|
DayOfWeek dayOfWeek = date.DayOfWeek;
|
||||||
|
|
||||||
if ((weekendId == 1 && dayOfWeek == DayOfWeek.Saturday) ||
|
if ((weekendId == 1 && dayOfWeek == DayOfWeek.Saturday) ||
|
||||||
(weekendId == 2 && dayOfWeek == DayOfWeek.Sunday))
|
(weekendId == 2 && dayOfWeek == DayOfWeek.Sunday))
|
||||||
{
|
{
|
||||||
return "Rest Day";
|
return "Rest Day";
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((weekendId == 1 && dayOfWeek == DayOfWeek.Friday) ||
|
if ((weekendId == 1 && dayOfWeek == DayOfWeek.Friday) ||
|
||||||
(weekendId == 2 && dayOfWeek == DayOfWeek.Saturday))
|
(weekendId == 2 && dayOfWeek == DayOfWeek.Saturday))
|
||||||
{
|
{
|
||||||
return "Off Day";
|
return "Off Day";
|
||||||
}
|
}
|
||||||
@ -992,11 +998,11 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
if (totalMinutes < 0)
|
if (totalMinutes < 0)
|
||||||
{
|
{
|
||||||
totalMinutes += 24 * 60;
|
totalMinutes += 24 * 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalMinutes -= (record.OfficeBreak ?? 0);
|
totalMinutes -= (record.OfficeBreak ?? 0);
|
||||||
totalMinutes = Math.Max(0, totalMinutes);
|
totalMinutes = Math.Max(0, totalMinutes);
|
||||||
|
|
||||||
int hours = (int)(totalMinutes / 60);
|
int hours = (int)(totalMinutes / 60);
|
||||||
int minutes = (int)(totalMinutes % 60);
|
int minutes = (int)(totalMinutes % 60);
|
||||||
@ -1015,11 +1021,11 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
if (totalMinutes < 0)
|
if (totalMinutes < 0)
|
||||||
{
|
{
|
||||||
totalMinutes += 24 * 60;
|
totalMinutes += 24 * 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
totalMinutes -= (record.AfterBreak ?? 0);
|
totalMinutes -= (record.AfterBreak ?? 0);
|
||||||
totalMinutes = Math.Max(0, totalMinutes);
|
totalMinutes = Math.Max(0, totalMinutes);
|
||||||
|
|
||||||
int hours = (int)(totalMinutes / 60);
|
int hours = (int)(totalMinutes / 60);
|
||||||
int minutes = (int)(totalMinutes % 60);
|
int minutes = (int)(totalMinutes % 60);
|
||||||
@ -1055,7 +1061,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
switch (dayType)
|
switch (dayType)
|
||||||
{
|
{
|
||||||
case "Normal Day":
|
case "Normal Day":
|
||||||
result["ndAfter"] = toFixedOrEmpty(afterHrs);
|
result["ndAfter"] = toFixedOrEmpty(afterHrs);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "Off Day":
|
case "Off Day":
|
||||||
@ -1105,7 +1111,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
{
|
{
|
||||||
result["phUnder8"] = toFixedOrEmpty(officeHrs); // Assign all to 'under 8'
|
result["phUnder8"] = toFixedOrEmpty(officeHrs); // Assign all to 'under 8'
|
||||||
}
|
}
|
||||||
else // If total office hours are more than 8
|
else
|
||||||
{
|
{
|
||||||
result["phAfter"] = toFixedOrEmpty(officeHrs); // Assign all to 'PH After' (for office hours beyond 8)
|
result["phAfter"] = toFixedOrEmpty(officeHrs); // Assign all to 'PH After' (for office hours beyond 8)
|
||||||
}
|
}
|
||||||
@ -1170,7 +1176,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
private string CalculateOtAmount(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
|
private string CalculateOtAmount(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
|
||||||
{
|
{
|
||||||
decimal orp = hrp * 8m;
|
decimal orp = hrp * 8m;
|
||||||
|
|
||||||
var dayType = GetDayType(record.OtDate, weekendId, publicHolidays);
|
var dayType = GetDayType(record.OtDate, weekendId, publicHolidays);
|
||||||
|
|
||||||
@ -1238,7 +1244,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services
|
|||||||
|
|
||||||
if ((weekendId == 1 && (dayOfWeek == DayOfWeek.Friday || dayOfWeek == DayOfWeek.Saturday)) ||
|
if ((weekendId == 1 && (dayOfWeek == DayOfWeek.Friday || dayOfWeek == DayOfWeek.Saturday)) ||
|
||||||
(weekendId == 2 && (dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday)))
|
(weekendId == 2 && (dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday)))
|
||||||
return "#add8e6";
|
return "#add8e6";
|
||||||
|
|
||||||
return "#ffffff";
|
return "#ffffff";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,9 +86,9 @@
|
|||||||
<table class="table table-bordered table-sm table-striped">
|
<table class="table table-bordered table-sm table-striped">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="header-orange" rowspan="2" v-if="!isHoU">Basic Salary<br>(RM)</th>
|
<th class="header-orange" rowspan="2" v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])">Basic Salary<br>(RM)</th>
|
||||||
<th class="header-orange" rowspan="2" v-if="!isHoU">ORP</th>
|
<th class="header-orange" rowspan="2" v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])">ORP</th>
|
||||||
<th class="header-orange" rowspan="2" v-if="!isHoU">HRP</th>
|
<th class="header-orange" rowspan="2" v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])">HRP</th>
|
||||||
<th class="header-green text-nowrap" rowspan="2">Date</th>
|
<th class="header-green text-nowrap" rowspan="2">Date</th>
|
||||||
<th class="header-blue" colspan="3">Office Hour</th>
|
<th class="header-blue" colspan="3">Office Hour</th>
|
||||||
<th class="header-blue" colspan="3">After Office Hour</th>
|
<th class="header-blue" colspan="3">After Office Hour</th>
|
||||||
@ -102,7 +102,7 @@
|
|||||||
<th class="header-green" rowspan="2">Total OT Hrs<br>ND & OD</th>
|
<th class="header-green" rowspan="2">Total OT Hrs<br>ND & OD</th>
|
||||||
<th class="header-green" rowspan="2">Total OT Hrs<br>RD</th>
|
<th class="header-green" rowspan="2">Total OT Hrs<br>RD</th>
|
||||||
<th class="header-green" rowspan="2">Total OT Hrs<br>PH</th>
|
<th class="header-green" rowspan="2">Total OT Hrs<br>PH</th>
|
||||||
<th class="header-green" rowspan="2" v-if="!isHoU">OT Amt (RM)</th>
|
<th class="header-green" rowspan="2" v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])">OT Amt (RM)</th>
|
||||||
<th class="header-orange" rowspan="2" v-if="showStationColumn">Station</th>
|
<th class="header-orange" rowspan="2" v-if="showStationColumn">Station</th>
|
||||||
<th class="header-blue" rowspan="2">Description</th>
|
<th class="header-blue" rowspan="2">Description</th>
|
||||||
<th class="header-green" rowspan="2">Action</th>
|
<th class="header-green" rowspan="2">Action</th>
|
||||||
@ -127,7 +127,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(record, index) in sortedOtRecords" :key="record.overtimeId">
|
<tr v-for="(record, index) in sortedOtRecords" :key="record.overtimeId">
|
||||||
<template v-if="index === 0 && !isHoU">
|
<template v-if="index === 0 && !isApproverRole(['HoU', 'HoD', 'Manager'])">
|
||||||
<td :rowspan="sortedOtRecords.length" class="text-nowrap">{{ calculateBasicSalary() }}</td>
|
<td :rowspan="sortedOtRecords.length" class="text-nowrap">{{ calculateBasicSalary() }}</td>
|
||||||
<td :rowspan="sortedOtRecords.length" class="text-nowrap">{{ calculateOrp() }}</td>
|
<td :rowspan="sortedOtRecords.length" class="text-nowrap">{{ calculateOrp() }}</td>
|
||||||
<td :rowspan="sortedOtRecords.length" class="text-nowrap">{{ calculateHrp() }}</td>
|
<td :rowspan="sortedOtRecords.length" class="text-nowrap">{{ calculateHrp() }}</td>
|
||||||
@ -162,7 +162,7 @@
|
|||||||
<td>{{ calculateRdTotal(record) }}</td>
|
<td>{{ calculateRdTotal(record) }}</td>
|
||||||
<td>{{ calculatePhTotal(record) }}</td>
|
<td>{{ calculatePhTotal(record) }}</td>
|
||||||
|
|
||||||
<td v-if="!isHoU">{{ calculateOtAmount(record) }}</td>
|
<td v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])">{{ calculateOtAmount(record) }}</td>
|
||||||
|
|
||||||
<td v-if="showStationColumn">{{ record.stationName || 'N/A' }}</td>
|
<td v-if="showStationColumn">{{ record.stationName || 'N/A' }}</td>
|
||||||
<td class="wrap-text">
|
<td class="wrap-text">
|
||||||
@ -184,23 +184,23 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="otRecords.length === 0">
|
<tr v-if="otRecords.length === 0">
|
||||||
<td :colspan="showStationColumn ? (isHoU ? 27 : 31) : (isHoU ? 26 : 30)">No overtime details found for this submission.</td>
|
<td :colspan="showStationColumn ? (isApproverRole(['HoU', 'HoD', 'Manager']) ? 27 : 31) : (isApproverRole(['HoU', 'HoD', 'Manager']) ? 26 : 30)">No overtime details found for this submission.</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
<tfoot>
|
<tfoot>
|
||||||
<tr class="fw-bold bg-light">
|
<tr class="fw-bold bg-light">
|
||||||
<td v-if="!isHoU" colspan="3">TOTAL</td>
|
<td v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])" colspan="3">TOTAL</td>
|
||||||
<td v-else colspan="1">TOTAL</td>
|
<td v-else colspan="1">TOTAL</td>
|
||||||
|
|
||||||
<td v-if="!isHoU" colspan="3"></td>
|
<td v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])" colspan="3"></td>
|
||||||
<td v-else colspan="2"></td>
|
<td v-else colspan="2"></td>
|
||||||
<td><strong>{{ formatBreakToHourMinute(totals.officeBreak) }}</strong></td>
|
<td><strong>{{ formatBreakToHourMinute(totals.officeBreak) }}</strong></td>
|
||||||
|
|
||||||
<td v-if="!isHoU" colspan="2"></td>
|
<td v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])" colspan="2"></td>
|
||||||
<td v-else colspan="2"></td>
|
<td v-else colspan="2"></td>
|
||||||
<td><strong>{{ formatBreakToHourMinute(totals.afterBreak) }}</strong></td>
|
<td><strong>{{ formatBreakToHourMinute(totals.afterBreak) }}</strong></td>
|
||||||
|
|
||||||
<td v-if="!isHoU" colspan="2"></td>
|
<td v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])" colspan="2"></td>
|
||||||
<td v-else colspan="2"></td>
|
<td v-else colspan="2"></td>
|
||||||
<td>{{ totals.ndAfter }}</td>
|
<td>{{ totals.ndAfter }}</td>
|
||||||
|
|
||||||
@ -220,7 +220,7 @@
|
|||||||
<td>{{ totals.totalRd }}</td>
|
<td>{{ totals.totalRd }}</td>
|
||||||
<td>{{ totals.totalPh }}</td>
|
<td>{{ totals.totalPh }}</td>
|
||||||
|
|
||||||
<td v-if="!isHoU">{{ totals.otAmt }}</td>
|
<td v-if="!isApproverRole(['HoU', 'HoD', 'Manager'])">{{ totals.otAmt }}</td>
|
||||||
|
|
||||||
<td v-if="showStationColumn"></td>
|
<td v-if="showStationColumn"></td>
|
||||||
|
|
||||||
@ -387,7 +387,7 @@
|
|||||||
weekendId: null,
|
weekendId: null,
|
||||||
basicSalary: null
|
basicSalary: null
|
||||||
},
|
},
|
||||||
isHoU: false,
|
isHoU: false, // Keep this for existing logic, but use isApproverRole for salary visibility
|
||||||
expandedDescriptions: [],
|
expandedDescriptions: [],
|
||||||
currentEditRecord: {
|
currentEditRecord: {
|
||||||
overtimeId: null,
|
overtimeId: null,
|
||||||
@ -545,6 +545,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
// New method to check if the current approver role is in the list of roles to hide salary info
|
||||||
|
isApproverRole(rolesToHide) {
|
||||||
|
return rolesToHide.includes(this.approverRole);
|
||||||
|
},
|
||||||
toggleDescription(index) {
|
toggleDescription(index) {
|
||||||
this.expandedDescriptions[index] = !this.expandedDescriptions[index];
|
this.expandedDescriptions[index] = !this.expandedDescriptions[index];
|
||||||
},
|
},
|
||||||
@ -562,6 +566,7 @@
|
|||||||
...data.userInfo,
|
...data.userInfo,
|
||||||
basicSalary: data.userInfo.rate
|
basicSalary: data.userInfo.rate
|
||||||
};
|
};
|
||||||
|
// No change here for isHoU, as it's used for other logic (like edit/delete buttons)
|
||||||
this.isHoU = data.isHoU;
|
this.isHoU = data.isHoU;
|
||||||
this.currentEditRecord.statusId = parseInt(statusId);
|
this.currentEditRecord.statusId = parseInt(statusId);
|
||||||
|
|
||||||
@ -1189,7 +1194,7 @@
|
|||||||
const end = this.parseTime(toTime);
|
const end = this.parseTime(toTime);
|
||||||
|
|
||||||
const minAllowedFromMinutesForMidnightTo = 16 * 60 + 30;
|
const minAllowedFromMinutesForMidnightTo = 16 * 60 + 30;
|
||||||
const maxAllowedFromMinutesForMidnightTo = 23 * 60 + 30;
|
const maxAllowedFromMidnightTo = 23 * 60 + 30;
|
||||||
const startMinutes = start.hours * 60 + start.minutes;
|
const startMinutes = start.hours * 60 + start.minutes;
|
||||||
|
|
||||||
if (end.hours === 0 && end.minutes === 0) {
|
if (end.hours === 0 && end.minutes === 0) {
|
||||||
@ -1197,7 +1202,7 @@
|
|||||||
alert(`Invalid ${label} Time: 'From' and 'To' cannot both be 00:00 (midnight).`);
|
alert(`Invalid ${label} Time: 'From' and 'To' cannot both be 00:00 (midnight).`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (startMinutes < minAllowedFromMinutesForMidnightTo || startMinutes > maxAllowedFromMinutesForMidnightTo) {
|
if (startMinutes < minAllowedFromMidnightTo || startMinutes > maxAllowedFromMidnightTo) {
|
||||||
alert(`Invalid ${label} Time: If 'To' is 12:00 am (00:00), 'From' must start between 4:30 pm and 11:30 pm on the same day to be saved.`);
|
alert(`Invalid ${label} Time: If 'To' is 12:00 am (00:00), 'From' must start between 4:30 pm and 11:30 pm on the same day to be saved.`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2282,16 +2282,23 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
var currentLoggedInUserId = GetCurrentLoggedInUserId();
|
var currentLoggedInUserId = GetCurrentLoggedInUserId();
|
||||||
|
|
||||||
var userSetting = _centralDbContext.Hrusersetting
|
var userSetting = _centralDbContext.Hrusersetting
|
||||||
.Include(us => us.Approvalflow)
|
.Include(us => us.Approvalflow)
|
||||||
.Include(us => us.FlexiHour)
|
.Include(us => us.FlexiHour)
|
||||||
.FirstOrDefault(us => us.UserId == user.Id);
|
.FirstOrDefault(us => us.UserId == user.Id);
|
||||||
|
|
||||||
bool isHoU = false;
|
// Determine if the current logged-in user is HoU, HoD, or Manager for the OT user
|
||||||
if (userSetting?.Approvalflow != null && userSetting.Approvalflow.HoU == currentLoggedInUserId)
|
bool hideSalaryDetails = false;
|
||||||
|
if (userSetting?.Approvalflow != null)
|
||||||
{
|
{
|
||||||
isHoU = true;
|
if (userSetting.Approvalflow.HoU == currentLoggedInUserId ||
|
||||||
|
userSetting.Approvalflow.HoD == currentLoggedInUserId ||
|
||||||
|
userSetting.Approvalflow.Manager == currentLoggedInUserId)
|
||||||
|
{
|
||||||
|
hideSalaryDetails = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
string? flexiHour = userSetting?.FlexiHour?.FlexiHour;
|
string? flexiHour = userSetting?.FlexiHour?.FlexiHour;
|
||||||
|
|
||||||
var approvedSignatures = new List<ApprovalSignatureData>();
|
var approvedSignatures = new List<ApprovalSignatureData>();
|
||||||
@ -2316,19 +2323,20 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
byte[]? signatureImageBytes = null;
|
byte[]? signatureImageBytes = null;
|
||||||
|
|
||||||
var staffSign = _centralDbContext.Staffsign
|
var staffSign = _centralDbContext.Staffsign
|
||||||
.FirstOrDefault(ss => ss.UserId == stage.approverId.Value);
|
.FirstOrDefault(ss => ss.UserId == stage.approverId.Value);
|
||||||
|
|
||||||
approvedSignatures.Add(new ApprovalSignatureData
|
approvedSignatures.Add(new ApprovalSignatureData
|
||||||
{
|
{
|
||||||
ApproverName = stage.approverUser.FullName,
|
ApproverName = stage.approverUser.FullName,
|
||||||
SignatureImage = signatureImageBytes,
|
SignatureImage = signatureImageBytes,
|
||||||
ApprovedDate = stage.submitDate
|
ApprovedDate = stage.submitDate
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var pdfGenerator = new OvertimePDF(_centralDbContext);
|
var pdfGenerator = new OvertimePDF(_centralDbContext);
|
||||||
var stream = pdfGenerator.GenerateOvertimeTablePdf(otRecords, user, userRate, selectedMonth, logoImage, isHoU, flexiHour, approvedSignatures);
|
// Pass the new hideSalaryDetails flag to the PDF generator
|
||||||
|
var stream = pdfGenerator.GenerateOvertimeTablePdf(otRecords, user, userRate, selectedMonth, logoImage, hideSalaryDetails, flexiHour, approvedSignatures);
|
||||||
|
|
||||||
string fileName = $"OvertimeReport_{user.FullName}_{DateTime.Now:yyyyMMdd}.pdf";
|
string fileName = $"OvertimeReport_{user.FullName}_{DateTime.Now:yyyyMMdd}.pdf";
|
||||||
return File(stream.ToArray(), "application/pdf", fileName);
|
return File(stream.ToArray(), "application/pdf", fileName);
|
||||||
@ -2423,19 +2431,45 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
.FirstOrDefault(us => us.UserId == user.Id);
|
.FirstOrDefault(us => us.UserId == user.Id);
|
||||||
|
|
||||||
bool isHoU = false;
|
bool isHoU = false;
|
||||||
if (userSetting?.Approvalflow != null && userSetting.Approvalflow.HoU == currentLoggedInUserId)
|
bool isHoD = false; // Initialize isHoD
|
||||||
|
bool isManager = false; // Initialize isManager
|
||||||
|
|
||||||
|
if (userSetting?.Approvalflow != null)
|
||||||
{
|
{
|
||||||
isHoU = true;
|
if (userSetting.Approvalflow.HoU == currentLoggedInUserId)
|
||||||
|
{
|
||||||
|
isHoU = true;
|
||||||
|
}
|
||||||
|
if (userSetting.Approvalflow.HoD == currentLoggedInUserId) // Check if current user is HoD
|
||||||
|
{
|
||||||
|
isHoD = true;
|
||||||
|
}
|
||||||
|
if (userSetting.Approvalflow.Manager == currentLoggedInUserId) // Check if current user is Manager
|
||||||
|
{
|
||||||
|
isManager = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string? flexiHour = userSetting?.FlexiHour?.FlexiHour;
|
string? flexiHour = userSetting?.FlexiHour?.FlexiHour;
|
||||||
|
|
||||||
var excelGenerator = new OvertimeExcel(_centralDbContext, _env);
|
var excelGenerator = new OvertimeExcel(_centralDbContext, _env);
|
||||||
|
|
||||||
var logoPath = Path.Combine(_env.WebRootPath, "images", "logo.jpg");
|
var logoPath = Path.Combine(_env.WebRootPath, "images", "logo.jpg");
|
||||||
byte[]? logoImage = System.IO.File.Exists(logoPath) ? System.IO.File.ReadAllBytes(logoPath) : null;
|
byte[]? logoImage = System.IO.File.Exists(logoPath) ? System.IO.File.ReadAllBytes(logoPath) : null;
|
||||||
|
|
||||||
var stream = excelGenerator.GenerateOvertimeExcel(otRecords, user, userRate, selectedMonth, isHoU, flexiHour, logoImage, isSimplifiedExport: false, otStatus);
|
var stream = excelGenerator.GenerateOvertimeExcel(
|
||||||
|
otRecords,
|
||||||
|
user,
|
||||||
|
userRate,
|
||||||
|
selectedMonth,
|
||||||
|
isHoU,
|
||||||
|
isHoD, // Pass isHoD
|
||||||
|
isManager, // Pass isManager
|
||||||
|
flexiHour,
|
||||||
|
logoImage,
|
||||||
|
isSimplifiedExport: false,
|
||||||
|
otStatus
|
||||||
|
);
|
||||||
|
|
||||||
string fileName = $"OvertimeReport_{user.FullName}_{DateTime.Now:yyyyMMdd}.xlsx";
|
string fileName = $"OvertimeReport_{user.FullName}_{DateTime.Now:yyyyMMdd}.xlsx";
|
||||||
return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
|
return File(stream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
|
||||||
@ -2460,6 +2494,7 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
|
|
||||||
var userSetting = _centralDbContext.Hrusersetting
|
var userSetting = _centralDbContext.Hrusersetting
|
||||||
.Include(us => us.FlexiHour)
|
.Include(us => us.FlexiHour)
|
||||||
|
.Include(us => us.Approvalflow) // Include Approvalflow to check roles
|
||||||
.FirstOrDefault(us => us.UserId == userId);
|
.FirstOrDefault(us => us.UserId == userId);
|
||||||
|
|
||||||
string flexiHour = userSetting?.FlexiHour?.FlexiHour;
|
string flexiHour = userSetting?.FlexiHour?.FlexiHour;
|
||||||
@ -2472,7 +2507,27 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
.Where(o => o.UserId == userId && o.OtDate >= startDate && o.OtDate < endDate)
|
.Where(o => o.UserId == userId && o.OtDate >= startDate && o.OtDate < endDate)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
bool isAdminUser = IsAdmin(user.Id);
|
var currentLoggedInUserId = GetCurrentLoggedInUserId();
|
||||||
|
|
||||||
|
bool isHoU = false;
|
||||||
|
bool isHoD = false; // Initialize isHoD
|
||||||
|
bool isManager = false; // Initialize isManager
|
||||||
|
|
||||||
|
if (userSetting?.Approvalflow != null)
|
||||||
|
{
|
||||||
|
if (userSetting.Approvalflow.HoU == currentLoggedInUserId)
|
||||||
|
{
|
||||||
|
isHoU = true;
|
||||||
|
}
|
||||||
|
if (userSetting.Approvalflow.HoD == currentLoggedInUserId) // Check if current user is HoD
|
||||||
|
{
|
||||||
|
isHoD = true;
|
||||||
|
}
|
||||||
|
if (userSetting.Approvalflow.Manager == currentLoggedInUserId) // Check if current user is Manager
|
||||||
|
{
|
||||||
|
isManager = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var excelGenerator = new OvertimeExcel(_centralDbContext, _env);
|
var excelGenerator = new OvertimeExcel(_centralDbContext, _env);
|
||||||
|
|
||||||
@ -2484,7 +2539,9 @@ namespace PSTW_CentralSystem.Controllers.API
|
|||||||
user,
|
user,
|
||||||
userRate,
|
userRate,
|
||||||
startDate,
|
startDate,
|
||||||
isHoU: false,
|
isHoU,
|
||||||
|
isHoD, // Pass isHoD
|
||||||
|
isManager, // Pass isManager
|
||||||
flexiHour: flexiHour,
|
flexiHour: flexiHour,
|
||||||
logoImage: logoImage,
|
logoImage: logoImage,
|
||||||
isSimplifiedExport: true
|
isSimplifiedExport: true
|
||||||
|
|||||||
Binary file not shown.
Loading…
Reference in New Issue
Block a user