diff --git a/Marco.Pms.Services/Controllers/DirectoryController.cs b/Marco.Pms.Services/Controllers/DirectoryController.cs index efa7490..eac6929 100644 --- a/Marco.Pms.Services/Controllers/DirectoryController.cs +++ b/Marco.Pms.Services/Controllers/DirectoryController.cs @@ -127,17 +127,18 @@ namespace Marco.Pms.Services.Controllers #region =================================================================== Contact Notes APIs =================================================================== [HttpGet("notes")] - public async Task GetListOFAllNotes([FromQuery] Guid? projectId, [FromQuery] int? pageSize, [FromQuery] int pageNumber) + public async Task GetListOFAllNotes([FromQuery] Guid? projectId, [FromQuery] int pageSize = 20, [FromQuery] int pageNumber = 1) { - var response = await _directoryService.GetListOFAllNotes(projectId, pageSize ?? 25, pageNumber); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _directoryService.GetListOFAllNotesAsync(projectId, pageSize, pageNumber, tenantId, loggedInEmployee); return StatusCode(response.StatusCode, response); } [HttpPost("note")] public async Task CreateContactNote([FromBody] CreateContactNoteDto noteDto) { - - var response = await _directoryService.CreateContactNote(noteDto); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _directoryService.CreateContactNote(noteDto, tenantId, loggedInEmployee); ; if (response.StatusCode == 200) { return Ok(response); @@ -155,7 +156,8 @@ namespace Marco.Pms.Services.Controllers [HttpGet("notes/{ContactId}")] public async Task GetNoteListByContactId(Guid contactId, [FromQuery] bool active = true) { - var response = await _directoryService.GetNoteListByContactId(contactId, active); + var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); + var response = await _directoryService.GetNoteListByContactId(contactId, active, tenantId, loggedInEmployee); if (response.StatusCode == 200) { return Ok(response); diff --git a/Marco.Pms.Services/Service/DirectoryService.cs b/Marco.Pms.Services/Service/DirectoryService.cs index f6d7193..0a119e3 100644 --- a/Marco.Pms.Services/Service/DirectoryService.cs +++ b/Marco.Pms.Services/Service/DirectoryService.cs @@ -560,7 +560,9 @@ namespace Marco.Pms.Services.Service .AsNoTracking() // Use AsNoTracking for read-only operations to improve performance. .Include(c => c.ContactCategory) .Include(c => c.CreatedBy) + .ThenInclude(e => e!.JobRole) .Include(c => c.UpdatedBy) + .ThenInclude(e => e!.JobRole) .FirstOrDefaultAsync(c => c.Id == id && c.IsActive && c.TenantId == tenantId); if (contact == null) { @@ -611,6 +613,7 @@ namespace Marco.Pms.Services.Service .AsNoTracking() .Include(cb => cb.Bucket) .ThenInclude(b => b!.CreatedBy) + .ThenInclude(e => e!.JobRole) .Where(cb => cb.ContactId == contact.Id && cb.Bucket != null && cb.Bucket.TenantId == tenantId); if (hasAdminPermission) @@ -649,7 +652,9 @@ namespace Marco.Pms.Services.Service return await taskDbContext.ContactNotes .AsNoTracking() .Include(cn => cn.Createdby) + .ThenInclude(e => e!.JobRole) .Include(cn => cn.UpdatedBy) + .ThenInclude(e => e!.JobRole) .Include(cn => cn.Contact) .Where(cn => cn.ContactId == contact.Id && cn.Createdby != null && cn.Createdby.TenantId == tenantId) .Select(cn => _mapper.Map(cn)) @@ -1240,193 +1245,216 @@ namespace Marco.Pms.Services.Service #region =================================================================== Contact Notes APIs =================================================================== - /// - /// Retrieves a paginated list of contact notes based on user permissions. - /// - /// The number of items per page. - /// The current page number. - /// An ApiResponse containing the paginated notes or an error message. - public async Task> GetListOFAllNotes(Guid? projectId, int pageSize, int pageNumber) + public async Task> GetListOFAllNotesAsync(Guid? projectId, int pageSize, int pageNumber, Guid tenantId, Employee loggedInEmployee) { - _logger.LogInfo("Attempting to fetch list of all notes. PageSize: {PageSize}, PageNumber: {PageNumber}", pageSize, pageNumber); + _logger.LogInfo("Initiating GetListOFAllNotesAsync. TenantId: {TenantId}, ProjectId: {ProjectId}, PageSize: {PageSize}, PageNumber: {PageNumber}, EmployeeId: {EmployeeId}", + tenantId, projectId ?? Guid.Empty, pageSize, pageNumber, loggedInEmployee.Id); - Guid tenantId = _userHelper.GetTenantId(); - var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - List? projectContactIds = null; - - if (loggedInEmployee == null) + // Ensure user context is present + if (loggedInEmployee.Id == Guid.Empty || tenantId == Guid.Empty) { - _logger.LogWarning("GetListOFAllNotes: LoggedInEmployee is null. Cannot proceed."); + _logger.LogWarning("Unauthorized: LoggedInEmployee is null."); return ApiResponse.ErrorResponse("Unauthorized", "Employee not found.", 403); } - // --- Permission Checks --- - var hasAdminPermission = await _permissionServices.HasPermission(PermissionsMaster.DirectoryAdmin, loggedInEmployee.Id); - var hasManagerPermission = await _permissionServices.HasPermission(PermissionsMaster.DirectoryAdmin, loggedInEmployee.Id); - var hasUserPermission = await _permissionServices.HasPermission(PermissionsMaster.DirectoryUser, loggedInEmployee.Id); - - IQueryable notesQuery = _context.ContactNotes - .Include(cn => cn.UpdatedBy) - .Include(cn => cn.Createdby) // Assuming 'CreatedBy' (PascalCase) - .Include(cn => cn.Contact) - .Where(cn => cn.TenantId == tenantId) - .AsQueryable(); // Start building the query - - if (!hasAdminPermission && !(hasManagerPermission || hasUserPermission)) + try { - _logger.LogWarning("GetListOFAllNotes: User {EmployeeId} does not have required permissions to access notes for TenantId: {TenantId}", loggedInEmployee.Id, tenantId); + // Use a context instance per method call for safety in parallel scenarios + await using var context = _dbContextFactory.CreateDbContext(); + + // Permission checks (parallel as they're independent) + var (hasAdminPermission, hasManagerPermission, hasUserPermission) = await CheckPermissionsAsync(loggedInEmployee.Id); + + // Access control + if (!hasAdminPermission && !hasManagerPermission && !hasUserPermission) + { + _logger.LogWarning("Access Denied. EmployeeId: {EmployeeId}, TenantId: {TenantId}", loggedInEmployee.Id, tenantId); + return ApiResponse.ErrorResponse("Access Denied", "You don't have access to view notes.", 403); + } + + // Build base query + IQueryable notesQuery = context.ContactNotes + .Include(cn => cn.UpdatedBy) + .ThenInclude(e => e!.JobRole) + .Include(cn => cn.Createdby) + .ThenInclude(e => e!.JobRole) + .Include(cn => cn.Contact) + .Where(cn => cn.TenantId == tenantId); + + // Fetch associated contact IDs for project (if filtering by project) + List? projectContactIds = null; + if (projectId.HasValue) + { + projectContactIds = await context.ContactProjectMappings + .Where(pc => pc.ProjectId == projectId.Value) + .Select(pc => pc.ContactId) + .ToListAsync(); + } + + if (!hasAdminPermission) // Manager/User filtering + { + _logger.LogInfo("Non-admin user. Applying bucket-based filtering. EmployeeId: {EmployeeId}", loggedInEmployee.Id); + // Get assigned bucket IDs + var assignedBucketIds = await context.EmployeeBucketMappings + .Where(eb => eb.EmployeeId == loggedInEmployee.Id) + .Select(eb => eb.BucketId) + .ToListAsync(); + + if (!assignedBucketIds.Any()) + { + _logger.LogInfo("No assigned buckets for user: {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.SuccessResponse(new + { + CurrentPage = pageNumber, + TotalPages = 0, + Data = new List() + }, "No notes found based on assigned buckets.", 200); + } + + // Contacts based on assigned buckets, further filtered by project (if provided) + var contactBucketQuery = context.ContactBucketMappings + .Where(cb => assignedBucketIds.Contains(cb.BucketId)); + + if (projectContactIds != null) + { + contactBucketQuery = contactBucketQuery.Where(cb => projectContactIds.Contains(cb.ContactId)); + } + + var contactIds = await contactBucketQuery.Select(cb => cb.ContactId).Distinct().ToListAsync(); + + if (!contactIds.Any()) + { + _logger.LogInfo("No contacts found for assigned buckets for user: {EmployeeId}", loggedInEmployee.Id); + return ApiResponse.SuccessResponse(new + { + CurrentPage = pageNumber, + TotalPages = 0, + Data = new List() + }, "No notes found for associated contacts.", 200); + } + + notesQuery = notesQuery.Where(cn => contactIds.Contains(cn.ContactId)); + } + else + { + // Admin: If project specified, filter notes further + if (projectContactIds != null) + notesQuery = notesQuery.Where(cn => projectContactIds.Contains(cn.ContactId)); + } + + // Pagination safeguard + pageSize = pageSize < 1 ? 25 : pageSize; + pageNumber = pageNumber < 1 ? 1 : pageNumber; + + // Accurate pagination metadata + int totalRecords = await notesQuery.CountAsync(); + int totalPages = (int)Math.Ceiling(totalRecords / (double)pageSize); + + // Fetch paginated, ordered results + List notes = await notesQuery + .OrderByDescending(cn => cn.UpdatedAt ?? cn.CreatedAt) + .Skip((pageNumber - 1) * pageSize) + .Take(pageSize) + .ToListAsync(); + + _logger.LogInfo("Notes fetched: {Count}, Page: {PageNumber}/{TotalPages}, EmployeeId: {EmployeeId}, TenantId: {TenantId}", + notes.Count, pageNumber, totalPages, loggedInEmployee.Id, tenantId); + + // In-memory mapping to ViewModel + var noteVms = _mapper.Map>(notes); + + var response = new + { + CurrentPage = pageNumber, + PageSize = pageSize, + TotalPages = totalPages, + TotalRecords = totalRecords, + Data = noteVms + }; + + _logger.LogInfo("Notes mapped to ViewModel for TenantId: {TenantId}, EmployeeId: {EmployeeId}", tenantId, loggedInEmployee.Id); + return ApiResponse.SuccessResponse(response, $"{noteVms.Count} notes fetched successfully.", 200); + + } + catch (Exception ex) + { + _logger.LogError(ex, "Exception occurred in GetListOFAllNotesAsync. TenantId: {TenantId}, EmployeeId: {EmployeeId}", tenantId, loggedInEmployee.Id); + return ApiResponse.ErrorResponse("Internal Server Error", "An error occurred while fetching notes. Please try again later.", 500); + } + } + public async Task> GetNoteListByContactId(Guid id, bool active, Guid tenantId, Employee loggedInEmployee) + { + var (hasAdminPermission, hasManagerPermission, hasUserPermission) = await CheckPermissionsAsync(loggedInEmployee.Id); + + if (!hasAdminPermission && !hasManagerPermission && !hasUserPermission) + { + _logger.LogWarning("Access Denied. EmployeeId: {EmployeeId}, TenantId: {TenantId} Do not have permission", loggedInEmployee.Id, tenantId); return ApiResponse.ErrorResponse("Access Denied", "You don't have access to view notes.", 403); } - if (projectId != null) + + Contact? contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == id && c.IsActive && c.TenantId == tenantId); + if (contact == null) { - projectContactIds = await _context.ContactProjectMappings - .Where(pc => pc.ProjectId == projectId) - .Select(pc => pc.ContactId) - .ToListAsync(); + _logger.LogWarning("Employee with ID {LoggedInEmployeeId} attempted to fetch a list notes from contact with ID {ContactId}, but the contact was not found in the database.", loggedInEmployee.Id, id); + return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); } - if (!hasAdminPermission) // If not an admin, apply additional filtering + + if (!hasAdminPermission && (hasManagerPermission || hasUserPermission)) { - _logger.LogInfo("GetListOFAllNotes: User {EmployeeId} is not an admin. Applying manager/user specific filters.", loggedInEmployee.Id); - var assignedBucketIds = await _context.EmployeeBucketMappings - .Where(eb => eb.EmployeeId == loggedInEmployee.Id) - .Select(eb => eb.BucketId) - .ToListAsync(); - - if (!assignedBucketIds.Any()) + var bucketIds = await _context.EmployeeBucketMappings.Where(em => em.EmployeeId == loggedInEmployee.Id).Select(em => em.BucketId).ToListAsync(); + var hasContactAccess = await _context.ContactBucketMappings.AnyAsync(cb => bucketIds.Contains(cb.BucketId) && cb.ContactId == contact.Id); + if (!hasContactAccess) { - _logger.LogInfo("GetListOFAllNotes: User {EmployeeId} has no assigned buckets. Returning empty list.", loggedInEmployee.Id); - return ApiResponse.SuccessResponse(new { CurrentPage = pageNumber, TotalPages = 0, Data = new List() }, "No notes found based on assigned buckets.", 200); - } - - List? contactIds = null; - - if (projectContactIds == null) - { - contactIds = await _context.ContactBucketMappings - .Where(cb => assignedBucketIds.Contains(cb.BucketId)) - .Select(cb => cb.ContactId) - .ToListAsync(); - } - else - { - contactIds = await _context.ContactBucketMappings - .Where(cb => assignedBucketIds.Contains(cb.BucketId) && projectContactIds.Contains(cb.ContactId)) - .Select(cb => cb.ContactId) - .ToListAsync(); - } - - if (!contactIds.Any()) - { - _logger.LogInfo("GetListOFAllNotes: No contacts found for assigned buckets for user {EmployeeId}. Returning empty list.", loggedInEmployee.Id); - return ApiResponse.SuccessResponse(new { CurrentPage = pageNumber, TotalPages = 0, Data = new List() }, "No notes found for associated contacts.", 200); - } - - notesQuery = notesQuery.Where(cn => contactIds.Contains(cn.ContactId)); - } - else - { - if (projectContactIds != null) - { - notesQuery = notesQuery.Where(cn => projectContactIds.Contains(cn.ContactId)); + _logger.LogWarning("Access Denied. EmployeeId: {EmployeeId}, TenantId: {TenantId} Do not have access of bucket", loggedInEmployee.Id, tenantId); + return ApiResponse.ErrorResponse("Access Denied", "You don't have access to view notes.", 403); } } - // --- Pagination Logic --- - // Ensure pageSize and pageNumber are valid - pageSize = pageSize < 1 ? 25 : pageSize; // Default to 25 if less than 1 - pageNumber = pageNumber < 1 ? 1 : pageNumber; // Default to 1 if less than 1 + var notesQuery = _context.ContactNotes + .Include(n => n.Createdby) + .ThenInclude(e => e!.JobRole) + .Include(n => n.UpdatedBy) + .ThenInclude(e => e!.JobRole) + .Where(n => n.ContactId == contact.Id && n.TenantId == tenantId); - // Get total count BEFORE applying Skip/Take for accurate pagination metadata - int totalRecords = await notesQuery.CountAsync(); - int totalPages = (int)Math.Ceiling((double)totalRecords / pageSize); + if (active) + { + notesQuery = notesQuery.Where(n => n.IsActive); + } - int skip = (pageNumber - 1) * pageSize; + List notes = await notesQuery.ToListAsync(); - // --- Apply Ordering and Pagination in the database --- - List notes = await notesQuery - .OrderByDescending(cn => (cn.UpdatedAt != null ? cn.UpdatedAt : cn.CreatedAt)) // Order by updated date or created date - .Skip((pageNumber - 1) * pageSize) - .Take(pageSize) + var noteIds = notes.Select(n => n.Id).ToList(); + List? updateLogs = await _context.DirectoryUpdateLogs + .Include(l => l.Employee) + .ThenInclude(e => e!.JobRole) + .Where(l => noteIds.Contains(l.RefereanceId)) .ToListAsync(); - _logger.LogInfo("GetListOFAllNotes: Fetched {Count} notes for page {PageNumber} of {TotalPages} total pages. Total records: {TotalRecords}.", - notes.Count, pageNumber, totalPages, totalRecords); + List noteVMs = _mapper.Map>(notes); - // --- Map to ViewModel (in-memory) --- - // This mapping is done in memory because ToBasicEmployeeVMFromEmployee() is likely a C# method - // that cannot be translated to SQL by Entity Framework. - - List noteVMS = notes - .Select(cn => cn.ToContactNoteVMFromContactNote()) - .ToList(); - - var response = new - { - CurrentPage = pageNumber, - PageSize = pageSize, // Include pageSize in response for client clarity - TotalPages = totalPages, - TotalRecords = totalRecords, // Add total records for client - Data = noteVMS - }; - - _logger.LogInfo("GetListOFAllNotes: Successfully retrieved notes and mapped to ViewModel for TenantId: {TenantId}.", tenantId); - return ApiResponse.SuccessResponse(response, $"{noteVMS.Count} notes fetched successfully.", 200); + _logger.LogInfo("{count} contact-notes record from contact {ContactId} fetched by Employee {EmployeeId}", noteVMs.Count, id, loggedInEmployee.Id); + return ApiResponse.SuccessResponse(noteVMs, $"{noteVMs.Count} contact-notes record fetched successfully", 200); } - public async Task> GetNoteListByContactId(Guid id, bool active) - { - Guid tenantId = _userHelper.GetTenantId(); - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); - Contact? contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == id && c.IsActive && c.TenantId == tenantId); - if (contact != null) - { - List notes = new List(); - if (active) - { - notes = await _context.ContactNotes - .Include(n => n.Createdby) - .Include(n => n.UpdatedBy) - .Where(n => n.ContactId == contact.Id && n.IsActive && n.TenantId == tenantId) - .ToListAsync(); - } - else - { - notes = await _context.ContactNotes - .Include(n => n.Createdby) - .Include(n => n.UpdatedBy) - .Where(n => n.ContactId == contact.Id && n.TenantId == tenantId) - .ToListAsync(); - } - var noteIds = notes.Select(n => n.Id).ToList(); - List? updateLogs = await _context.DirectoryUpdateLogs.Include(l => l.Employee).Where(l => noteIds.Contains(l.RefereanceId)).ToListAsync(); - //List? noteVMs = new List(); - List? noteVMs = notes.Select(n => n.ToContactNoteVMFromContactNote()).ToList(); - _logger.LogInfo("{count} contact-notes record from contact {ContactId} fetched by Employee {EmployeeId}", noteVMs.Count, id, LoggedInEmployee.Id); - return ApiResponse.SuccessResponse(noteVMs, $"{noteVMs.Count} contact-notes record fetched successfully", 200); - } - _logger.LogWarning("Employee with ID {LoggedInEmployeeId} attempted to fetch a list notes from contact with ID {ContactId}, but the contact was not found in the database.", LoggedInEmployee.Id, id); - return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); - } - public async Task> CreateContactNote(CreateContactNoteDto noteDto) + public async Task> CreateContactNote(CreateContactNoteDto noteDto, Guid tenantId, Employee loggedInEmployee) { - Guid tenantId = _userHelper.GetTenantId(); - var LoggedInEmployee = await _userHelper.GetCurrentEmployeeAsync(); if (noteDto != null) { Contact? contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == noteDto.ContactId && c.IsActive && c.TenantId == tenantId); if (contact != null) { - ContactNote note = noteDto.ToContactNoteFromCreateContactNoteDto(tenantId, LoggedInEmployee.Id); + ContactNote note = noteDto.ToContactNoteFromCreateContactNoteDto(tenantId, loggedInEmployee.Id); _context.ContactNotes.Add(note); await _context.SaveChangesAsync(); ContactNoteVM noteVM = note.ToContactNoteVMFromContactNote(); - _logger.LogInfo("Employee {EmployeeId} Added note at contact {ContactId}", LoggedInEmployee.Id, contact.Id); + _logger.LogInfo("Employee {EmployeeId} Added note at contact {ContactId}", loggedInEmployee.Id, contact.Id); return ApiResponse.SuccessResponse(noteVM, "Note added successfully", 200); } - _logger.LogWarning("Employee with ID {LoggedInEmployeeId} attempted to add a note to contact with ID {ContactId}, but the contact was not found in the database.", LoggedInEmployee.Id, noteDto.ContactId); + _logger.LogWarning("Employee with ID {LoggedInEmployeeId} attempted to add a note to contact with ID {ContactId}, but the contact was not found in the database.", loggedInEmployee.Id, noteDto.ContactId); return ApiResponse.ErrorResponse("Contact not found", "Contact not found", 404); } - _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", LoggedInEmployee.Id); + _logger.LogWarning("Employee with ID {LoggedInEmployeeId} sended empty payload", loggedInEmployee.Id); return ApiResponse.ErrorResponse("User Send empty Payload", "User Send empty Payload", 400); } public async Task> UpdateContactNote(Guid id, UpdateContactNoteDto noteDto) @@ -1438,7 +1466,11 @@ namespace Marco.Pms.Services.Service Contact? contact = await _context.Contacts.FirstOrDefaultAsync(c => c.Id == noteDto.ContactId && c.TenantId == tenantId); if (contact != null) { - ContactNote? contactNote = await _context.ContactNotes.Include(cn => cn.Createdby).Include(cn => cn.Contact).FirstOrDefaultAsync(n => n.Id == noteDto.Id && n.ContactId == contact.Id && n.IsActive); + ContactNote? contactNote = await _context.ContactNotes + .Include(cn => cn.Createdby) + .ThenInclude(e => e!.JobRole) + .Include(cn => cn.Contact) + .FirstOrDefaultAsync(n => n.Id == noteDto.Id && n.ContactId == contact.Id && n.IsActive); if (contactNote != null) { contactNote.Note = noteDto.Note; @@ -1519,6 +1551,7 @@ namespace Marco.Pms.Services.Service // Admin gets all buckets for the tenant bucketList = await _context.Buckets .Include(b => b.CreatedBy) + .ThenInclude(e => e!.JobRole) .Where(b => b.TenantId == tenantId) .ToListAsync(); @@ -1536,6 +1569,7 @@ namespace Marco.Pms.Services.Service bucketList = await _context.Buckets .Include(b => b.CreatedBy) + .ThenInclude(e => e!.JobRole) .Where(b => bucketIds.Contains(b.Id) || b.CreatedByID == loggedInEmployee.Id) .ToListAsync(); @@ -1779,7 +1813,6 @@ namespace Marco.Pms.Services.Service return ApiResponse.ErrorResponse("An unexpected error occurred. Please try again later.", "Internal server error", 500); } } - public async Task> AssignBucketAsync(Guid bucketId, List assignBuckets, Guid tenantId, Employee loggedInEmployee) { // Validate input payload @@ -1794,8 +1827,10 @@ namespace Marco.Pms.Services.Service // Load the bucket with related CreatedBy and validate tenant - var bucket = await _context.Buckets.Include(b => b.CreatedBy) - .FirstOrDefaultAsync(b => b.Id == bucketId && b.TenantId == tenantId); + var bucket = await _context.Buckets + .Include(b => b.CreatedBy) + .ThenInclude(e => e!.JobRole) + .FirstOrDefaultAsync(b => b.Id == bucketId && b.TenantId == tenantId); if (bucket == null) { @@ -1931,7 +1966,6 @@ namespace Marco.Pms.Services.Service return ApiResponse.SuccessResponse(bucketVm, "Bucket details updated successfully", 200); } - public async Task> DeleteBucketAsync(Guid id, Guid tenantId, Employee loggedInEmployee) { try diff --git a/Marco.Pms.Services/Service/ServiceInterfaces/IDirectoryService.cs b/Marco.Pms.Services/Service/ServiceInterfaces/IDirectoryService.cs index 5884e42..bd8468d 100644 --- a/Marco.Pms.Services/Service/ServiceInterfaces/IDirectoryService.cs +++ b/Marco.Pms.Services/Service/ServiceInterfaces/IDirectoryService.cs @@ -16,9 +16,12 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces Task> DeleteContactAsync(Guid id, bool active, Guid tenantId, Employee loggedInEmployee); - Task> GetListOFAllNotes(Guid? projectId, int pageSize, int pageNumber); - Task> GetNoteListByContactId(Guid id, bool active); - Task> CreateContactNote(CreateContactNoteDto noteDto); + + + + Task> GetListOFAllNotesAsync(Guid? projectId, int pageSize, int pageNumber, Guid tenantId, Employee loggedInEmployee); + Task> GetNoteListByContactId(Guid id, bool active, Guid tenantId, Employee loggedInEmployee); + Task> CreateContactNote(CreateContactNoteDto noteDto, Guid tenantId, Employee loggedInEmployee); Task> UpdateContactNote(Guid id, UpdateContactNoteDto noteDto); Task> DeleteContactNote(Guid id, bool active);