using AutoMapper; using Marco.Pms.Model.Dtos.ServiceProject; using Marco.Pms.Model.Employees; using Marco.Pms.Model.Utilities; using Marco.Pms.Services.Service.ServiceInterfaces; using MarcoBMS.Services.Helpers; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.JsonPatch; using Microsoft.AspNetCore.Mvc; namespace Marco.Pms.Services.Controllers { [ApiController] [Route("api/[controller]")] [Authorize] public class ServiceProjectController : Controller { private readonly IServiceProject _serviceProject; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly UserHelper _userHelper; private readonly ISignalRService _signalR; private readonly Guid tenantId; public ServiceProjectController(IServiceProject serviceProject, IServiceScopeFactory serviceScopeFactory, UserHelper userHelper, ISignalRService signalR) { _serviceProject = serviceProject; _serviceScopeFactory = serviceScopeFactory; _userHelper = userHelper; _signalR = signalR; tenantId = userHelper.GetTenantId(); } #region =================================================================== Service Project Functions =================================================================== [HttpGet("list")] public async Task GetServiceProjectList([FromQuery] string? searchString, [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetServiceProjectListAsync(searchString, pageNumber, pageSize, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpGet("details/{id}")] public async Task GetServiceProjectDetails(Guid id) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetServiceProjectDetailsAsync(id, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("create")] public async Task CreateProject([FromBody] ServiceProjectDto serviceProject) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.CreateServiceProjectAsync(serviceProject, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Service_Project", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } [HttpPut("edit/{id}")] public async Task UpdateServicecProject(Guid id, [FromBody] ServiceProjectDto serviceProject) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.UpdateServiceProjectAsync(id, serviceProject, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Service_Project", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } [HttpDelete("delete/{id}")] public async Task DeActivateServiceProject(Guid id, bool isActive = false) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.DeActivateServiceProjectAsync(id, isActive, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Service_Project", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } #endregion #region =================================================================== Project Branch Functions =================================================================== [HttpGet("branch/list/{projectId}")] public async Task GetProjectBranchListByProject(Guid projectId, [FromQuery] string? searchString, [FromQuery] bool isActive = true, [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetProjectBranchListByProjectAsync(projectId, isActive, searchString, pageNumber, pageSize, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpGet("branch/details/{id}")] public async Task GetProjectBranchDetails(Guid id) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetProjectBranchDetailsAsync(id, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("branch/create")] public async Task CreateProjectBranch([FromBody] ProjectBranchDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.CreateProjectBranchAsync(model, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Project_Branch", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } [HttpPut("branch/edit/{id}")] public async Task UpdateProjectBranch(Guid id, ProjectBranchDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.UpdateProjectBranchAsync(id, model, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Project_Branch", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } [HttpDelete("branch/delete/{id}")] public async Task DeleteProjectBranch(Guid id, [FromQuery] bool isActive = false) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.DeleteProjectBranchAsync(id, isActive, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Project_Branch", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } #endregion #region =================================================================== Service Project Allocation Functions =================================================================== [HttpGet("get/allocation/list")] public async Task GetServiceProjectAllocationList([FromQuery] Guid? projectId, [FromQuery] Guid? employeeId, [FromQuery] bool isActive = true) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetServiceProjectAllocationListAsync(projectId, employeeId, true, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("manage/allocation")] public async Task ManageServiceProjectAllocation([FromBody] List model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.ManageServiceProjectAllocationAsync(model, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Service_Project_Allocation", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } #endregion #region =================================================================== Service Project Talking Points Functions =================================================================== #endregion #region =================================================================== Job Tickets Functions =================================================================== [HttpGet("job/list")] public async Task GetJobTicketsList([FromQuery] Guid? projectId, [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20, [FromQuery] bool isActive = true) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetJobTicketsListAsync(projectId, pageNumber, pageSize, isActive, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpGet("job/details/{id}")] public async Task GetJobTicketDetails(Guid id) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetJobTicketDetailsAsync(id, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpGet("job/tag/list")] public async Task GetJobTagList() { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetJobTagListAsync(loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("job/create")] public async Task CreateJobTicket([FromBody] CreateJobTicketDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.CreateJobTicketAsync(model, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Job_Ticket", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } [HttpPost("job/status-change")] public async Task ChangeJobsStatus([FromBody] ChangeJobStatusDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.ChangeJobsStatusAsync(model, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Job_Ticket", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } [HttpPatch("job/edit/{id}")] public async Task UpdateJobTicket(Guid id, [FromBody] JsonPatchDocument patchDoc) { // Validate incoming patch document if (patchDoc == null) { return BadRequest(ApiResponse.ErrorResponse("Invalid request", "Patch document cannot be null", 400)); } // Get the currently logged in employee Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); // Retrieve the job ticket by id and tenant context var jobTicket = await _serviceProject.GetJobTicketByIdAsync(id, tenantId); if (jobTicket == null) { return NotFound(ApiResponse.ErrorResponse("Job ticket not found", $"No active job ticket found with id {id}", 404)); } // Use a scoped Mapper instance to map the entity to the DTO for patching using var scope = _serviceScopeFactory.CreateScope(); var mapper = scope.ServiceProvider.GetRequiredService(); var modelToPatch = mapper.Map(jobTicket); // Apply the JSON Patch document to the DTO and check model state validity patchDoc.ApplyTo(modelToPatch, ModelState); if (!ModelState.IsValid) { return BadRequest(ApiResponse.ErrorResponse("Validation failed", "Provided patch document values are invalid", 400)); } // Update the job ticket with the patched model and logged-in user info var response = await _serviceProject.UpdateJobTicketAsync(id, jobTicket, modelToPatch, loggedInEmployee, tenantId); if (response.Success) { // If update successful, send SignalR notification with relevant info var notificationPayload = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Job_Ticket", Response = response.Data }; await _signalR.SendNotificationAsync(notificationPayload); } // Return status codes with appropriate response return StatusCode(response.StatusCode, response); } #endregion #region =================================================================== Job Comments Functions =================================================================== [HttpGet("job/comment/list")] public async Task GetCommentListByJobTicket([FromQuery] Guid? jobTicketId, [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetCommentListByJobTicketAsync(jobTicketId, pageNumber, pageSize, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("job/add/comment")] public async Task AddCommentToJobTicket([FromBody] JobCommentDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.AddCommentToJobTicketAsync(model, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Job_Ticket_Comment", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } [HttpPut("job/edit/comment")] public async Task UpdateComment(Guid id, [FromBody] JobCommentDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.UpdateCommentAsync(id, model, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Job_Ticket_Comment", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } #endregion #region =================================================================== Job Tagging Functions =================================================================== [HttpGet("job/attendance/self/{jobTicketId}")] public async Task GetAttendanceForSelf(Guid jobTicketId) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetAttendanceForSelfAsync(jobTicketId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpGet("job/attendance/log/{attendanceId}")] public async Task GetAttendanceLogForAttendance(Guid attendanceId) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetAttendanceLogForAttendanceAsync(attendanceId, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpGet("job/attendance/team/history")] public async Task GetAttendanceForJobTeam([FromQuery] Guid jobTicketId, [FromQuery] DateTime? fromDate, [FromQuery] DateTime? toDate) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.GetAttendanceForJobTeamAsync(jobTicketId, fromDate, toDate, loggedInEmployee, tenantId); return StatusCode(response.StatusCode, response); } [HttpPost("job/attendance")] public async Task ManageJobTagging(JobAttendanceDto model) { Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); var response = await _serviceProject.ManageJobTaggingAsync(model, loggedInEmployee, tenantId); if (response.Success) { var notification = new { LoggedInUserId = loggedInEmployee.Id, Keyword = "Job_Ticket_Attendance", Response = response.Data }; await _signalR.SendNotificationAsync(notification); } return StatusCode(response.StatusCode, response); } #endregion } }