diff --git a/Areas/OTcalculate/Models/OtRegisterModel.cs b/Areas/OTcalculate/Models/OtRegisterModel.cs index ed17e09..c46bfaf 100644 --- a/Areas/OTcalculate/Models/OtRegisterModel.cs +++ b/Areas/OTcalculate/Models/OtRegisterModel.cs @@ -17,9 +17,9 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Models public TimeSpan? OfficeFrom { get; set; } public TimeSpan? OfficeTo { get; set; } public int? OfficeBreak { get; set; } - public TimeSpan? OutsideFrom { get; set; } - public TimeSpan? OutsideTo { get; set; } - public int? OutsideBreak { get; set; } + public TimeSpan? AfterFrom { get; set; } + public TimeSpan? AfterTo { get; set; } + public int? AfterBreak { get; set; } public int? StationId { get; set; } [ForeignKey("StationId")] @@ -27,7 +27,6 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Models public string OtDescription { get; set; } public string OtDays { get; set; } - public string FilePath { get; set; } [Required] public int UserId { get; set; } @@ -35,8 +34,8 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Models // Convert string times to TimeSpan before saving public TimeSpan? GetOfficeFrom() => ParseTimeSpan(OfficeFrom?.ToString()); public TimeSpan? GetOfficeTo() => ParseTimeSpan(OfficeTo?.ToString()); - public TimeSpan? GetOutsideFrom() => ParseTimeSpan(OutsideFrom?.ToString()); - public TimeSpan? GetOutsideTo() => ParseTimeSpan(OutsideTo?.ToString()); + public TimeSpan? GetAfterFrom() => ParseTimeSpan(AfterFrom?.ToString()); + public TimeSpan? GetAfterTo() => ParseTimeSpan(AfterTo?.ToString()); private TimeSpan? ParseTimeSpan(string? time) { diff --git a/Areas/OTcalculate/Models/OvertimeRequestDto.cs b/Areas/OTcalculate/Models/OvertimeRequestDto.cs index df9f54a..109ef5f 100644 --- a/Areas/OTcalculate/Models/OvertimeRequestDto.cs +++ b/Areas/OTcalculate/Models/OvertimeRequestDto.cs @@ -3,17 +3,16 @@ public class OvertimeRequestDto { public DateTime OtDate { get; set; } - public string OfficeFrom { get; set; } - public string OfficeTo { get; set; } + public string? OfficeFrom { get; set; } + public string? OfficeTo { get; set; } public int? OfficeBreak { get; set; } - public string OutsideFrom { get; set; } - public string OutsideTo { get; set; } - public int? OutsideBreak { get; set; } + public string? AfterFrom { get; set; } + public string? AfterTo { get; set; } + public int? AfterBreak { get; set; } public int? StationId { get; set; } public string OtDescription { get; set; } public string OtDays { get; set; } public int UserId { get; set; } - public IFormFile File { get; set; } } diff --git a/Areas/OTcalculate/Services/OvertimePdfService.cs b/Areas/OTcalculate/Services/OvertimePdfService.cs index 97440c0..0eb9241 100644 --- a/Areas/OTcalculate/Services/OvertimePdfService.cs +++ b/Areas/OTcalculate/Services/OvertimePdfService.cs @@ -66,9 +66,9 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services columns.RelativeColumn(0.8f); // Office From columns.RelativeColumn(0.8f); // Office To columns.RelativeColumn(0.8f); // Office Break - columns.RelativeColumn(0.9f); // Outside From - columns.RelativeColumn(0.9f); // Outside To - columns.RelativeColumn(0.9f); // Outside Break + columns.RelativeColumn(0.9f); // After From + columns.RelativeColumn(0.9f); // After To + columns.RelativeColumn(0.9f); // After Break columns.RelativeColumn(); // Total OT columns.RelativeColumn(); // Break Hours columns.RelativeColumn(); // Net OT @@ -90,9 +90,9 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services AddHeaderCell("From\n(Office)", "#dceefb"); AddHeaderCell("To\n(Office)", "#dceefb"); AddHeaderCell("Break\n(Office)", "#dceefb"); - AddHeaderCell("From\n(Outside)", "#edf2f7"); - AddHeaderCell("To\n(Outside)", "#edf2f7"); - AddHeaderCell("Break\n(Outside)", "#edf2f7"); + AddHeaderCell("From\n(After)", "#edf2f7"); + AddHeaderCell("To\n(After)", "#edf2f7"); + AddHeaderCell("Break\n(After)", "#edf2f7"); AddHeaderCell("Total OT\nHours", "#fdebd0"); AddHeaderCell("Break Hours\n(min)", "#fdebd0"); AddHeaderCell("Net OT Hours", "#fdebd0"); @@ -126,7 +126,7 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services foreach (var r in records) { var totalOT = CalculateTotalOT(r); - var totalBreak = (r.OfficeBreak ?? 0) + (r.OutsideBreak ?? 0); + var totalBreak = (r.OfficeBreak ?? 0) + (r.AfterBreak ?? 0); var netOT = totalOT - TimeSpan.FromMinutes(totalBreak); totalOTSum += totalOT.TotalHours; @@ -149,9 +149,9 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services AddCell(FormatTime(r.OfficeFrom)); AddCell(FormatTime(r.OfficeTo)); AddCell($"{r.OfficeBreak ?? 0} min"); - AddCell(FormatTime(r.OutsideFrom)); - AddCell(FormatTime(r.OutsideTo)); - AddCell($"{r.OutsideBreak ?? 0} min"); + AddCell(FormatTime(r.AfterFrom)); + AddCell(FormatTime(r.AfterTo)); + AddCell($"{r.AfterBreak ?? 0} min"); AddCell($"{(int)totalOT.TotalHours} hr {totalOT.Minutes} min"); AddCell($"{totalBreak}"); AddCell($"{netOT.Hours} hr {netOT.Minutes} min"); @@ -194,12 +194,12 @@ namespace PSTW_CentralSystem.Areas.OTcalculate.Services private TimeSpan CalculateTotalOT(OtRegisterModel r) { TimeSpan office = (r.OfficeTo ?? TimeSpan.Zero) - (r.OfficeFrom ?? TimeSpan.Zero); - TimeSpan outside = (r.OutsideTo ?? TimeSpan.Zero) - (r.OutsideFrom ?? TimeSpan.Zero); + TimeSpan after = (r.AfterTo ?? TimeSpan.Zero) - (r.AfterFrom ?? TimeSpan.Zero); - if (outside < TimeSpan.Zero) - outside += TimeSpan.FromHours(24); + if (after < TimeSpan.Zero) + after += TimeSpan.FromHours(24); - return office + outside; + return office + after; } private string FormatTime(TimeSpan? time) diff --git a/Areas/OTcalculate/Views/HodDashboard/OtReview.cshtml b/Areas/OTcalculate/Views/HodDashboard/OtReview.cshtml index 7dd3ab5..6693b41 100644 --- a/Areas/OTcalculate/Views/HodDashboard/OtReview.cshtml +++ b/Areas/OTcalculate/Views/HodDashboard/OtReview.cshtml @@ -15,9 +15,9 @@ {{ formatTime(record.officeFrom) }} {{ formatTime(record.officeTo) }} {{ record.officeBreak }} min - {{ formatTime(record.outsideFrom) }} - {{ formatTime(record.outsideTo) }} - {{ record.outsideBreak }} min + {{ formatTime(record.afterFrom) }} + {{ formatTime(record.afterTo) }} + {{ record.afterBreak }} min {{ formatHourMinute(calcTotalTime(record)) }} {{ calcBreakTotal(record) }} {{ formatHourMinute(calcNetHours(record)) }} @@ -143,10 +143,10 @@ }; }, calcTotalHours(r) { - return this.getTimeDiff(r.officeFrom, r.officeTo) + this.getTimeDiff(r.outsideFrom, r.outsideTo); + return this.getTimeDiff(r.afterFrom, r.officeTo) + this.getTimeDiff(r.afterFrom, r.afterTo); }, calcBreakTotal(r) { - return (r.officeBreak || 0) + (r.outsideBreak || 0); + return (r.officeBreak || 0) + (r.afterBreak || 0); }, calcNetHours(r) { const totalMinutes = (this.calcTotalHours(r) * 60) - this.calcBreakTotal(r); diff --git a/Areas/OTcalculate/Views/Overtime/EditOvertime.cshtml b/Areas/OTcalculate/Views/Overtime/EditOvertime.cshtml index 28d530e..5aac66d 100644 --- a/Areas/OTcalculate/Views/Overtime/EditOvertime.cshtml +++ b/Areas/OTcalculate/Views/Overtime/EditOvertime.cshtml @@ -41,26 +41,26 @@ - -
OUTSIDE OFFICE HOURS
+ +
AFTER OFFICE HOURS
- - From +
- - To +
- +
- -
@@ -113,18 +113,6 @@
-
- - - *upload pdf file only -
-
- - View Existing PDF - -
-
Date - Office
(8:30 - 17:30) - Outside
(17:30 - 8:30) + Office Hour
(8:30 - 17:30) + After Office Hour
(17:30 - 8:30) Total OT Hours Break Hours (min) Net OT Hours Station Days Description - File Action @@ -122,9 +121,9 @@ {{ formatTime(record.officeFrom) }} {{ formatTime(record.officeTo) }} {{ record.officeBreak }} min - {{ formatTime(record.outsideFrom) }} - {{ formatTime(record.outsideTo) }} - {{ record.outsideBreak }} min + {{ formatTime(record.afterFrom) }} + {{ formatTime(record.afterTo) }} + {{ record.afterBreak }} min {{ formatHourMinute(calcTotalTime(record)) }} {{ calcBreakTotal(record) }} {{ formatHourMinute(calcNetHours(record)) }} @@ -135,14 +134,6 @@ {{ record.otDescription }}
- - - - - - - - -
-
OUTSIDE OFFICE HOURS
+
AFTER OFFICE HOURS
- - From +
- - To +
- - Break Hours (Minutes) +
@@ -98,13 +98,6 @@ -
- - - *upload pdf file only -
-
AddOvertimeAsync([FromForm] OvertimeRequestDto request) + public async Task AddOvertimeAsync([FromBody] OvertimeRequestDto request) { - _logger.LogInformation("AddOvertimeAsync called (with file upload)."); + _logger.LogInformation("AddOvertimeAsync called."); if (request == null) { @@ -409,59 +409,35 @@ namespace PSTW_CentralSystem.Controllers.API return BadRequest("User ID is required."); } - // Parse times - TimeSpan? officeFrom = TimeSpan.TryParse(request.OfficeFrom, out var of) ? of : (TimeSpan?)null; - TimeSpan? officeTo = TimeSpan.TryParse(request.OfficeTo, out var ot) ? ot : (TimeSpan?)null; - TimeSpan? outsideFrom = TimeSpan.TryParse(request.OutsideFrom, out var ofr) ? ofr : (TimeSpan?)null; - TimeSpan? outsideTo = TimeSpan.TryParse(request.OutsideTo, out var otr) ? otr : (TimeSpan?)null; + // Parse times (make them optional) + TimeSpan? officeFrom = string.IsNullOrEmpty(request.OfficeFrom) ? (TimeSpan?)null : TimeSpan.Parse(request.OfficeFrom); + TimeSpan? officeTo = string.IsNullOrEmpty(request.OfficeTo) ? (TimeSpan?)null : TimeSpan.Parse(request.OfficeTo); + TimeSpan? afterFrom = string.IsNullOrEmpty(request.AfterFrom) ? (TimeSpan?)null : TimeSpan.Parse(request.AfterFrom); + TimeSpan? afterTo = string.IsNullOrEmpty(request.AfterTo) ? (TimeSpan?)null : TimeSpan.Parse(request.AfterTo); + // Office time validation: if officeFrom is set, officeTo must be set too, and vice versa if ((officeFrom != null && officeTo == null) || (officeFrom == null && officeTo != null)) { return BadRequest("Both Office From and To must be filled if one is provided."); } - if ((outsideFrom != null && outsideTo == null) || (outsideFrom == null && outsideTo != null)) - { - return BadRequest("Both Outside From and To must be filled if one is provided."); - } + // No need for specific validation for AfterFrom and AfterTo being both present + // If one is null and the other isn't, that's acceptable now. - // Save file - string pdfPath = null; - if (request.File != null && request.File.Length > 0) - { - var uploadsFolder = Path.Combine(_env.WebRootPath, "Media", "Overtime"); - - if (!Directory.Exists(uploadsFolder)) - Directory.CreateDirectory(uploadsFolder); - - var fileName = $"OT_{Guid.NewGuid()}{Path.GetExtension(request.File.FileName)}"; - var filePath = Path.Combine(uploadsFolder, fileName); - - using (var stream = new FileStream(filePath, FileMode.Create)) - { - await request.File.CopyToAsync(stream); - } - - // This is the relative public URL path - pdfPath = $"/media/overtime/{fileName}"; - } - - - // Map to DB model + // Map to DB model (continue using null for optional fields) var newRecord = new OtRegisterModel { OtDate = request.OtDate, OfficeFrom = officeFrom, OfficeTo = officeTo, - OfficeBreak = request.OfficeBreak, - OutsideFrom = outsideFrom, - OutsideTo = outsideTo, - OutsideBreak = request.OutsideBreak, + OfficeBreak = request.OfficeBreak ?? null, // Make OfficeBreak optional + AfterFrom = afterFrom, + AfterTo = afterTo, + AfterBreak = request.AfterBreak ?? null, // Make AfterBreak optional StationId = request.StationId, OtDescription = request.OtDescription, OtDays = request.OtDays, UserId = request.UserId, - FilePath = pdfPath }; _centralDbContext.Otregisters.Add(newRecord); @@ -475,8 +451,6 @@ namespace PSTW_CentralSystem.Controllers.API return StatusCode(500, "An error occurred while saving overtime."); } } - - #endregion #region Ot Records @@ -494,14 +468,13 @@ namespace PSTW_CentralSystem.Controllers.API o.OfficeFrom, o.OfficeTo, o.OfficeBreak, - o.OutsideFrom, - o.OutsideTo, - o.OutsideBreak, + o.AfterFrom, + o.AfterTo, + o.AfterBreak, o.StationId, StationName = o.Stations != null ? o.Stations.StationName : "N/A", o.OtDescription, o.OtDays, - o.FilePath, o.UserId }) .OrderByDescending(o => o.OtDate) @@ -528,22 +501,7 @@ namespace PSTW_CentralSystem.Controllers.API return NotFound("Overtime record not found."); } - // 1. Delete the file from the server - if (!string.IsNullOrEmpty(record.FilePath)) - { - var filePath = Path.Combine(_env.WebRootPath, record.FilePath.TrimStart('/')); // Construct full path - if (System.IO.File.Exists(filePath)) - { - System.IO.File.Delete(filePath); - _logger.LogInformation("File deleted successfully: {FilePath}", filePath); - } - else - { - _logger.LogWarning("File not found, could not delete: {FilePath}", filePath); - } - } - - // 2. Delete the record from the database + // Delete the record from the database (No file handling anymore) _centralDbContext.Otregisters.Remove(record); _centralDbContext.SaveChanges(); @@ -557,48 +515,6 @@ namespace PSTW_CentralSystem.Controllers.API } } - [HttpPost("SaveOvertimeRecordsWithPdf")] - public async Task SaveOvertimeRecordsWithPdf([FromBody] List records) - { - if (!ModelState.IsValid) - { - return BadRequest(ModelState); - } - - try - { - _logger.LogInformation("SaveOvertimeRecordsWithPdf called with {RecordCount} records", records.Count); - - foreach (var record in records) - { - _logger.LogDebug("Processing record with OvertimeId: {OvertimeId}", record.OvertimeId); - - var existingRecord = await _centralDbContext.Otregisters.FindAsync(record.OvertimeId); - - if (existingRecord != null) - { - _logger.LogDebug("Updating existing record with OvertimeId: {OvertimeId}", record.OvertimeId); - existingRecord.FilePath = record.FilePath; - _centralDbContext.Otregisters.Update(existingRecord); - } - else - { - _logger.LogWarning("Record with OvertimeId: {OvertimeId} not found, adding new", record.OvertimeId); - _centralDbContext.Otregisters.Add(record); - } - } - - await _centralDbContext.SaveChangesAsync(); - _logger.LogInformation("Successfully saved {RecordCount} overtime records with PDFs", records.Count); - return Ok("Overtime records updated with PDFs."); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error saving overtime records with PDFs"); - return StatusCode(500, "An error occurred while saving records."); - } - } - [HttpGet("GenerateOvertimePdf")] public IActionResult GenerateOvertimePdf(int month, int year) { @@ -653,7 +569,7 @@ namespace PSTW_CentralSystem.Controllers.API [HttpPost] [Route("UpdateOvertimeRecord")] - public async Task UpdateOvertimeRecord([FromForm] OtRegisterModel model, IFormFile? newFile) + public IActionResult UpdateOvertimeRecord([FromForm] OtRegisterModel model) { _logger.LogInformation("UpdateOvertimeRecord called. Model: {@Model}", model); @@ -674,33 +590,13 @@ namespace PSTW_CentralSystem.Controllers.API _logger.LogInformation("Existing record found: {@ExistingRecord}", existing); - string? oldFilePath = existing.FilePath; // Store the old file path - - string? newPdfPath = null; // Initialize the new file path - - // Handle new file upload - if (newFile != null && newFile.Length > 0) - { - var fileName = $"OT_{Guid.NewGuid()}{Path.GetExtension(newFile.FileName)}"; - var savePath = Path.Combine(_env.WebRootPath, "media", "Overtime", fileName); - newPdfPath = $"/media/Overtime/{fileName}"; - - using (var stream = new FileStream(savePath, FileMode.Create)) - { - await newFile.CopyToAsync(stream); - } - - existing.FilePath = newPdfPath; // Update the file path in the database - } - - // Update other fields existing.OtDate = model.OtDate; existing.OfficeFrom = model.OfficeFrom; existing.OfficeTo = model.OfficeTo; existing.OfficeBreak = model.OfficeBreak; - existing.OutsideFrom = model.OutsideFrom; - existing.OutsideTo = model.OutsideTo; - existing.OutsideBreak = model.OutsideBreak; + existing.AfterFrom = model.AfterFrom; + existing.AfterTo = model.AfterTo; + existing.AfterBreak = model.AfterBreak; existing.StationId = model.StationId; existing.OtDescription = model.OtDescription; existing.OtDays = model.OtDays; @@ -709,21 +605,6 @@ namespace PSTW_CentralSystem.Controllers.API _centralDbContext.SaveChanges(); _logger.LogInformation("Overtime record updated successfully for Id: {OvertimeId}", model.OvertimeId); - // Delete the old file after saving the new one (if a new file was uploaded) - if (newFile != null && !string.IsNullOrEmpty(oldFilePath)) - { - var fullOldFilePath = Path.Combine(_env.WebRootPath, oldFilePath.TrimStart('/')); - if (System.IO.File.Exists(fullOldFilePath)) - { - System.IO.File.Delete(fullOldFilePath); - _logger.LogInformation("Old file deleted successfully: {OldFilePath}", fullOldFilePath); - } - else - { - _logger.LogWarning("Old file not found, could not delete: {OldFilePath}", fullOldFilePath); - } - } - return Ok(new { message = "Record updated successfully." }); } catch (Exception ex) diff --git a/wwwroot/Media/Overtime/OT_1c49d312-a22e-4ac2-9c45-d3d57a917eed.pdf b/wwwroot/Media/Overtime/OT_1c49d312-a22e-4ac2-9c45-d3d57a917eed.pdf new file mode 100644 index 0000000..866fe3b Binary files /dev/null and b/wwwroot/Media/Overtime/OT_1c49d312-a22e-4ac2-9c45-d3d57a917eed.pdf differ diff --git a/wwwroot/Media/Overtime/OT_525ffef0-da41-463a-bd4b-05556272c6cc.pdf b/wwwroot/Media/Overtime/OT_525ffef0-da41-463a-bd4b-05556272c6cc.pdf new file mode 100644 index 0000000..866fe3b Binary files /dev/null and b/wwwroot/Media/Overtime/OT_525ffef0-da41-463a-bd4b-05556272c6cc.pdf differ