1059 lines
38 KiB
C#
1059 lines
38 KiB
C#
using Azure.Core;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Mono.TextTemplating;
|
|
using Newtonsoft.Json;
|
|
using PSTW_CentralSystem.Areas.OTcalculate.Models;
|
|
using PSTW_CentralSystem.Controllers.API;
|
|
using PSTW_CentralSystem.Controllers.API.Inventory;
|
|
using PSTW_CentralSystem.DBContext;
|
|
using PSTW_CentralSystem.Models;
|
|
using System.ComponentModel.Design;
|
|
using System.Data;
|
|
using System;
|
|
using System.Threading.Tasks;
|
|
using System.Diagnostics;
|
|
using System.Reflection;
|
|
using static System.Collections.Specialized.BitVector32;
|
|
using System.Security.Claims;
|
|
using Microsoft.VisualStudio.Web.CodeGenerators.Mvc.Templates.BlazorIdentity.Pages;
|
|
using Microsoft.AspNetCore.Mvc.Rendering;
|
|
using QuestPDF.Fluent;
|
|
using QuestPDF.Helpers;
|
|
using QuestPDF.Infrastructure;
|
|
using PSTW_CentralSystem.Areas.OTcalculate.Services;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
|
|
|
|
namespace PSTW_CentralSystem.Controllers.API
|
|
{
|
|
[ApiController]
|
|
[Route("[controller]")]
|
|
public class OvertimeAPI : Controller
|
|
{
|
|
private readonly ILogger<OvertimeAPI> _logger;
|
|
private readonly CentralSystemContext _centralDbContext;
|
|
private readonly UserManager<UserModel> _userManager;
|
|
private readonly OvertimePdfService _pdfService;
|
|
private readonly IWebHostEnvironment _env;
|
|
private readonly OvertimeExcelService _excelService;
|
|
|
|
public OvertimeAPI(ILogger<OvertimeAPI> logger, CentralSystemContext centralDbContext, UserManager<UserModel> userManager, OvertimePdfService pdfService, IWebHostEnvironment env, OvertimeExcelService excelService)
|
|
{
|
|
_logger = logger;
|
|
_centralDbContext = centralDbContext;
|
|
_userManager = userManager;
|
|
_pdfService = pdfService;
|
|
_env = env;
|
|
_excelService = excelService;
|
|
}
|
|
|
|
#region Settings
|
|
[HttpGet("GetUpdateDates")]
|
|
public IActionResult GetUpdateDates()
|
|
{
|
|
try
|
|
{
|
|
|
|
var latestRateUpdate = _centralDbContext.Rates.OrderByDescending(r => r.LastUpdated).FirstOrDefault()?.LastUpdated;
|
|
var latestCalendarUpdate = _centralDbContext.Holidays.OrderByDescending(c => c.LastUpdated).FirstOrDefault()?.LastUpdated;
|
|
var latestFlexiHourUpdate = _centralDbContext.Hrusersetting.OrderByDescending(r => r.FlexiHourUpdate).FirstOrDefault()?.FlexiHourUpdate;
|
|
var latestRegionUpdate = _centralDbContext.Hrusersetting.OrderByDescending(c => c.StateUpdate).FirstOrDefault()?.StateUpdate;
|
|
|
|
var updateDates = new
|
|
{
|
|
rateUpdateDate = latestRateUpdate.HasValue ? latestRateUpdate.Value.ToString("dd MMMM yyyy") : null,
|
|
calendarUpdateDate = latestCalendarUpdate.HasValue ? latestCalendarUpdate.Value.ToString("dd MMMM yyyy") : null,
|
|
flexiHourUpdateDate = latestFlexiHourUpdate.HasValue ? latestFlexiHourUpdate.Value.ToString("dd MMMM yyyy") : null,
|
|
regionUpdateDate = latestRegionUpdate.HasValue ? latestRegionUpdate.Value.ToString("dd MMMM yyyy") : null
|
|
};
|
|
|
|
return Json(updateDates);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Rate
|
|
[HttpPost("UpdateRates")]
|
|
public async Task<IActionResult> UpdateRate([FromBody] List<RateModel> rates)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
{
|
|
return BadRequest(ModelState);
|
|
}
|
|
|
|
try
|
|
{
|
|
foreach (var rate in rates)
|
|
{
|
|
var existingRate = await _centralDbContext.Rates
|
|
.FirstOrDefaultAsync(r => r.UserId == rate.UserId);
|
|
|
|
if (existingRate != null)
|
|
{
|
|
existingRate.RateValue = rate.RateValue;
|
|
existingRate.LastUpdated = DateTime.Now;
|
|
_centralDbContext.Rates.Update(existingRate);
|
|
}
|
|
else
|
|
{
|
|
_centralDbContext.Rates.Add(new RateModel
|
|
{
|
|
UserId = rate.UserId,
|
|
RateValue = rate.RateValue,
|
|
LastUpdated = DateTime.Now
|
|
});
|
|
}
|
|
}
|
|
|
|
await _centralDbContext.SaveChangesAsync();
|
|
|
|
var updatedRates = await _centralDbContext.Rates
|
|
.Include(r => r.Users)
|
|
.Select(r => new
|
|
{
|
|
r.RateId,
|
|
r.RateValue,
|
|
r.UserId,
|
|
FullName = r.Users.FullName,
|
|
DepartmentName = r.Users.Department.DepartmentName
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Json(updatedRates);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpPost("GetUserRates")]
|
|
public async Task<IActionResult> GetUserRates()
|
|
{
|
|
try
|
|
{
|
|
var userRates = await _centralDbContext.Rates
|
|
.Include(rates => rates.Users)
|
|
.ThenInclude(user => user.Department)
|
|
.Select(rates => new
|
|
{
|
|
rates.RateId,
|
|
rates.RateValue,
|
|
rates.UserId,
|
|
rates.Users.FullName,
|
|
rates.Users.Department.DepartmentName
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Json(userRates);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region FlexiHour State
|
|
private async Task UpdateOrInsertUserSettingAsync(int userId, int? flexiHourId = null, int? stateId = null)
|
|
{
|
|
var setting = await _centralDbContext.Hrusersetting
|
|
.FirstOrDefaultAsync(h => h.UserId == userId);
|
|
|
|
if (setting != null)
|
|
{
|
|
if (flexiHourId.HasValue)
|
|
{
|
|
setting.FlexiHourId = flexiHourId;
|
|
setting.FlexiHourUpdate = DateTime.Now;
|
|
}
|
|
|
|
if (stateId.HasValue)
|
|
{
|
|
setting.StateId = stateId;
|
|
setting.StateUpdate = DateTime.Now;
|
|
}
|
|
|
|
_centralDbContext.Hrusersetting.Update(setting);
|
|
}
|
|
else
|
|
{
|
|
var newSetting = new HrUserSettingModel
|
|
{
|
|
UserId = userId,
|
|
FlexiHourId = flexiHourId,
|
|
FlexiHourUpdate = flexiHourId.HasValue ? DateTime.Now : null,
|
|
StateId = stateId,
|
|
StateUpdate = stateId.HasValue ? DateTime.Now : null
|
|
};
|
|
_centralDbContext.Hrusersetting.Add(newSetting);
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region FlexiHour
|
|
[HttpGet("GetFlexiHours")]
|
|
public IActionResult GetAllFlexiHours()
|
|
{
|
|
var flexiHours = _centralDbContext.Flexihour
|
|
.Select(f => new { f.FlexiHourId, f.FlexiHour })
|
|
.ToList();
|
|
return Ok(flexiHours);
|
|
}
|
|
|
|
[HttpGet("GetUserFlexiHours")]
|
|
public async Task<IActionResult> GetUserFlexiHours()
|
|
{
|
|
try
|
|
{
|
|
var users = await _centralDbContext.Users
|
|
.Include(u => u.Department)
|
|
.ToListAsync();
|
|
|
|
var hrUserSettings = await _centralDbContext.Hrusersetting
|
|
.Include(hr => hr.FlexiHour)
|
|
.ToListAsync();
|
|
|
|
var result = users.Select(u => new
|
|
{
|
|
UserId = u.Id,
|
|
FullName = u.FullName,
|
|
DepartmentName = u.Department != null ? u.Department.DepartmentName : "N/A",
|
|
FlexiHour = hrUserSettings
|
|
.Where(hr => hr.UserId == u.Id)
|
|
.Select(hr => hr.FlexiHour != null ? hr.FlexiHour.FlexiHour : "N/A")
|
|
.FirstOrDefault() ?? "N/A",
|
|
State = hrUserSettings
|
|
.Where(hr => hr.UserId == u.Id)
|
|
.Select(hr => hr.State != null ? hr.State.StateName : "N/A")
|
|
.FirstOrDefault() ?? "N/A"
|
|
}).ToList();
|
|
|
|
// Log this data to inspect the response
|
|
Console.WriteLine(JsonConvert.SerializeObject(result)); // Debugging log
|
|
return Ok(result);
|
|
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
|
|
[HttpPost("UpdateUserFlexiHours")]
|
|
public async Task<IActionResult> UpdateUserFlexiHours([FromBody] List<HrUserSettingModel> updates)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
return BadRequest(ModelState);
|
|
|
|
try
|
|
{
|
|
foreach (var update in updates)
|
|
{
|
|
await UpdateOrInsertUserSettingAsync(update.UserId, flexiHourId: update.FlexiHourId);
|
|
}
|
|
|
|
await _centralDbContext.SaveChangesAsync();
|
|
return Ok();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region State
|
|
[HttpGet("GetUserStates")]
|
|
public async Task<IActionResult> GetUserStates()
|
|
{
|
|
try
|
|
{
|
|
var users = await _centralDbContext.Users
|
|
.Include(u => u.Department)
|
|
.ToListAsync();
|
|
|
|
var hrUserSettings = await _centralDbContext.Hrusersetting
|
|
.Include(h => h.State)
|
|
.ToListAsync();
|
|
|
|
var result = users.Select(u =>
|
|
{
|
|
var hrSetting = hrUserSettings.FirstOrDefault(h => h.UserId == u.Id);
|
|
return new
|
|
{
|
|
u.Id,
|
|
u.FullName,
|
|
DepartmentName = u.Department != null ? u.Department.DepartmentName : "N/A",
|
|
State = hrSetting != null && hrSetting.State != null ? hrSetting.State.StateName : "N/A"
|
|
};
|
|
}).ToList();
|
|
|
|
return Ok(result);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return StatusCode(500, ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpPost("UpdateUserStates")]
|
|
public async Task<IActionResult> UpdateUserStates([FromBody] List<HrUserSettingModel> updates)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
return BadRequest(ModelState);
|
|
|
|
try
|
|
{
|
|
foreach (var update in updates)
|
|
{
|
|
await UpdateOrInsertUserSettingAsync(update.UserId, stateId: update.StateId);
|
|
|
|
}
|
|
|
|
await _centralDbContext.SaveChangesAsync();
|
|
return Ok();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(new { message = ex.Message });
|
|
}
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Calendar
|
|
[HttpGet("GetStatesName")]
|
|
public async Task<IActionResult> GetStatesName()
|
|
{
|
|
try
|
|
{
|
|
var states = await _centralDbContext.States
|
|
.Select(s => new
|
|
{
|
|
s.StateId,
|
|
s.StateName
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Json(states);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
|
|
[HttpPost("UpdateHoliday")]
|
|
public async Task<IActionResult> UpdateHoliday([FromBody] List<CalendarModel> holidays)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
{
|
|
return BadRequest(ModelState);
|
|
}
|
|
|
|
try
|
|
{
|
|
foreach (var calendar in holidays)
|
|
{
|
|
var existingCalendar = await _centralDbContext.Holidays
|
|
.FirstOrDefaultAsync(h => h.StateId == calendar.StateId && h.HolidayDate == calendar.HolidayDate);
|
|
|
|
if (existingCalendar != null)
|
|
{
|
|
existingCalendar.HolidayName = calendar.HolidayName;
|
|
existingCalendar.LastUpdated = DateTime.Now;
|
|
_centralDbContext.Holidays.Update(existingCalendar);
|
|
}
|
|
else
|
|
{
|
|
_centralDbContext.Holidays.Add(new CalendarModel
|
|
{
|
|
HolidayName = calendar.HolidayName,
|
|
HolidayDate = calendar.HolidayDate,
|
|
StateId = calendar.StateId,
|
|
LastUpdated = DateTime.Now
|
|
});
|
|
}
|
|
}
|
|
|
|
await _centralDbContext.SaveChangesAsync();
|
|
|
|
var updatedHoliday = await _centralDbContext.Holidays
|
|
.Include(h => h.States)
|
|
.Select(h => new
|
|
{
|
|
h.HolidayId,
|
|
h.HolidayName,
|
|
h.HolidayDate,
|
|
h.StateId,
|
|
StateName = h.States.StateName
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Json(updatedHoliday);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpGet("GetAllHolidays")]
|
|
public IActionResult GetAllHolidays()
|
|
{
|
|
var holidays = _centralDbContext.Holidays.ToList();
|
|
return Ok(holidays);
|
|
}
|
|
|
|
[HttpDelete("DeleteHoliday/{id}")]
|
|
public async Task<IActionResult> DeleteHoliday(int id)
|
|
{
|
|
try
|
|
{
|
|
var holiday = await _centralDbContext.Holidays.FindAsync(id);
|
|
if (holiday == null)
|
|
{
|
|
return NotFound("Holiday not found.");
|
|
}
|
|
|
|
_centralDbContext.Holidays.Remove(holiday);
|
|
await _centralDbContext.SaveChangesAsync();
|
|
|
|
return Ok(new { message = "Holiday deleted successfully." });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Weekend
|
|
[HttpGet("GetWeekendDay")]
|
|
public async Task<IActionResult> GetWeekendDay()
|
|
{
|
|
try
|
|
{
|
|
var weekends = await _centralDbContext.Weekends
|
|
.Select(w => new
|
|
{
|
|
w.WeekendId,
|
|
w.Day
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Json(weekends);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpPost("UpdateWeekend")]
|
|
public async Task<IActionResult> UpdateWeekend([FromBody] List<StateModel> states)
|
|
{
|
|
if (!ModelState.IsValid)
|
|
{
|
|
return BadRequest(ModelState);
|
|
}
|
|
|
|
try
|
|
{
|
|
foreach (var state in states)
|
|
{
|
|
var existingState = await _centralDbContext.States
|
|
.FirstOrDefaultAsync(s => s.StateId == state.StateId);
|
|
|
|
if (existingState != null)
|
|
{
|
|
// Corrected: Updating WeekendId
|
|
existingState.WeekendId = state.WeekendId;
|
|
_centralDbContext.States.Update(existingState);
|
|
}
|
|
else
|
|
{
|
|
// Ensure new states are added correctly
|
|
_centralDbContext.States.Add(new StateModel
|
|
{
|
|
StateId = state.StateId,
|
|
StateName = state.StateName,
|
|
WeekendId = state.WeekendId
|
|
});
|
|
}
|
|
}
|
|
|
|
await _centralDbContext.SaveChangesAsync();
|
|
|
|
var updatedWeekend = await _centralDbContext.States
|
|
.Include(w => w.Weekends)
|
|
.Select(w => new
|
|
{
|
|
w.StateId,
|
|
w.StateName,
|
|
w.WeekendId,
|
|
Day = w.Weekends.Day
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Json(updatedWeekend);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
|
|
[HttpGet("GetAllWeekends")]
|
|
public IActionResult GetAllWeekends()
|
|
{
|
|
var weekends = _centralDbContext.Weekends.ToList();
|
|
return Ok(weekends);
|
|
}
|
|
|
|
[HttpGet("GetStateWeekends")]
|
|
public async Task<IActionResult> GetStateWeekends()
|
|
{
|
|
try
|
|
{
|
|
var stateWeekends = await _centralDbContext.States
|
|
.Include(s => s.Weekends)
|
|
.Where(s => s.WeekendId != null)
|
|
.Select(s => new
|
|
{
|
|
s.StateId,
|
|
s.StateName,
|
|
Day = s.Weekends.Day
|
|
})
|
|
.ToListAsync();
|
|
|
|
return Json(stateWeekends);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region OtRegister
|
|
[HttpGet("GetStationsByDepartment")]
|
|
public IActionResult GetStationsByDepartment()
|
|
{
|
|
var stations = _centralDbContext.Stations
|
|
.Where(s => s.DepartmentId == 2)
|
|
.Select(s => new
|
|
{
|
|
s.StationId,
|
|
StationName = s.StationName ?? "Unnamed Station"
|
|
})
|
|
.ToList();
|
|
|
|
return Ok(stations);
|
|
}
|
|
|
|
|
|
[HttpPost("AddOvertime")]
|
|
public async Task<IActionResult> AddOvertimeAsync([FromBody] OvertimeRequestDto request)
|
|
{
|
|
_logger.LogInformation("AddOvertimeAsync called.");
|
|
|
|
if (request == null)
|
|
{
|
|
_logger.LogError("Request is null.");
|
|
return BadRequest("Invalid data.");
|
|
}
|
|
|
|
try
|
|
{
|
|
if (request.UserId == 0)
|
|
{
|
|
_logger.LogWarning("No user ID provided.");
|
|
return BadRequest("User ID is required.");
|
|
}
|
|
|
|
// 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.");
|
|
}
|
|
|
|
// 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.
|
|
|
|
// Map to DB model (continue using null for optional fields)
|
|
var newRecord = new OtRegisterModel
|
|
{
|
|
OtDate = request.OtDate,
|
|
OfficeFrom = officeFrom,
|
|
OfficeTo = officeTo,
|
|
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,
|
|
};
|
|
|
|
_centralDbContext.Otregisters.Add(newRecord);
|
|
await _centralDbContext.SaveChangesAsync();
|
|
|
|
return Ok(new { message = "Overtime registered successfully." });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error registering overtime.");
|
|
return StatusCode(500, "An error occurred while saving overtime.");
|
|
}
|
|
}
|
|
|
|
[HttpGet("GetUserStateAndHolidays/{userId}")]
|
|
public async Task<IActionResult> GetUserStateAndHolidaysAsync(int userId)
|
|
{
|
|
try
|
|
{
|
|
var hrSettings = await _centralDbContext.Hrusersetting
|
|
.Include(h => h.State)
|
|
.ThenInclude(s => s.Weekends)
|
|
.Where(h => h.UserId == userId)
|
|
.FirstOrDefaultAsync();
|
|
|
|
if (hrSettings?.State == null)
|
|
{
|
|
return Ok(new { state = (object)null, publicHolidays = new List<object>() }); // Or handle no state differently
|
|
}
|
|
|
|
// Fetch public holidays for the user's state and the current year (example)
|
|
var publicHolidays = await _centralDbContext.Holidays
|
|
.Where(ph => ph.StateId == hrSettings.StateId && ph.HolidayDate.Year == DateTime.Now.Year)
|
|
.Select(ph => new { Date = ph.HolidayDate.ToString("yyyy-MM-dd") })
|
|
.ToListAsync();
|
|
|
|
return Ok(new
|
|
{
|
|
state = new
|
|
{
|
|
stateId = hrSettings.StateId,
|
|
stateName = hrSettings.State?.StateName,
|
|
weekendDay = hrSettings.State?.Weekends?.Day,
|
|
weekendId = hrSettings.State?.WeekendId
|
|
},
|
|
publicHolidays
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error fetching user state and public holidays.");
|
|
return StatusCode(500, "An error occurred while fetching user state and public holidays.");
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Ot Records
|
|
|
|
[HttpGet("GetUserOvertimeRecords/{userId}")]
|
|
public IActionResult GetUserOvertimeRecords(int userId)
|
|
{
|
|
try
|
|
{
|
|
var records = _centralDbContext.Otregisters
|
|
.Where(o => o.UserId == userId)
|
|
.OrderByDescending(o => o.OtDate)
|
|
.Select(o => new
|
|
{
|
|
o.OvertimeId,
|
|
o.OtDate,
|
|
o.OfficeFrom,
|
|
o.OfficeTo,
|
|
o.OfficeBreak,
|
|
o.AfterFrom,
|
|
o.AfterTo,
|
|
o.AfterBreak,
|
|
o.StationId,
|
|
StationName = o.Stations != null ? o.Stations.StationName : "N/A",
|
|
o.OtDescription,
|
|
o.OtDays,
|
|
o.UserId
|
|
})
|
|
.ToList();
|
|
|
|
return Ok(records);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to fetch OT records.");
|
|
return StatusCode(500, "Error retrieving OT records.");
|
|
}
|
|
}
|
|
|
|
[HttpDelete("DeleteOvertimeRecord/{id}")]
|
|
public IActionResult DeleteOvertimeRecord(int id)
|
|
{
|
|
try
|
|
{
|
|
var record = _centralDbContext.Otregisters.FirstOrDefault(o => o.OvertimeId == id);
|
|
if (record == null)
|
|
{
|
|
_logger.LogWarning("Overtime record not found for Id: {OvertimeId}", id);
|
|
return NotFound("Overtime record not found.");
|
|
}
|
|
|
|
_centralDbContext.Otregisters.Remove(record);
|
|
_centralDbContext.SaveChanges();
|
|
|
|
_logger.LogInformation("Overtime record deleted successfully for Id: {OvertimeId}", id);
|
|
return Ok(new { message = "Record deleted successfully." });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to delete OT record.");
|
|
return StatusCode(500, "Error deleting OT record.");
|
|
}
|
|
}
|
|
|
|
[HttpGet("GenerateOvertimePdf")]
|
|
public IActionResult GenerateOvertimePdf(int month, int year)
|
|
{
|
|
var userIdStr = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userIdStr) || !int.TryParse(userIdStr, out int userId))
|
|
return Unauthorized();
|
|
|
|
var user = _centralDbContext.Users
|
|
.Include(u => u.Department)
|
|
.FirstOrDefault(u => u.Id == userId);
|
|
|
|
if (user == null)
|
|
return NotFound("User not found.");
|
|
|
|
var fullName = user.FullName;
|
|
var departmentId = user.departmentId ?? 0;
|
|
var departmentName = user.Department?.DepartmentName ?? "N/A";
|
|
|
|
var records = _centralDbContext.Otregisters
|
|
.Include(o => o.Stations)
|
|
.Where(o => o.UserId == userId && o.OtDate.Month == month && o.OtDate.Year == year)
|
|
.ToList();
|
|
|
|
var hrUserSetting = _centralDbContext.Hrusersetting.FirstOrDefault(h => h.UserId == userId);
|
|
|
|
// StateId
|
|
var userStateId = hrUserSetting?.StateId ?? 0;
|
|
|
|
// WeekendId
|
|
var weekendId = _centralDbContext.States
|
|
.Where(s => s.StateId == userStateId)
|
|
.Select(s => s.WeekendId)
|
|
.FirstOrDefault() ?? 2; // Default Sat-Sun if null
|
|
|
|
// Public Holidays
|
|
var publicHolidays = _centralDbContext.Holidays
|
|
.Where(c => c.StateId == userStateId)
|
|
.ToList();
|
|
|
|
// Step 1: Generate all days of the month
|
|
var daysInMonth = DateTime.DaysInMonth(year, month);
|
|
var allDays = Enumerable.Range(1, daysInMonth)
|
|
.Select(day => new DateTime(year, month, day))
|
|
.ToList();
|
|
|
|
// Step 2: Merge records with missing days
|
|
var mergedRecords = new List<OtRegisterModel>();
|
|
|
|
foreach (var date in allDays)
|
|
{
|
|
var dayRecords = records
|
|
.Where(r => r.OtDate.Date == date.Date)
|
|
.OrderBy(r => r.OfficeFrom)
|
|
.ToList();
|
|
|
|
if (dayRecords.Any())
|
|
{
|
|
mergedRecords.AddRange(dayRecords);
|
|
}
|
|
else
|
|
{
|
|
mergedRecords.Add(new OtRegisterModel
|
|
{
|
|
OtDate = date,
|
|
OtDays = date.DayOfWeek.ToString(),
|
|
OtDescription = "",
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
byte[]? logoImage = null;
|
|
var logoPath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images", "logo.jpg");
|
|
|
|
logoImage = System.IO.File.Exists(logoPath) ? System.IO.File.ReadAllBytes(logoPath) : null;
|
|
|
|
var stream = _pdfService.GenerateOvertimeTablePdf(
|
|
mergedRecords,
|
|
departmentId,
|
|
fullName,
|
|
departmentName,
|
|
userStateId,
|
|
weekendId,
|
|
publicHolidays,
|
|
isAdminUser: IsAdmin(userId),
|
|
logoImage
|
|
);
|
|
|
|
|
|
return File(stream, "application/pdf", $"OvertimeRecords_{year}_{month}.pdf");
|
|
}
|
|
|
|
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"));
|
|
}
|
|
|
|
[HttpGet("GenerateOvertimeExcel")]
|
|
public IActionResult GenerateOvertimeExcel(int month, int year)
|
|
{
|
|
var userIdStr = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userIdStr) || !int.TryParse(userIdStr, out int userId))
|
|
return Unauthorized();
|
|
|
|
var user = _centralDbContext.Users
|
|
.Include(u => u.Department)
|
|
.FirstOrDefault(u => u.Id == userId);
|
|
|
|
if (user == null)
|
|
return NotFound("User not found.");
|
|
|
|
var fullName = user.FullName;
|
|
var departmentId = user.departmentId ?? 0;
|
|
var departmentName = user.Department?.DepartmentName ?? "N/A";
|
|
|
|
var records = _centralDbContext.Otregisters
|
|
.Include(o => o.Stations)
|
|
.Where(o => o.UserId == userId && o.OtDate.Month == month && o.OtDate.Year == year)
|
|
.ToList();
|
|
|
|
var hrUserSetting = _centralDbContext.Hrusersetting.FirstOrDefault(h => h.UserId == userId);
|
|
var userStateId = hrUserSetting?.StateId ?? 0;
|
|
|
|
var weekendId = _centralDbContext.States
|
|
.Where(s => s.StateId == userStateId)
|
|
.Select(s => s.WeekendId)
|
|
.FirstOrDefault() ?? 2;
|
|
|
|
var publicHolidays = _centralDbContext.Holidays
|
|
.Where(c => c.StateId == userStateId)
|
|
.ToList();
|
|
|
|
var daysInMonth = DateTime.DaysInMonth(year, month);
|
|
var allDays = Enumerable.Range(1, daysInMonth)
|
|
.Select(day => new DateTime(year, month, day))
|
|
.ToList();
|
|
|
|
var mergedRecords = new List<OtRegisterModel>();
|
|
foreach (var date in allDays)
|
|
{
|
|
var dayRecords = records
|
|
.Where(r => r.OtDate.Date == date.Date)
|
|
.OrderBy(r => r.OfficeFrom)
|
|
.ToList();
|
|
|
|
if (dayRecords.Any())
|
|
{
|
|
mergedRecords.AddRange(dayRecords);
|
|
}
|
|
else
|
|
{
|
|
mergedRecords.Add(new OtRegisterModel
|
|
{
|
|
OtDate = date,
|
|
OtDays = date.DayOfWeek.ToString(),
|
|
OtDescription = "",
|
|
});
|
|
}
|
|
}
|
|
|
|
var stream = _excelService.GenerateOvertimeExcel(
|
|
mergedRecords,
|
|
departmentId,
|
|
fullName,
|
|
departmentName,
|
|
userStateId,
|
|
weekendId,
|
|
publicHolidays,
|
|
isAdminUser: IsAdmin(userId),
|
|
logoImage: null
|
|
);
|
|
|
|
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
$"OvertimeRecords_{year}_{month}.xlsx");
|
|
}
|
|
|
|
[HttpPost("SubmitOvertime")]
|
|
public async Task<IActionResult> SubmitOvertime([FromForm] OvertimeSubmissionModel model)
|
|
{
|
|
if (model.File == null || model.File.Length == 0)
|
|
return BadRequest("No file uploaded.");
|
|
|
|
// Get userId from the login token
|
|
var userIdStr = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
|
|
if (string.IsNullOrEmpty(userIdStr) || !int.TryParse(userIdStr, out int userId))
|
|
return Unauthorized();
|
|
|
|
try
|
|
{
|
|
var uploadsFolder = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "Media", "Overtime");
|
|
if (!Directory.Exists(uploadsFolder))
|
|
Directory.CreateDirectory(uploadsFolder);
|
|
|
|
var uniqueFileName = $"{Guid.NewGuid()}_{model.File.FileName}";
|
|
var filePath = Path.Combine(uploadsFolder, uniqueFileName);
|
|
|
|
using (var fileStream = new FileStream(filePath, FileMode.Create))
|
|
{
|
|
await model.File.CopyToAsync(fileStream);
|
|
}
|
|
|
|
var relativePath = Path.Combine("Media", "Overtime", uniqueFileName).Replace("\\", "/");
|
|
|
|
// Check if record exists for same month/year/user
|
|
var existingStatus = _centralDbContext.Otstatus.FirstOrDefault(x => x.UserId == userId && x.Month == model.Month && x.Year == model.Year);
|
|
|
|
if (existingStatus != null)
|
|
{
|
|
existingStatus.FilePath = relativePath;
|
|
existingStatus.SubmitDate = DateTime.Now;
|
|
_centralDbContext.Otstatus.Update(existingStatus);
|
|
}
|
|
else
|
|
{
|
|
var newStatus = new OtStatusModel
|
|
{
|
|
UserId = userId,
|
|
Month = model.Month,
|
|
Year = model.Year,
|
|
FilePath = relativePath,
|
|
SubmitDate = DateTime.Now,
|
|
HodStatus = "Pending",
|
|
HrStatus = "Pending"
|
|
};
|
|
_centralDbContext.Otstatus.Add(newStatus);
|
|
}
|
|
|
|
await _centralDbContext.SaveChangesAsync();
|
|
return Ok();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Failed to submit overtime.");
|
|
return StatusCode(500, "An error occurred while submitting overtime.");
|
|
}
|
|
}
|
|
|
|
[HttpGet("CheckOvertimeSubmitted/{userId}/{month}/{year}")]
|
|
public async Task<IActionResult> CheckOvertimeSubmitted(string userId, int month, int year)
|
|
{
|
|
if (!int.TryParse(userId, out int parsedUserId))
|
|
return BadRequest("Invalid userId.");
|
|
|
|
var isSubmitted = await _centralDbContext.Otstatus
|
|
.AnyAsync(s => s.UserId == parsedUserId && s.Month == month && s.Year == year);
|
|
|
|
return Ok(isSubmitted);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Ot Edit
|
|
[HttpGet("GetOvertimeRecordById/{id}")]
|
|
public async Task<IActionResult> GetOvertimeRecordById(int id)
|
|
{
|
|
var record = await _centralDbContext.Otregisters.FindAsync(id);
|
|
if (record == null)
|
|
return NotFound();
|
|
|
|
return Ok(record);
|
|
}
|
|
|
|
[HttpPost]
|
|
[Route("UpdateOvertimeRecord")]
|
|
public IActionResult UpdateOvertimeRecord([FromForm] OtRegisterModel model)
|
|
{
|
|
_logger.LogInformation("UpdateOvertimeRecord called. Model: {@Model}", model);
|
|
|
|
try
|
|
{
|
|
if (!ModelState.IsValid)
|
|
{
|
|
_logger.LogWarning("ModelState is invalid. Errors: {@ModelStateErrors}", ModelState.Values.SelectMany(v => v.Errors));
|
|
return BadRequest(ModelState);
|
|
}
|
|
|
|
var existing = _centralDbContext.Otregisters.FirstOrDefault(o => o.OvertimeId == model.OvertimeId);
|
|
if (existing == null)
|
|
{
|
|
_logger.LogWarning("Overtime record not found for Id: {OvertimeId}", model.OvertimeId);
|
|
return NotFound("Overtime record not found.");
|
|
}
|
|
|
|
_logger.LogInformation("Existing record found: {@ExistingRecord}", existing);
|
|
|
|
existing.OtDate = model.OtDate;
|
|
existing.OfficeFrom = model.OfficeFrom;
|
|
existing.OfficeTo = model.OfficeTo;
|
|
existing.OfficeBreak = model.OfficeBreak;
|
|
existing.AfterFrom = model.AfterFrom;
|
|
existing.AfterTo = model.AfterTo;
|
|
existing.AfterBreak = model.AfterBreak;
|
|
existing.StationId = model.StationId;
|
|
existing.OtDescription = model.OtDescription;
|
|
existing.OtDays = model.OtDays;
|
|
existing.UserId = model.UserId;
|
|
|
|
_centralDbContext.SaveChanges();
|
|
_logger.LogInformation("Overtime record updated successfully for Id: {OvertimeId}", model.OvertimeId);
|
|
|
|
return Ok(new { message = "Record updated successfully." });
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error updating overtime record. Stack Trace: {StackTrace}", ex.StackTrace);
|
|
return StatusCode(500, "Failed to update record.");
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region OtStatus
|
|
|
|
#endregion
|
|
|
|
}
|
|
} |