inventory_mobile/pstw_centralizesystem/Areas/OTcalculate/Services/OvertimePDF.cs
2025-12-15 15:35:35 +08:00

1252 lines
61 KiB
C#

using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using PSTW_CentralSystem.Areas.OTcalculate.Models;
using PSTW_CentralSystem.Models;
using Microsoft.EntityFrameworkCore;
using PSTW_CentralSystem.DBContext;
namespace PSTW_CentralSystem.Areas.OTcalculate.Services
{
public class OvertimePDF
{
private readonly CentralSystemContext _centralDbContext;
public OvertimePDF(CentralSystemContext centralDbContext)
{
_centralDbContext = centralDbContext;
}
public MemoryStream GenerateOvertimeTablePdf(
List<OtRegisterModel> records,
UserModel user,
decimal userRate,
DateTime? selectedMonth = null,
byte[]? logoImage = null,
bool isRestrictedUser = false,
string? flexiHour = null,
List<ApprovalSignatureData>? approvedSignatures = null)
{
bool isAdminUser = IsAdmin(user.Id);
bool showStationColumn = user.departmentId == 2 || user.departmentId == 3 || isAdminUser;
DateTime displayMonth = selectedMonth ??
(records.Any() ? records.First().OtDate : DateTime.Now);
var allDatesInMonth = GetAllDatesInMonth(displayMonth);
var userSetting = _centralDbContext.Hrusersetting
.Include(us => us.State)
.FirstOrDefault(us => us.UserId == user.Id);
var publicHolidaysForUser = _centralDbContext.Holidays
.Where(h => userSetting != null && h.StateId == userSetting.State.StateId && h.HolidayDate.Month == displayMonth.Month && h.HolidayDate.Year == displayMonth.Year)
.OrderBy(h => h.HolidayDate)
.ToList();
records = records.OrderBy(r => r.OtDate).ToList();
var stream = new MemoryStream();
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4.Landscape());
page.Margin(30);
page.Content().Column(column =>
{
column.Item().Row(row =>
{
row.RelativeItem(2).Column(col =>
{
if (logoImage != null)
{
col.Item().PaddingBottom(10).Container().Height(25).Image(logoImage, ImageScaling.FitArea);
}
col.Item().PaddingBottom(2).Text(text =>
{
text.Span("Name: ").SemiBold().FontSize(9);
text.Span($"{user.FullName} |").FontSize(9);
text.Span(" Department: ").SemiBold().FontSize(9);
text.Span($"{user.Department?.DepartmentName ?? "N/A"} |").FontSize(9);
if (!string.IsNullOrEmpty(flexiHour))
{
text.Span(" Flexi Hour: ").SemiBold().FontSize(9);
text.Span($"{flexiHour}").FontSize(9);
}
});
});
row.RelativeItem(1).AlignRight().Text($"Generated: {DateTime.Now:dd MMM yyyy HH:mm}")
.FontSize(9).FontColor(Colors.Grey.Medium);
});
column.Item().PaddingTop(3).Row(row =>
{
row.RelativeItem(2).Text($"Overtime Record: {displayMonth:MMMM yyyy}").FontSize(9).Italic();
row.RelativeItem(1).AlignRight().Column(legendCol =>
{
legendCol.Item().Element(e => e.ShowEntire().Row(subRow =>
{
subRow.AutoItem().Text(text =>
{
text.Span(" ").BackgroundColor("#add8e6").FontSize(9);
text.Span(" Weekend").FontSize(8).FontColor(Colors.Black);
});
}));
legendCol.Item().Element(e => e.ShowEntire().Row(subRow =>
{
subRow.AutoItem().Text(text =>
{
text.Span(" ").BackgroundColor("#ffc0cb").FontSize(9);
text.Span(" Public Holiday").FontSize(8).FontColor(Colors.Black);
});
}));
});
});
column.Item().PaddingVertical(10).LineHorizontal(0.5f).LineColor(Colors.Grey.Lighten2);
// 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 =>
{
container.ShowEntire().Row(row =>
{
row.RelativeItem().Element(e => e.ShowEntire().Column(approvalCol =>
{
if (approvedSignatures != null && approvedSignatures.Any())
{
approvalCol.Item().Element(e => e.ShowEntire().Row(approvalsRow =>
{
approvalsRow.Spacing(20);
foreach (var approval in approvedSignatures)
{
approvalsRow.RelativeItem().Element(e => e.ShowEntire().Column(individualApprovalColumn =>
{
individualApprovalColumn.Item().Text("Approved by:").FontSize(9).SemiBold().AlignCenter();
individualApprovalColumn.Item().PaddingTop(1)
.Height(50)
.AlignCenter()
.AlignMiddle()
.Text(approval.ApproverName)
.FontSize(15)
.FontColor(Colors.Black)
.FontFamily("Brush Script MT");
individualApprovalColumn.Item().PaddingTop(1)
.Text(approval.ApproverName).FontSize(9).SemiBold().AlignCenter();
if (approval.ApprovedDate.HasValue)
{
individualApprovalColumn.Item().PaddingTop(2)
.Text(approval.ApprovedDate.Value.ToString("dd MMMM yyyy"))
.FontSize(8).AlignCenter();
}
}));
}
}));
}
}));
row.RelativeItem().Element(e => e.ShowEntire().Column(remarksCol =>
{
remarksCol.Item().Element(e => e.ShowEntire().Row(remarksRow =>
{
remarksRow.RelativeItem(2).Element(e => e.ShowEntire().AlignRight().Column(holidayListCol =>
{
holidayListCol.Item().Text("Public Holidays:").FontSize(9).SemiBold();
holidayListCol.Item().Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.RelativeColumn(1);
columns.RelativeColumn(2);
});
table.Header(header =>
{
header.Cell().Border(0.25f).Padding(2).Text("Date").FontSize(7).Bold().AlignCenter();
header.Cell().Border(0.25f).Padding(2).Text("Holiday Name").FontSize(7).Bold().AlignCenter();
});
if (publicHolidaysForUser.Any())
{
foreach (var holiday in publicHolidaysForUser)
{
table.Cell().Border(0.25f).Padding(2).Text($"{holiday.HolidayDate:dd-MM-yyyy}").FontSize(7).AlignCenter();
table.Cell().Border(0.25f).Padding(2).Text(holiday.HolidayName).FontSize(7).AlignLeft();
}
}
else
{
table.Cell().ColumnSpan(2).Border(0.25f).Padding(2)
.Text($"No public holidays found for {userSetting?.State?.StateName ?? "this state"} in {displayMonth:MMMM yyyy}.")
.FontSize(7).Italic().AlignCenter();
}
});
}));
}));
}));
});
});
if (approvedSignatures != null && approvedSignatures.Any())
{
column.Item().PaddingTop(20).AlignCenter().Text("This is an automatically generated document. No signature is required for validation.").FontSize(8).Italic().FontColor(Colors.Grey.Darken2);
}
});
});
}).GeneratePdf(stream);
stream.Position = 0;
return stream;
}
// 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
.GroupBy(r => r.OtDate.Date)
.ToDictionary(g => g.Key, g => g.ToList());
var userSetting = _centralDbContext.Hrusersetting
.Include(us => us.State)
.FirstOrDefault(us => us.UserId == user.Id);
container.Table(table =>
{
table.ColumnsDefinition(columns =>
{
// Conditionally add salary columns based on hideSalaryDetails
if (!hideSalaryDetails)
{
columns.RelativeColumn(0.25f); // Basic Salary
columns.RelativeColumn(0.2f); // ORP
columns.RelativeColumn(0.2f); // HRP
}
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.4f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.25f);
columns.RelativeColumn(0.25f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.25f);
columns.RelativeColumn(0.3f);
columns.RelativeColumn(0.2f);
columns.RelativeColumn(0.2f);
if (!hideSalaryDetails) // Conditionally add Total Amt column
{
columns.RelativeColumn(0.25f);
}
if (showStationColumn)
{
columns.RelativeColumn(0.3f);
}
columns.RelativeColumn(0.7f);
});
table.Header(header =>
{
// 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("ORP").FontSize(6).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3).Text("HRP").FontSize(6).Bold().AlignCenter();
}
header.Cell().RowSpan(2).Background("#e0f7da").Border(0.25f).Padding(3).Text("Day").FontSize(6).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#d0ead2").Border(0.25f).Padding(3).Text("Date").FontSize(6).Bold().AlignCenter();
header.Cell().ColumnSpan(3).Background("#dceefb").Border(0.25f).Padding(3).Text("Office Hours").FontSize(6).Bold().AlignCenter();
header.Cell().ColumnSpan(3).Background("#edf2f7").Border(0.25f).Padding(3).Text("After Office Hours").FontSize(6).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("OT Hrs\n(Office Hour)").FontSize(6).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("OT Hrs\n(After Office Hour)").FontSize(6).Bold().AlignCenter();
header.Cell().ColumnSpan(1).Background("#deebf7").Border(0.25f).Padding(3).Text("Normal Day").FontSize(5).Bold().AlignCenter();
header.Cell().ColumnSpan(3).Background("#deebf7").Border(0.25f).Padding(3).Text("Off Day").FontSize(5).Bold().AlignCenter();
header.Cell().ColumnSpan(3).Background("#deebf7").Border(0.25f).Padding(3).Text("Rest Day").FontSize(5).Bold().AlignCenter();
header.Cell().ColumnSpan(2).Background("#deebf7").Border(0.25f).Padding(3).Text("Public Holiday").FontSize(5).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total OT").FontSize(6).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#fdebd0").Border(0.25f).Padding(3).Text("Total\nND & OD").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();
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();
}
if (showStationColumn)
{
header.Cell().RowSpan(2).Background("#d0f0ef").Border(0.25f).Padding(3).Text("Station").FontSize(6).Bold().AlignCenter();
}
header.Cell().RowSpan(2).Background("#e3f2fd").Border(0.25f).Padding(3).Text("Description").FontSize(6).Bold().AlignCenter();
header.Cell().Background("#dceefb").Border(0.25f).Padding(3).Text("From").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#dceefb").Border(0.25f).Padding(3).Text("To").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#dceefb").Border(0.25f).Padding(3).Text("Break\n(min)").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#edf2f7").Border(0.25f).Padding(3).Text("From").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#edf2f7").Border(0.25f).Padding(3).Text("To").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#edf2f7").Border(0.25f).Padding(3).Text("Break\n(min)").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("ND OT").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("OD < 4").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("OD 4-8").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("OD After").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("RD < 4").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("RD 4-8").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("RD After").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("PH < 8").FontSize(5).Bold().AlignCenter();
header.Cell().Background("#deebf7").Border(0.25f).Padding(3).Text("PH After").FontSize(5).Bold().AlignCenter();
});
decimal totalOfficeBreak = 0;
decimal totalAfterBreak = 0;
decimal totalOtHrsOffice = 0;
decimal totalOtHrsAfterOffice = 0;
decimal totalNdOt = 0;
decimal totalOdUnder4 = 0;
decimal totalOd4to8 = 0;
decimal totalOdAfter = 0;
decimal totalRdUnder4 = 0;
decimal totalRd4to8 = 0;
decimal totalRdAfter = 0;
decimal totalPhUnder8 = 0;
decimal totalPhAfter = 0;
decimal grandTotalOt = 0;
decimal grandTotalNdOd = 0;
decimal grandTotalRd = 0;
decimal grandTotalPh = 0;
decimal grandTotalOtAmount = 0;
bool alternate = false;
var basicSalary = userRate; // userRate is now treated as basic salary
var orp = basicSalary / 26m; // Calculate ORP from basicSalary
var hrp = orp / 8m; // Calculate HRP from ORP
bool hasPrintedSalaryDetails = false;
DateTime? previousDate = null;
foreach (var date in allDatesInMonth)
{
recordsGroupedByDate.TryGetValue(date, out var dateRecords);
var recordsToShow = dateRecords ?? new List<OtRegisterModel> { new OtRegisterModel { OtDate = date } };
recordsToShow = recordsToShow.OrderBy(r => r.OfficeFrom ?? r.AfterFrom).ToList();
foreach (var record in recordsToShow)
{
var dayType = GetDayType(date, userSetting?.State?.WeekendId, publicHolidays);
var backgroundColor = GetDayCellBackgroundColor(date, userSetting?.State?.WeekendId, publicHolidays);
var classified = ClassifyOt(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
var totalOt = CalculateTotalOtHrs(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
var totalNdOd = CalculateNdOdTotal(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
var totalRd = CalculateRdTotal(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
var totalPh = CalculatePhTotal(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
var otAmt = CalculateOtAmount(record, hrp, publicHolidays, userSetting?.State?.WeekendId);
totalOfficeBreak += (decimal)record.OfficeBreak.GetValueOrDefault(0);
totalAfterBreak += (decimal)record.AfterBreak.GetValueOrDefault(0);
totalOtHrsOffice += ConvertTimeToDecimal(CalculateOfficeOtHours(record));
totalOtHrsAfterOffice += ConvertTimeToDecimal(CalculateAfterOfficeOtHours(record));
totalNdOt += decimal.TryParse(classified["ndAfter"], out decimal ndOtVal) ? ndOtVal : 0;
totalOdUnder4 += decimal.TryParse(classified["odUnder4"], out decimal odUnder4Val) ? odUnder4Val : 0;
totalOd4to8 += decimal.TryParse(classified["odBetween4And8"], out decimal od4to8Val) ? od4to8Val : 0;
totalOdAfter += decimal.TryParse(classified["odAfter"], out decimal odAfterVal) ? odAfterVal : 0;
totalRdUnder4 += decimal.TryParse(classified["rdUnder4"], out decimal rdUnder4Val) ? rdUnder4Val : 0;
totalRd4to8 += decimal.TryParse(classified["rdBetween4And8"], out decimal rd4to8Val) ? rd4to8Val : 0;
totalRdAfter += decimal.TryParse(classified["rdAfter"], out decimal rdAfterVal) ? rdAfterVal : 0;
totalPhUnder8 += decimal.TryParse(classified["phUnder8"], out decimal phUnder8Val) ? phUnder8Val : 0;
totalPhAfter += decimal.TryParse(classified["phAfter"], out decimal phAfterVal) ? phAfterVal : 0;
grandTotalOt += decimal.TryParse(totalOt, out decimal totalOtVal) ? totalOtVal : 0;
grandTotalNdOd += decimal.TryParse(totalNdOd, out decimal totalNdOdVal) ? totalNdOdVal : 0;
grandTotalRd += decimal.TryParse(totalRd, out decimal totalRdVal) ? totalRdVal : 0;
grandTotalPh += decimal.TryParse(totalPh, out decimal totalPhVal) ? totalPhVal : 0;
grandTotalOtAmount += decimal.TryParse(otAmt, out decimal otAmtVal) ? otAmtVal : 0;
string rowBg = alternate ? "#f9f9f9" : "#ffffff";
if (dateRecords == null || !dateRecords.Any())
rowBg = alternate ? Colors.Grey.Lighten5 : Colors.White;
void AddCell(string value, bool center = true, string? bg = null)
{
var cell = table.Cell().Background(bg ?? rowBg).Border(0.25f).Padding(2);
var text = cell.Text(value).FontSize(6);
if (center) text.AlignCenter();
}
// Conditionally render salary details
if (!hideSalaryDetails)
{
// Display the calculated values here
AddCell(!hasPrintedSalaryDetails ? $"{basicSalary:F2}" : "");
AddCell(!hasPrintedSalaryDetails ? $"{orp:F2}" : "");
AddCell(!hasPrintedSalaryDetails ? $"{hrp:F2}" : "");
}
hasPrintedSalaryDetails = true;
if (date.Date != previousDate?.Date)
{
AddCell(date.ToString("ddd"), true, backgroundColor);
AddCell(date.ToString("dd-MM-yyyy"), true, backgroundColor);
}
else
{
AddCell("", true, backgroundColor);
AddCell("", true, backgroundColor);
}
previousDate = date;
AddCell(record.OfficeFrom?.ToString(@"hh\:mm") ?? "");
AddCell(record.OfficeTo?.ToString(@"hh\:mm") ?? "");
AddCell(FormatAsHourMinute(record.OfficeBreak, isMinutes: true));
AddCell(record.AfterFrom?.ToString(@"hh\:mm") ?? "");
AddCell(record.AfterTo?.ToString(@"hh\:mm") ?? "");
AddCell(FormatAsHourMinute(record.AfterBreak, isMinutes: true));
AddCell(CalculateOfficeOtHours(record));
AddCell(CalculateAfterOfficeOtHours(record));
AddCell(classified["ndAfter"]);
AddCell(classified["odUnder4"]);
AddCell(classified["odBetween4And8"]);
AddCell(classified["odAfter"]);
AddCell(classified["rdUnder4"]);
AddCell(classified["rdBetween4And8"]);
AddCell(classified["rdAfter"]);
AddCell(classified["phUnder8"]);
AddCell(classified["phAfter"]);
AddCell(totalOt);
AddCell(totalNdOd);
AddCell(totalRd);
AddCell(totalPh);
if (!hideSalaryDetails) // Conditionally render Total Amt column
{
AddCell(otAmt == "0.00" ? "" : otAmt);
}
if (showStationColumn)
{
AddCell(record.Stations?.StationName ?? "");
}
table.Cell().Background(rowBg).Border(0.25f).Padding(2)
.Text(record.OtDescription ?? "").FontSize(6).AlignLeft();
alternate = !alternate;
}
}
// Adjust column span for the TOTAL row based on visibility
if (!hideSalaryDetails)
{
table.Cell().ColumnSpan(5).Background("#d8d1f5").Border(0.80f).Padding(3)
.Text("TOTAL").Bold().FontSize(6).AlignCenter();
}
else
{
table.Cell().ColumnSpan(2).Background("#d8d1f5").Border(0.80f).Padding(3)
.Text("TOTAL").Bold().FontSize(6).AlignCenter();
}
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text(totalOfficeBreak == 0 ? "0.00" : FormatAsHourMinute(totalOfficeBreak, isMinutes: true))
.Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text(totalAfterBreak == 0 ? "0.00" : FormatAsHourMinute(totalAfterBreak, isMinutes: true))
.Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalNdOt:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalOdUnder4:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalOd4to8:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalOdAfter:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalRdUnder4:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalRd4to8:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalRdAfter:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalPhUnder8:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{totalPhAfter:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{grandTotalOt:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{grandTotalNdOd:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{grandTotalRd:N2}").Bold().FontSize(6).AlignCenter();
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{grandTotalPh:N2}").Bold().FontSize(6).AlignCenter();
if (!hideSalaryDetails) // Conditionally render Total Amt in footer
{
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text($"{Math.Round(grandTotalOtAmount, MidpointRounding.AwayFromZero):F2}").Bold().FontSize(6).AlignCenter();
}
if (showStationColumn)
{
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
}
table.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
});
}
public MemoryStream GenerateSimpleOvertimeTablePdf(
List<OtRegisterModel> records,
UserModel user,
decimal userRate,
DateTime? selectedMonth = null,
byte[]? logoImage = null,
string? flexiHour = null)
{
bool isAdminUser = IsAdmin(user.Id);
bool showStationColumn = user.departmentId == 2 || user.departmentId == 3 || isAdminUser;
DateTime displayMonth = selectedMonth ??
(records.Any() ? records.First().OtDate : DateTime.Now);
var allDatesInMonth = GetAllDatesInMonth(displayMonth);
var userSetting = _centralDbContext.Hrusersetting
.Include(us => us.State)
.FirstOrDefault(us => us.UserId == user.Id);
var publicHolidaysForUser = _centralDbContext.Holidays
.Where(h => userSetting != null && h.StateId == userSetting.State.StateId && h.HolidayDate.Month == displayMonth.Month && h.HolidayDate.Year == displayMonth.Year)
.OrderBy(h => h.HolidayDate)
.ToList();
records = records.OrderBy(r => r.OtDate).ToList();
var stream = new MemoryStream();
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4.Landscape());
page.Margin(30);
page.Content().Column(column =>
{
column.Item().Row(row =>
{
row.RelativeItem(2).Column(col =>
{
if (logoImage != null)
{
col.Item().PaddingBottom(10).Container().Height(25).Image(logoImage, ImageScaling.FitArea);
}
col.Item().PaddingBottom(2).Text(text =>
{
text.Span("Name: ").SemiBold().FontSize(9);
text.Span($"{user.FullName} |").FontSize(9);
text.Span(" Department: ").SemiBold().FontSize(9);
text.Span($"{user.Department?.DepartmentName ?? "N/A"} |").FontSize(9);
if (!string.IsNullOrEmpty(flexiHour))
{
text.Span(" Flexi Hour: ").SemiBold().FontSize(9);
text.Span($"{flexiHour}").FontSize(9);
}
});
});
row.RelativeItem(1).AlignRight().Text($"Generated: {DateTime.Now:dd MMM yyyy HH:mm}")
.FontSize(9).FontColor(Colors.Grey.Medium);
});
column.Item().PaddingTop(3).Row(row =>
{
row.RelativeItem(2).Text($"Overtime Record: {displayMonth:MMMM yyyy}").SemiBold().FontSize(9).Italic();
row.RelativeItem(1).AlignRight().Column(legendCol =>
{
legendCol.Item().Element(e => e.ShowEntire().Row(subRow =>
{
subRow.AutoItem().Text(text =>
{
text.Span(" ").BackgroundColor("#add8e6").FontSize(9);
text.Span(" Weekend").FontSize(8).FontColor(Colors.Black);
});
}));
legendCol.Item().Element(e => e.ShowEntire().Row(subRow =>
{
subRow.AutoItem().Text(text =>
{
text.Span(" ").BackgroundColor("#ffc0cb").FontSize(9);
text.Span(" Public Holiday").FontSize(8).FontColor(Colors.Black);
});
}));
});
});
column.Item().PaddingVertical(10).LineHorizontal(0.5f).LineColor(Colors.Grey.Lighten2);
column.Item().Element(container => ComposeSimpleTable(container, records, user, showStationColumn, allDatesInMonth, publicHolidaysForUser.Select(h => h.HolidayDate.Date).ToList()));
column.Item().PaddingTop(20).Element(container =>
{
container.ShowEntire().Row(row =>
{
row.RelativeItem().Column(legendCol =>
{
});
row.RelativeItem(2).AlignRight().Column(holidayListCol =>
{
holidayListCol.Item().Element(e => e.ShowEntire().Text("Public Holidays:").FontSize(9).SemiBold());
holidayListCol.Item().Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.RelativeColumn(1);
columns.RelativeColumn(2);
});
table.Header(header =>
{
header.Cell().Border(0.25f).Padding(2).Text("Date").FontSize(7).Bold().AlignCenter();
header.Cell().Border(0.25f).Padding(2).Text("Holiday Name").FontSize(7).Bold().AlignCenter();
});
if (publicHolidaysForUser.Any())
{
foreach (var holiday in publicHolidaysForUser)
{
table.Cell().Border(0.25f).Padding(2).Text($"{holiday.HolidayDate:dd-MM-yyyy}").FontSize(7).AlignCenter();
table.Cell().Border(0.25f).Padding(2).Text(holiday.HolidayName).FontSize(7).AlignLeft();
}
}
else
{
table.Cell().ColumnSpan(2).Border(0.25f).Padding(2)
.Text($"No public holidays found for {userSetting?.State?.StateName ?? "this state"} in {displayMonth:MMMM yyyy}.")
.FontSize(7).Italic().AlignCenter();
}
});
});
});
});
});
});
}).GeneratePdf(stream);
stream.Position = 0;
return stream;
}
private void ComposeSimpleTable(IContainer container, List<OtRegisterModel> records, UserModel user, bool showStationColumn, List<DateTime> allDatesInMonth, List<DateTime> publicHolidays)
{
var recordsGroupedByDate = records
.GroupBy(r => r.OtDate.Date)
.ToDictionary(g => g.Key, g => g.ToList());
var userSetting = _centralDbContext.Hrusersetting
.Include(us => us.State)
.FirstOrDefault(us => us.UserId == user.Id);
container.Table(table =>
{
table.ColumnsDefinition(columns =>
{
columns.RelativeColumn(0.8f); // Day (ddd)
columns.RelativeColumn(1); // Date
// Office Hour group
columns.RelativeColumn(1); // From
columns.RelativeColumn(1); // To
columns.RelativeColumn(0.8f); // Break
// After Office Hour group
columns.RelativeColumn(1); // From
columns.RelativeColumn(1); // To
columns.RelativeColumn(0.8f); // Break
columns.RelativeColumn(1); // Total OT Hours
columns.RelativeColumn(0.8f); // Break (min)
if (showStationColumn)
{
columns.RelativeColumn(1.5f); // Station
}
columns.RelativeColumn(2); // Description
});
// Header
table.Header(header =>
{
header.Cell().RowSpan(2).Background("#d9ead3").Border(0.25f).Padding(3)
.Text("Day").FontSize(6).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#d9ead3").Border(0.25f).Padding(3)
.Text("Date").FontSize(6).Bold().AlignCenter();
header.Cell().ColumnSpan(3).Background("#cfe2f3").Border(0.25f).Padding(3)
.Text("Office Hour").FontSize(6).Bold().AlignCenter();
header.Cell().ColumnSpan(3).Background("#cfe2f3").Border(0.25f).Padding(3)
.Text("After Office Hour").FontSize(6).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3)
.Text("Total OT Hours").FontSize(6).Bold().AlignCenter();
header.Cell().RowSpan(2).Background("#fce5cd").Border(0.25f).Padding(3)
.Text("Break (min)").FontSize(6).Bold().AlignCenter();
if (showStationColumn)
{
header.Cell().RowSpan(2).Background("#d0f0ef").Border(0.25f).Padding(3)
.Text("Station").FontSize(6).Bold().AlignCenter();
}
header.Cell().RowSpan(2).Background("#e3f2fd").Border(0.25f).Padding(3)
.Text("Description").FontSize(6).Bold().AlignCenter();
// Second row of the header (sub-headers)
header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
.Text("From").FontSize(6).Bold().AlignCenter();
header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
.Text("To").FontSize(6).Bold().AlignCenter();
header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
.Text("Break").FontSize(6).Bold().AlignCenter();
header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
.Text("From").FontSize(6).Bold().AlignCenter();
header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
.Text("To").FontSize(6).Bold().AlignCenter();
header.Cell().Background("#cfe2f3").Border(0.25f).Padding(3)
.Text("Break").FontSize(6).Bold().AlignCenter();
});
decimal totalHours = 0;
decimal totalBreak = 0;
bool alternate = false;
DateTime? previousDate = null;
foreach (var date in allDatesInMonth)
{
recordsGroupedByDate.TryGetValue(date, out var dateRecords);
var recordsToShow = dateRecords ?? new List<OtRegisterModel> { new OtRegisterModel { OtDate = date } };
recordsToShow = recordsToShow.OrderBy(r => r.OfficeFrom ?? r.AfterFrom).ToList();
foreach (var record in recordsToShow)
{
var backgroundColor = GetDayCellBackgroundColor(date, userSetting?.State?.WeekendId, publicHolidays);
string rowBg = alternate ? "#f9f9f9" : "#ffffff";
if (dateRecords == null || !dateRecords.Any())
rowBg = alternate ? Colors.Grey.Lighten5 : Colors.White;
void AddCell(string value, bool center = true, string? bg = null)
{
var cell = table.Cell().Background(bg ?? rowBg).Border(0.25f).Padding(2);
var text = cell.Text(value).FontSize(6);
if (center) text.AlignCenter();
}
if (date.Date != previousDate?.Date)
{
AddCell(date.ToString("ddd"), true, backgroundColor);
AddCell(date.ToString("dd-MM-yyyy"), true, backgroundColor);
}
else
{
AddCell("", true, backgroundColor);
AddCell("", true, backgroundColor);
}
previousDate = date;
var officeHours = CalculateOfficeOtHours(record);
var afterHours = CalculateAfterOfficeOtHours(record);
var totalTime = ConvertTimeToDecimal(officeHours) + ConvertTimeToDecimal(afterHours);
var breakTime = (record.OfficeBreak ?? 0) + (record.AfterBreak ?? 0);
totalHours += totalTime;
totalBreak += breakTime;
// Office Hour
AddCell(record.OfficeFrom?.ToString(@"hh\:mm") ?? "");
AddCell(record.OfficeTo?.ToString(@"hh\:mm") ?? "");
AddCell(FormatAsHourMinute(record.OfficeBreak, isMinutes: true));
// After Office Hour
AddCell(record.AfterFrom?.ToString(@"hh\:mm") ?? "");
AddCell(record.AfterTo?.ToString(@"hh\:mm") ?? "");
AddCell(FormatAsHourMinute(record.AfterBreak, isMinutes: true));
// Totals
AddCell(FormatAsHourMinute(totalTime, isMinutes: false));
AddCell(FormatAsHourMinute(breakTime, isMinutes: true));
// Station
if (showStationColumn)
{
AddCell(record.Stations?.StationName ?? "");
}
// Description
table.Cell().Background(rowBg).Border(0.25f).Padding(2)
.Text(record.OtDescription ?? "").FontSize(6).AlignLeft();
alternate = !alternate;
}
}
// Footer with totals
table.Footer(footer =>
{
// TOTAL
footer.Cell().ColumnSpan(2).Background("#d8d1f5").Border(0.80f).Padding(3)
.Text("TOTAL").Bold().FontSize(6).AlignCenter();
footer.Cell().ColumnSpan(6).Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
footer.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text(FormatAsHourMinute(totalHours, isMinutes: false)).Bold().FontSize(6).AlignCenter();
footer.Cell().Background("#d8d1f5").Border(0.80f).Padding(3)
.Text(FormatAsHourMinute(totalBreak, isMinutes: true)).Bold().FontSize(6).AlignCenter();
if (showStationColumn)
{
footer.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
}
footer.Cell().Background("#d8d1f5").Border(0.80f).Padding(3).Text("").FontSize(6).AlignCenter();
});
});
}
private bool IsAdmin(int userId)
{
var userRoles = _centralDbContext.UserRoles
.Where(ur => ur.UserId == userId)
.Join(_centralDbContext.Roles, ur => ur.RoleId, r => r.Id, (ur, r) => r.Name)
.ToList();
return userRoles.Any(role => role.Contains("SuperAdmin") || role.Contains("SystemAdmin"));
}
private string GetMonthYearString(List<OtRegisterModel> records)
{
if (records == null || !records.Any())
return "No Records";
var firstDate = records.First().OtDate;
var lastDate = records.Last().OtDate;
if (firstDate.Month == lastDate.Month && firstDate.Year == lastDate.Year)
return firstDate.ToString("MMMM yyyy");
return $"{firstDate:MMM yyyy} - {lastDate:MMM yyyy}";
}
private static IContainer CellStyle(IContainer container)
{
return container
.Padding(5)
.Border(1)
.BorderColor(QuestPDF.Helpers.Colors.Grey.Lighten2)
.AlignMiddle()
.AlignLeft();
}
private string FormatAsHourMinute(decimal? hoursOrMinutes, bool isMinutes = false)
{
if (hoursOrMinutes == null || hoursOrMinutes == 0)
return "";
TimeSpan ts = isMinutes
? TimeSpan.FromMinutes((double)hoursOrMinutes.Value)
: TimeSpan.FromHours((double)hoursOrMinutes.Value);
int totalHours = (int)(ts.TotalHours);
int minutes = (int)(ts.Minutes);
return $"{totalHours}:{minutes:D2}";
}
private string GetDayType(DateTime date, int? weekendId, List<DateTime> publicHolidays)
{
if (publicHolidays.Contains(date.Date))
{
return "Public Holiday";
}
DayOfWeek dayOfWeek = date.DayOfWeek;
if ((weekendId == 1 && dayOfWeek == DayOfWeek.Saturday) ||
(weekendId == 2 && dayOfWeek == DayOfWeek.Sunday))
{
return "Rest Day";
}
if ((weekendId == 1 && dayOfWeek == DayOfWeek.Friday) ||
(weekendId == 2 && dayOfWeek == DayOfWeek.Saturday))
{
return "Off Day";
}
return "Normal Day";
}
private decimal CalculateOrp(decimal basicSalary)
{
return basicSalary / 26m;
}
private decimal CalculateHrp(decimal orp)
{
return orp / 8m;
}
private decimal ConvertTimeToDecimal(string time)
{
if (string.IsNullOrEmpty(time)) return 0;
var parts = time.Split(':');
if (parts.Length != 2) return 0;
if (int.TryParse(parts[0], out int hours) && int.TryParse(parts[1], out int minutes))
{
return hours + (minutes / 60m);
}
return 0;
}
private string CalculateOfficeOtHours(OtRegisterModel record)
{
if (!record.OfficeFrom.HasValue || !record.OfficeTo.HasValue) return "";
double fromMinutes = record.OfficeFrom.Value.TotalMinutes;
double toMinutes = record.OfficeTo.Value.TotalMinutes;
double totalMinutes = toMinutes - fromMinutes;
if (totalMinutes < 0)
{
totalMinutes += 24 * 60;
}
totalMinutes -= (record.OfficeBreak ?? 0);
totalMinutes = Math.Max(0, totalMinutes);
int hours = (int)(totalMinutes / 60);
int minutes = (int)(totalMinutes % 60);
return $"{hours}:{minutes:D2}";
}
private string CalculateAfterOfficeOtHours(OtRegisterModel record)
{
if (!record.AfterFrom.HasValue || !record.AfterTo.HasValue) return "";
double fromMinutes = record.AfterFrom.Value.TotalMinutes;
double toMinutes = record.AfterTo.Value.TotalMinutes;
double totalMinutes = toMinutes - fromMinutes;
if (totalMinutes < 0)
{
totalMinutes += 24 * 60;
}
totalMinutes -= (record.AfterBreak ?? 0);
totalMinutes = Math.Max(0, totalMinutes);
int hours = (int)(totalMinutes / 60);
int minutes = (int)(totalMinutes % 60);
return $"{hours}:{minutes:D2}";
}
private Dictionary<string, string> ClassifyOt(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
{
var officeRaw = CalculateOfficeOtHours(record);
var afterRaw = CalculateAfterOfficeOtHours(record);
var officeHrs = ConvertTimeToDecimal(officeRaw);
var afterHrs = ConvertTimeToDecimal(afterRaw);
var toFixedOrEmpty = (decimal num) => num > 0 ? num.ToString("N2") : "";
var dayType = GetDayType(record.OtDate, weekendId, publicHolidays);
var result = new Dictionary<string, string>
{
["ndAfter"] = "",
["odUnder4"] = "",
["odBetween4And8"] = "",
["odAfter"] = "",
["rdUnder4"] = "",
["rdBetween4And8"] = "",
["rdAfter"] = "",
["phUnder8"] = "",
["phAfter"] = ""
};
switch (dayType)
{
case "Normal Day":
result["ndAfter"] = toFixedOrEmpty(afterHrs);
break;
case "Off Day":
if (officeHrs > 0) // Only process if there are office hours
{
if (officeHrs <= 4) // If total office hours are 4 or less
{
result["odUnder4"] = toFixedOrEmpty(officeHrs); // Assign all to 'under 4'
}
else if (officeHrs <= 8) // If total office hours are more than 4, but 8 or less
{
result["odBetween4And8"] = toFixedOrEmpty(officeHrs); // Assign all to '4-8'
}
else // If total office hours are more than 8
{
result["odAfter"] = toFixedOrEmpty(officeHrs); // Assign all to 'OD After' (for office hours beyond 8)
}
}
result["odAfter"] = toFixedOrEmpty(ConvertTimeToDecimal(result["odAfter"]) + afterHrs);
break;
case "Rest Day":
if (officeHrs > 0) // Only process if there are office hours
{
if (officeHrs <= 4) // If total office hours are 4 or less
{
result["rdUnder4"] = toFixedOrEmpty(officeHrs); // Assign all to 'under 4'
}
else if (officeHrs <= 8) // If total office hours are more than 4, but 8 or less
{
result["rdBetween4And8"] = toFixedOrEmpty(officeHrs); // Assign all to '4-8'
}
else // If total office hours are more than 8
{
result["rdAfter"] = toFixedOrEmpty(officeHrs); // Assign all to 'RD After' (for office hours beyond 8)
}
}
result["rdAfter"] = toFixedOrEmpty(ConvertTimeToDecimal(result["rdAfter"]) + afterHrs);
break;
case "Public Holiday":
if (officeHrs > 0) // Only process if there are office hours
{
if (officeHrs <= 8) // If total office hours are 8 or less
{
result["phUnder8"] = toFixedOrEmpty(officeHrs); // Assign all to 'under 8'
}
else
{
result["phAfter"] = toFixedOrEmpty(officeHrs); // Assign all to 'PH After' (for office hours beyond 8)
}
}
result["phAfter"] = toFixedOrEmpty(ConvertTimeToDecimal(result["phAfter"]) + afterHrs);
break;
}
return result;
}
private string CalculateTotalOtHrs(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
{
var classified = ClassifyOt(record, hrp, publicHolidays, weekendId);
decimal total = 0;
foreach (var value in classified.Values)
{
if (decimal.TryParse(value, out decimal num))
{
total += num;
}
}
return total > 0 ? total.ToString("N2") : "";
}
private string CalculateNdOdTotal(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
{
var classified = ClassifyOt(record, hrp, publicHolidays, weekendId);
var nd = decimal.TryParse(classified["ndAfter"], out decimal ndVal) ? ndVal : 0;
var od1 = decimal.TryParse(classified["odUnder4"], out decimal od1Val) ? od1Val : 0;
var od2 = decimal.TryParse(classified["odBetween4And8"], out decimal od2Val) ? od2Val : 0;
var od3 = decimal.TryParse(classified["odAfter"], out decimal od3Val) ? od3Val : 0;
var total = nd + od1 + od2 + od3;
return total > 0 ? total.ToString("N2") : "";
}
private string CalculateRdTotal(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
{
var classified = ClassifyOt(record, hrp, publicHolidays, weekendId);
var total =
(decimal.TryParse(classified["rdUnder4"], out decimal rd1) ? rd1 : 0) +
(decimal.TryParse(classified["rdBetween4And8"], out decimal rd2) ? rd2 : 0) +
(decimal.TryParse(classified["rdAfter"], out decimal rd3) ? rd3 : 0);
return total > 0 ? total.ToString("N2") : "";
}
private string CalculatePhTotal(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
{
var classified = ClassifyOt(record, hrp, publicHolidays, weekendId);
var total =
(decimal.TryParse(classified["phUnder8"], out decimal ph1) ? ph1 : 0) +
(decimal.TryParse(classified["phAfter"], out decimal ph2) ? ph2 : 0);
return total > 0 ? total.ToString("N2") : "";
}
private string CalculateOtAmount(OtRegisterModel record, decimal hrp, List<DateTime> publicHolidays, int? weekendId)
{
decimal orp = hrp * 8m;
var dayType = GetDayType(record.OtDate, weekendId, publicHolidays);
var officeRaw = CalculateOfficeOtHours(record);
var afterRaw = CalculateAfterOfficeOtHours(record);
var officeHours = ConvertTimeToDecimal(officeRaw);
var afterOfficeHours = ConvertTimeToDecimal(afterRaw);
decimal amountOffice = 0;
decimal amountAfter = 0;
if (officeHours > 0)
{
if (dayType == "Off Day" || dayType == "Rest Day")
{
if (officeHours <= 4)
{
amountOffice = 0.5m * orp;
}
else if (officeHours > 4 && officeHours <= 8)
{
amountOffice = 1 * orp;
}
}
else if (dayType == "Public Holiday")
{
amountOffice = 2 * orp;
}
}
if (afterOfficeHours > 0)
{
switch (dayType)
{
case "Normal Day":
case "Off Day":
amountAfter = 1.5m * hrp * afterOfficeHours;
break;
case "Rest Day":
amountAfter = 2 * hrp * afterOfficeHours;
break;
case "Public Holiday":
amountAfter = 3 * hrp * afterOfficeHours;
break;
}
}
var totalAmount = amountOffice + amountAfter;
return totalAmount.ToString("N2");
}
private List<DateTime> GetAllDatesInMonth(DateTime month)
{
return Enumerable.Range(1, DateTime.DaysInMonth(month.Year, month.Month))
.Select(day => new DateTime(month.Year, month.Month, day))
.ToList();
}
private string GetDayCellBackgroundColor(DateTime date, int? weekendId, List<DateTime> publicHolidays)
{
if (publicHolidays.Contains(date.Date))
return "#ffc0cb";
var dayOfWeek = date.DayOfWeek;
if ((weekendId == 1 && (dayOfWeek == DayOfWeek.Friday || dayOfWeek == DayOfWeek.Saturday)) ||
(weekendId == 2 && (dayOfWeek == DayOfWeek.Saturday || dayOfWeek == DayOfWeek.Sunday)))
return "#add8e6";
return "#ffffff";
}
}
}