Added an API to get list of comments using job ID (if possible)

This commit is contained in:
ashutosh.nehete 2025-11-13 14:49:56 +05:30
parent 6679c5877d
commit a9f1a99e6f
3 changed files with 102 additions and 0 deletions

View File

@ -102,6 +102,7 @@ namespace Marco.Pms.Services.Controllers
return StatusCode(response.StatusCode, response);
}
[HttpGet("job/details/{id}")]
public async Task<IActionResult> GetJobTicketDetails(Guid id)
{
@ -111,6 +112,15 @@ namespace Marco.Pms.Services.Controllers
return StatusCode(response.StatusCode, response);
}
[HttpGet("job/comment/list")]
public async Task<IActionResult> GetCommentListByJobTicket([FromQuery] Guid? jobTicketId, [FromQuery] int pageNumber = 1, [FromQuery] int pageSize = 20)
{
Employee loggedInEmploee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _serviceProject.GetCommentListByJobTicketAsync(jobTicketId, pageNumber, pageSize, loggedInEmploee, tenantId);
return StatusCode(response.StatusCode, response);
}
[HttpPost("job/create")]
public async Task<IActionResult> CreateJobTicket(CreateJobTicketDto model)
{

View File

@ -19,6 +19,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
Task<ApiResponse<object>> GetJobTicketsListAsync(Guid? projectId, int pageNumber, int pageSize, bool isActive, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> GetJobTicketDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> CreateJobTicketAsync(CreateJobTicketDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> GetCommentListByJobTicketAsync(Guid? jobTicketId, int pageNumber, int pageSize, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> AddCommentToJobTicketAsync(JobCommentDto model, Employee loggedInEmployee, Guid tenantId);
#endregion
}

View File

@ -597,6 +597,11 @@ namespace Marco.Pms.Services.Service
// Map comments, assignees, and tags to their respective viewmodels
var commentVMs = _mapper.Map<List<JobCommentVM>>(commentTask.Result);
commentVMs = commentVMs.Select(vm =>
{
vm.JobTicket = _mapper.Map<BasicJobTicketVM>(jobTicket);
return vm;
}).ToList();
var assigneeVMs = _mapper.Map<List<BasicEmployeeVM>>(assigneeTask.Result);
var tagVMs = _mapper.Map<List<TagVM>>(tagTask.Result);
@ -617,6 +622,91 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.ErrorResponse("Internal Server Error", "Failed to retrieve job details. Please try again later.", 500);
}
}
/// <summary>
/// Retrieves a paginated list of comments for a specified job ticket within a tenant context.
/// </summary>
/// <param name="jobTicketId">Optional job ticket identifier to filter comments.</param>
/// <param name="pageNumber">Page number (1-based index) for pagination.</param>
/// <param name="pageSize">Page size for pagination.</param>
/// <param name="loggedInEmployee">Employee making the request (for logging).</param>
/// <param name="tenantId">Tenant context to scope data.</param>
/// <returns>ApiResponse with paged comment view models or error details.</returns>
public async Task<ApiResponse<object>> GetCommentListByJobTicketAsync(Guid? jobTicketId, int pageNumber, int pageSize, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("TenantId missing in comment list request by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
if (pageNumber < 1 || pageSize < 1)
{
_logger.LogInfo("Invalid pagination parameters in comment list request. PageNumber: {PageNumber}, PageSize: {PageSize}", pageNumber, pageSize);
return ApiResponse<object>.ErrorResponse("Bad Request", "Page number and size must be greater than zero.", 400);
}
try
{
_logger.LogInfo("Fetching comment list for jobTicketId {JobTicketId} by employee {EmployeeId} in tenant {TenantId}",
jobTicketId ?? Guid.Empty, loggedInEmployee.Id, tenantId);
var commentQuery = _context.JobComments
.Include(jc => jc.JobTicket).ThenInclude(jt => jt!.Status)
.Include(jc => jc.CreatedBy).ThenInclude(e => e!.JobRole)
.Where(jc =>
jc.TenantId == tenantId &&
jc.JobTicket != null &&
jc.CreatedBy != null &&
jc.CreatedBy.JobRole != null);
// Validate and filter by job ticket if specified
if (jobTicketId.HasValue)
{
var jobTicketExists = await _context.JobTickets.AnyAsync(jt =>
jt.Id == jobTicketId && jt.TenantId == tenantId);
if (!jobTicketExists)
{
_logger.LogWarning("Job ticket {JobTicketId} not found in tenant {TenantId} for comment listing", jobTicketId, tenantId);
return ApiResponse<object>.ErrorResponse("Job not found", "Job ticket not found.", 404);
}
commentQuery = commentQuery.Where(jc => jc.JobTicketId == jobTicketId.Value);
}
var totalEntities = await commentQuery.CountAsync();
var totalPages = (int)Math.Ceiling((double)totalEntities / pageSize);
var comments = await commentQuery
.OrderByDescending(jc => jc.CreatedAt)
.Skip((pageNumber - 1) * pageSize)
.Take(pageSize)
.ToListAsync();
var commentVMs = _mapper.Map<List<JobCommentVM>>(comments);
var response = new
{
CurrentPage = pageNumber,
TotalPages = totalPages,
TotalEntities = totalEntities,
Data = commentVMs,
};
_logger.LogInfo("{Count} comments fetched successfully for jobTicketId {JobTicketId} by employee {EmployeeId}",
commentVMs.Count, jobTicketId ?? Guid.Empty, loggedInEmployee.Id);
return ApiResponse<object>.SuccessResponse(response, $"{commentVMs.Count} record(s) fetched successfully.", 200);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching comments for jobTicketId {JobTicketId} by employee {EmployeeId} in tenant {TenantId}",
jobTicketId ?? Guid.Empty, loggedInEmployee.Id, tenantId);
return ApiResponse<object>.ErrorResponse("Internal Server Error", "Failed to fetch comments. Please try again later.", 500);
}
}
/// <summary>
/// Creates a new job ticket with optional assignees and tags within a transactional scope.
@ -796,6 +886,7 @@ namespace Marco.Pms.Services.Service
return ApiResponse<object>.ErrorResponse("Internal Server Error", "An unexpected error occurred.", 500);
}
}
/// <summary>
/// Adds a new comment to an existing job ticket within the tenant context.
/// </summary>