Added an API to get logs of certain attendance
This commit is contained in:
parent
897537a60c
commit
bd14424062
@ -0,0 +1,20 @@
|
|||||||
|
using Marco.Pms.Model.ServiceProject;
|
||||||
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
using Marco.Pms.Model.ViewModels.DocumentManager;
|
||||||
|
|
||||||
|
namespace Marco.Pms.Model.ViewModels.ServiceProject
|
||||||
|
{
|
||||||
|
public class JobAttendanceLogVM
|
||||||
|
{
|
||||||
|
public Guid Id { get; set; }
|
||||||
|
public BasicJobTicketVM? JobTicket { get; set; }
|
||||||
|
public BasicDocumentVM? Document { get; set; }
|
||||||
|
public string? Latitude { get; set; }
|
||||||
|
public string? Longitude { get; set; }
|
||||||
|
public TAGGING_MARK_TYPE Action { get; set; }
|
||||||
|
public string? Comment { get; set; }
|
||||||
|
public BasicEmployeeVM? Employee { get; set; }
|
||||||
|
public DateTime MarkedTIme { get; set; }
|
||||||
|
public DateTime MarkedAt { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -271,6 +271,15 @@ namespace Marco.Pms.Services.Controllers
|
|||||||
return StatusCode(response.StatusCode, response);
|
return StatusCode(response.StatusCode, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("job/attendance/log/{attendanceId}")]
|
||||||
|
public async Task<IActionResult> 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")]
|
[HttpGet("job/attendance/team/history")]
|
||||||
public async Task<IActionResult> GetAttendanceForJobTeam([FromQuery] Guid jobTicketId, [FromQuery] DateTime? fromDate, [FromQuery] DateTime? toDate)
|
public async Task<IActionResult> GetAttendanceForJobTeam([FromQuery] Guid jobTicketId, [FromQuery] DateTime? fromDate, [FromQuery] DateTime? toDate)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -212,6 +212,7 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
|
|
||||||
CreateMap<JobComment, JobCommentVM>();
|
CreateMap<JobComment, JobCommentVM>();
|
||||||
|
|
||||||
|
CreateMap<JobAttendanceLog, JobAttendanceLogVM>();
|
||||||
CreateMap<JobAttendance, JobAttendanceVM>()
|
CreateMap<JobAttendance, JobAttendanceVM>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.NextAction,
|
dest => dest.NextAction,
|
||||||
@ -509,6 +510,10 @@ namespace Marco.Pms.Services.MappingProfiles
|
|||||||
#region ======================================================= Document =======================================================
|
#region ======================================================= Document =======================================================
|
||||||
|
|
||||||
CreateMap<Document, DocumentVM>();
|
CreateMap<Document, DocumentVM>();
|
||||||
|
CreateMap<Document, BasicDocumentVM>()
|
||||||
|
.ForMember(
|
||||||
|
dest => dest.DocumentId,
|
||||||
|
opt => opt.MapFrom(src => src.Id));
|
||||||
CreateMap<DocumentMongoDB, BasicDocumentVM>()
|
CreateMap<DocumentMongoDB, BasicDocumentVM>()
|
||||||
.ForMember(
|
.ForMember(
|
||||||
dest => dest.DocumentId,
|
dest => dest.DocumentId,
|
||||||
|
|||||||
@ -38,6 +38,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
|||||||
|
|
||||||
#region =================================================================== Job Tagging Functions ===================================================================
|
#region =================================================================== Job Tagging Functions ===================================================================
|
||||||
Task<ApiResponse<object>> GetAttendanceForSelfAsync(Guid jobTicketId, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetAttendanceForSelfAsync(Guid jobTicketId, Employee loggedInEmployee, Guid tenantId);
|
||||||
|
Task<ApiResponse<object>> GetAttendanceLogForAttendanceAsync(Guid jobAttendanceId, Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> GetAttendanceForJobTeamAsync(Guid jobTicketId, DateTime? startDate, DateTime? endDate, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> GetAttendanceForJobTeamAsync(Guid jobTicketId, DateTime? startDate, DateTime? endDate, Employee loggedInEmployee, Guid tenantId);
|
||||||
Task<ApiResponse<object>> ManageJobTaggingAsync(JobAttendanceDto model, Employee loggedInEmployee, Guid tenantId);
|
Task<ApiResponse<object>> ManageJobTaggingAsync(JobAttendanceDto model, Employee loggedInEmployee, Guid tenantId);
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -9,6 +9,7 @@ using Marco.Pms.Model.MongoDBModels.Utility;
|
|||||||
using Marco.Pms.Model.ServiceProject;
|
using Marco.Pms.Model.ServiceProject;
|
||||||
using Marco.Pms.Model.Utilities;
|
using Marco.Pms.Model.Utilities;
|
||||||
using Marco.Pms.Model.ViewModels.Activities;
|
using Marco.Pms.Model.ViewModels.Activities;
|
||||||
|
using Marco.Pms.Model.ViewModels.AttendanceVM;
|
||||||
using Marco.Pms.Model.ViewModels.DocumentManager;
|
using Marco.Pms.Model.ViewModels.DocumentManager;
|
||||||
using Marco.Pms.Model.ViewModels.Master;
|
using Marco.Pms.Model.ViewModels.Master;
|
||||||
using Marco.Pms.Model.ViewModels.Organization;
|
using Marco.Pms.Model.ViewModels.Organization;
|
||||||
@ -2070,6 +2071,84 @@ namespace Marco.Pms.Services.Service
|
|||||||
return ApiResponse<object>.ErrorResponse("An unexpected error occurred.", ex.Message, 500);
|
return ApiResponse<object>.ErrorResponse("An unexpected error occurred.", ex.Message, 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public async Task<ApiResponse<object>> GetAttendanceLogForAttendanceAsync(Guid jobAttendanceId, Employee loggedInEmployee, Guid tenantId)
|
||||||
|
{
|
||||||
|
_logger.LogInfo("GetAttendanceLogForAttendanceAsync called for JobAttendanceId: {JobAttendanceId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}", jobAttendanceId, tenantId, loggedInEmployee.Id);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Validate existence of the JobAttendance record for the tenant
|
||||||
|
var jobAttendance = await _context.JobAttendance
|
||||||
|
.AsNoTracking()
|
||||||
|
.FirstOrDefaultAsync(ja => ja.Id == jobAttendanceId && ja.TenantId == tenantId);
|
||||||
|
|
||||||
|
if (jobAttendance == null)
|
||||||
|
{
|
||||||
|
_logger.LogWarning("JobAttendance not found. JobAttendanceId: {JobAttendanceId}, TenantId: {TenantId}", jobAttendanceId, tenantId);
|
||||||
|
return ApiResponse<object>.ErrorResponse("Job attendance not found", "Job attendance not found", 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch related attendance logs including JobTicket status and Employee role details
|
||||||
|
var attendanceLogs = await _context.JobAttendanceLogs
|
||||||
|
.AsNoTracking()
|
||||||
|
.Include(jal => jal.JobTicket).ThenInclude(jt => jt!.Status)
|
||||||
|
.Include(jal => jal.Employee).ThenInclude(e => e!.JobRole)
|
||||||
|
.Where(jal => jal.JobAttendanceId == jobAttendanceId && jal.TenantId == tenantId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// If no logs found, return empty list with success message
|
||||||
|
if (!attendanceLogs.Any())
|
||||||
|
{
|
||||||
|
_logger.LogInfo("No attendance logs found for JobAttendanceId: {JobAttendanceId}", jobAttendanceId);
|
||||||
|
return ApiResponse<object>.SuccessResponse(new List<AttendanceLogVM>(), "Job attendance log fetched successfully", 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract document IDs from logs that have attached documents
|
||||||
|
var documentIds = attendanceLogs.Where(log => log.DocumentId.HasValue)
|
||||||
|
.Select(log => log.DocumentId!.Value)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Fetch documents related to the extracted document IDs and tenant
|
||||||
|
var documents = await _context.Documents
|
||||||
|
.AsNoTracking()
|
||||||
|
.Where(d => documentIds.Contains(d.Id) && d.TenantId == tenantId)
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
// Map each attendance log and enrich with document info including pre-signed URLs
|
||||||
|
var response = attendanceLogs.Select(log =>
|
||||||
|
{
|
||||||
|
var logVm = _mapper.Map<JobAttendanceLogVM>(log);
|
||||||
|
|
||||||
|
if (log.DocumentId.HasValue)
|
||||||
|
{
|
||||||
|
var document = documents.FirstOrDefault(d => d.Id == log.DocumentId.Value);
|
||||||
|
if (document != null)
|
||||||
|
{
|
||||||
|
var preSignedUrl = _s3Service.GeneratePreSignedUrl(document.S3Key);
|
||||||
|
var thumbPreSignedUrl = !string.IsNullOrWhiteSpace(document.ThumbS3Key)
|
||||||
|
? _s3Service.GeneratePreSignedUrl(document.ThumbS3Key)
|
||||||
|
: preSignedUrl;
|
||||||
|
|
||||||
|
logVm.Document = _mapper.Map<BasicDocumentVM>(document);
|
||||||
|
logVm.Document.PreSignedUrl = preSignedUrl;
|
||||||
|
logVm.Document.ThumbPreSignedUrl = thumbPreSignedUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logVm;
|
||||||
|
}).ToList();
|
||||||
|
|
||||||
|
_logger.LogInfo("Job attendance log fetched successfully. JobAttendanceId: {JobAttendanceId}, RecordsCount: {Count}", jobAttendanceId, response.Count);
|
||||||
|
|
||||||
|
return ApiResponse<object>.SuccessResponse(response, "Job attendance log fetched successfully", 200);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.LogError(ex, "Unhandled exception in GetAttendanceLogForAttendanceAsync for JobAttendanceId: {JobAttendanceId}, TenantId: {TenantId}", jobAttendanceId, tenantId);
|
||||||
|
return ApiResponse<object>.ErrorResponse("An unexpected error occurred.", ex.Message, 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<ApiResponse<object>> GetAttendanceForJobTeamAsync(Guid jobTicketId, DateTime? startDate, DateTime? endDate, Employee loggedInEmployee, Guid tenantId)
|
public async Task<ApiResponse<object>> GetAttendanceForJobTeamAsync(Guid jobTicketId, DateTime? startDate, DateTime? endDate, Employee loggedInEmployee, Guid tenantId)
|
||||||
{
|
{
|
||||||
@ -2137,6 +2216,7 @@ namespace Marco.Pms.Services.Service
|
|||||||
// Validate the job ticket existence and status
|
// Validate the job ticket existence and status
|
||||||
var jobTicket = await _context.JobTickets
|
var jobTicket = await _context.JobTickets
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
|
.Include(jt => jt.Status)
|
||||||
.FirstOrDefaultAsync(jt => jt.Id == model.JobTcketId && jt.TenantId == tenantId && jt.IsActive);
|
.FirstOrDefaultAsync(jt => jt.Id == model.JobTcketId && jt.TenantId == tenantId && jt.IsActive);
|
||||||
if (jobTicket == null)
|
if (jobTicket == null)
|
||||||
{
|
{
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user