Added the get filter APIs for contacts and contact notes
This commit is contained in:
parent
194764c9d6
commit
48562235f5
@ -80,6 +80,7 @@ namespace Marco.Pms.Services.Controllers
|
||||
var response = await _directoryService.GetOrganizationListAsync(tenantId, loggedInEmployee);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpGet("designations")]
|
||||
public async Task<IActionResult> GetDesignationList()
|
||||
{
|
||||
@ -88,6 +89,14 @@ namespace Marco.Pms.Services.Controllers
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpGet("contact/filter")]
|
||||
public async Task<IActionResult> GetContactFilterObject()
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var response = await _directoryService.GetContactFilterObjectAsync(tenantId, loggedInEmployee);
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[HttpPost]
|
||||
@ -161,6 +170,14 @@ namespace Marco.Pms.Services.Controllers
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
|
||||
[HttpGet("notes/filter")]
|
||||
public async Task<IActionResult> GetContactNotesFilterObject()
|
||||
{
|
||||
var loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
|
||||
var response = await _directoryService.GetContactNotesFilterObjectAsync(tenantId, loggedInEmployee);
|
||||
return StatusCode(response.StatusCode, response);
|
||||
}
|
||||
|
||||
[HttpPut("note/{id}")]
|
||||
public async Task<IActionResult> UpdateContactNote(Guid id, [FromBody] UpdateContactNoteDto noteDto)
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -186,7 +186,6 @@ builder.Services.AddScoped<GeneralHelper>();
|
||||
builder.Services.AddScoped<UserHelper>();
|
||||
builder.Services.AddScoped<RolesHelper>();
|
||||
builder.Services.AddScoped<EmployeeHelper>();
|
||||
builder.Services.AddScoped<DirectoryHelper>();
|
||||
builder.Services.AddScoped<MasterHelper>();
|
||||
builder.Services.AddScoped<ReportHelper>();
|
||||
builder.Services.AddScoped<CacheUpdateHelper>();
|
||||
|
@ -819,6 +819,106 @@ namespace Marco.Pms.Services.Service
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches filter options (Buckets and Contact Categories) based on user permissions
|
||||
/// for a given tenant.
|
||||
/// </summary>
|
||||
/// <param name="tenantId">The tenant ID.</param>
|
||||
/// <param name="loggedInEmployee">The employee making the request.</param>
|
||||
/// <returns>ApiResponse with Buckets and Contact Categories.</returns>
|
||||
public async Task<ApiResponse<object>> GetContactFilterObjectAsync(Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInfo("Started fetching contact filters for TenantId: {TenantId}, EmployeeId: {EmployeeId}",
|
||||
tenantId, loggedInEmployee.Id);
|
||||
|
||||
// Step 1: Determine accessible bucket IDs based on permissions
|
||||
var (hasAdminPermission, hasManagerPermission, hasUserPermission) = await CheckPermissionsAsync(loggedInEmployee.Id);
|
||||
List<Guid>? accessibleBucketIds = null;
|
||||
|
||||
if (hasAdminPermission)
|
||||
{
|
||||
// Admin → Has access to all buckets in the tenant
|
||||
accessibleBucketIds = await _context.Buckets
|
||||
.Where(b => b.TenantId == tenantId)
|
||||
.Select(b => b.Id)
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogDebug("Admin access granted. Fetched {Count} tenant buckets.", accessibleBucketIds.Count);
|
||||
}
|
||||
else if (hasManagerPermission || hasUserPermission)
|
||||
{
|
||||
// Manager/User → Only mapped buckets
|
||||
accessibleBucketIds = await _context.EmployeeBucketMappings
|
||||
.Where(eb => eb.EmployeeId == loggedInEmployee.Id)
|
||||
.Select(eb => eb.BucketId)
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogDebug("Manager/User access granted. Fetched {Count} mapped buckets for EmployeeId: {EmployeeId}",
|
||||
accessibleBucketIds.Count, loggedInEmployee.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No permissions found for EmployeeId: {EmployeeId}. Returning empty bucket list.", loggedInEmployee.Id);
|
||||
}
|
||||
|
||||
// Step 2: Fetch available buckets (accessible OR personally created by the employee)
|
||||
var buckets = await _context.Buckets
|
||||
.Where(b =>
|
||||
(accessibleBucketIds != null && accessibleBucketIds.Contains(b.Id) && b.TenantId == tenantId)
|
||||
|| b.CreatedByID == loggedInEmployee.Id)
|
||||
.Select(b => new
|
||||
{
|
||||
Id = b.Id,
|
||||
Name = b.Name
|
||||
})
|
||||
.OrderBy(b => b.Name)
|
||||
.Distinct() // Ensures no duplicates (LINQ to Entities distinct works with anonymous types)
|
||||
.ToListAsync();
|
||||
|
||||
accessibleBucketIds = buckets.Select(b => b.Id).ToList();
|
||||
|
||||
_logger.LogInfo("Fetched {Count} buckets for EmployeeId: {EmployeeId}", buckets.Count, loggedInEmployee.Id);
|
||||
|
||||
// Step 3: Fetch contact categories mapped to the retrieved buckets
|
||||
var contactCategories = await _context.ContactBucketMappings
|
||||
.AsNoTracking() // Optimized since we are reading only
|
||||
.Include(cb => cb.Contact)
|
||||
.ThenInclude(c => c!.ContactCategory)
|
||||
.Where(cb =>
|
||||
accessibleBucketIds.Contains(cb.BucketId) &&
|
||||
cb.Contact != null &&
|
||||
cb.Contact!.ContactCategory != null)
|
||||
.Select(cb => new
|
||||
{
|
||||
Id = cb.Contact!.ContactCategory!.Id,
|
||||
Name = cb.Contact.ContactCategory.Name
|
||||
})
|
||||
.OrderBy(cc => cc.Name)
|
||||
.Distinct()
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogInfo("{Count} contact categories fetched for EmployeeId: {EmployeeId}", contactCategories.Count, loggedInEmployee.Id);
|
||||
|
||||
// Step 4: Prepare response payload
|
||||
var response = new
|
||||
{
|
||||
Buckets = buckets,
|
||||
ContactCategories = contactCategories
|
||||
};
|
||||
|
||||
_logger.LogInfo("Successfully returning filters for TenantId: {TenantId}, EmployeeId: {EmployeeId}", tenantId, loggedInEmployee.Id);
|
||||
return ApiResponse<object>.SuccessResponse(response, "Filters for contact fetched successfully", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Error while fetching contact filters for TenantId: {TenantId}, EmployeeId: {EmployeeId}", tenantId, loggedInEmployee.Id);
|
||||
return ApiResponse<object>.ErrorResponse("An error occurred while fetching filters", 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Contact Post APIs ===================================================================
|
||||
@ -1661,6 +1761,125 @@ namespace Marco.Pms.Services.Service
|
||||
StatusCodes.Status200OK);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fetches filter objects (CreatedBy employees and Organizations) for Contact Notes
|
||||
/// accessible by the logged-in employee, based on permissions.
|
||||
/// </summary>
|
||||
/// <param name="tenantId">The tenant ID.</param>
|
||||
/// <param name="loggedInEmployee">The employee requesting filters.</param>
|
||||
/// <returns>ApiResponse containing CreatedBy and Organizations filter options.</returns>
|
||||
public async Task<ApiResponse<object>> GetContactNotesFilterObjectAsync(Guid tenantId, Employee loggedInEmployee)
|
||||
{
|
||||
try
|
||||
{
|
||||
_logger.LogInfo("Started fetching Contact Notes filters for TenantId: {TenantId}, EmployeeId: {EmployeeId}",
|
||||
tenantId, loggedInEmployee.Id);
|
||||
|
||||
// Step 1: Fetch accessible bucket IDs based on permissions
|
||||
var (hasAdminPermission, hasManagerPermission, hasUserPermission) = await CheckPermissionsAsync(loggedInEmployee.Id);
|
||||
List<Guid>? accessibleBucketIds = null;
|
||||
|
||||
if (hasAdminPermission)
|
||||
{
|
||||
// Admin → Access to all buckets in the tenant
|
||||
accessibleBucketIds = await _context.Buckets
|
||||
.Where(b => b.TenantId == tenantId)
|
||||
.Select(b => b.Id)
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogDebug("Admin access granted. Found {Count} buckets.", accessibleBucketIds.Count);
|
||||
}
|
||||
else if (hasManagerPermission || hasUserPermission)
|
||||
{
|
||||
// Manager/User → Access to mapped buckets only
|
||||
accessibleBucketIds = await _context.EmployeeBucketMappings
|
||||
.Where(eb => eb.EmployeeId == loggedInEmployee.Id)
|
||||
.Select(eb => eb.BucketId)
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogDebug("Manager/User access granted. Found {Count} mapped buckets for EmployeeId: {EmployeeId}.",
|
||||
accessibleBucketIds.Count, loggedInEmployee.Id);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogWarning("No permissions found for EmployeeId: {EmployeeId}. Returning empty filters.", loggedInEmployee.Id);
|
||||
}
|
||||
|
||||
// Step 2: Fetch Contact IDs from ContactBucketMappings
|
||||
var contactIds = await _context.ContactBucketMappings
|
||||
.Where(cb => accessibleBucketIds != null && accessibleBucketIds.Contains(cb.BucketId))
|
||||
.Select(cb => cb.ContactId)
|
||||
.Distinct() // ensures no duplicate contact IDs
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogInfo("Fetched {Count} contact Ids from accessible buckets.", contactIds.Count);
|
||||
|
||||
// Step 3: Fetch Contacts related to Contact Notes for those contactIds
|
||||
var contacts = await _context.ContactNotes
|
||||
.AsNoTracking() // no need to track since it’s for read-only filters
|
||||
.Include(cn => cn.Contact)
|
||||
.ThenInclude(c => c!.CreatedBy)
|
||||
.Where(cn =>
|
||||
contactIds.Contains(cn.ContactId) &&
|
||||
cn.Contact != null &&
|
||||
cn.Contact.CreatedBy != null &&
|
||||
cn.TenantId == tenantId)
|
||||
.Select(cn => cn.Contact!)
|
||||
.Distinct() // avoid duplicate contacts from multiple notes
|
||||
.ToListAsync();
|
||||
|
||||
_logger.LogInfo("Fetched {Count} unique contacts with notes.", contacts.Count);
|
||||
|
||||
// Step 4: Build organization filters
|
||||
var organizations = contacts
|
||||
.Where(c => !string.IsNullOrEmpty(c.Organization)) // filter out null/empty orgs
|
||||
.Select(c => new
|
||||
{
|
||||
Id = c.Organization, // Using organization string as unique identifier
|
||||
Name = c.Organization
|
||||
})
|
||||
.Distinct()
|
||||
.OrderBy(o => o.Name)
|
||||
.ToList();
|
||||
|
||||
_logger.LogInfo("Extracted {Count} unique organizations from contacts.", organizations.Count);
|
||||
|
||||
// Step 5: Build CreatedBy filters (employees who created the contacts)
|
||||
var createdBy = contacts
|
||||
.Select(c => new
|
||||
{
|
||||
Id = c.CreatedBy!.Id,
|
||||
Name = $"{c.CreatedBy.FirstName} {c.CreatedBy.LastName}".Trim()
|
||||
})
|
||||
.Distinct()
|
||||
.OrderBy(e => e.Name)
|
||||
.ToList();
|
||||
|
||||
_logger.LogInfo("Extracted {Count} unique CreatedBy employees from contacts.", createdBy.Count);
|
||||
|
||||
// Step 6: Build response
|
||||
var response = new
|
||||
{
|
||||
CreatedBy = createdBy,
|
||||
Organizations = organizations
|
||||
};
|
||||
|
||||
_logger.LogInfo("Successfully returning Contact Notes filters for TenantId: {TenantId}, EmployeeId: {EmployeeId}",
|
||||
tenantId, loggedInEmployee.Id);
|
||||
|
||||
return ApiResponse<object>.SuccessResponse(response, "Filters for contact notes fetched successfully", 200);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex,
|
||||
"Error occurred while fetching Contact Notes filters for TenantId: {TenantId}, EmployeeId: {EmployeeId}",
|
||||
tenantId, loggedInEmployee.Id);
|
||||
|
||||
return ApiResponse<object>.ErrorResponse("An error occurred while fetching filters", 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a note for a given contact under the specified tenant.
|
||||
/// Ensures that the contact exists and belongs to the tenant before adding the note.
|
||||
@ -1915,7 +2134,6 @@ namespace Marco.Pms.Services.Service
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region =================================================================== Bucket APIs ===================================================================
|
||||
|
@ -12,6 +12,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||
Task<ApiResponse<object>> GetContactProfileAsync(Guid id, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> GetOrganizationListAsync(Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> GetDesignationListAsync(Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> GetContactFilterObjectAsync(Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> CreateContactAsync(CreateContactDto createContact, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> UpdateContactAsync(Guid id, UpdateContactDto updateContact, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> DeleteContactAsync(Guid id, bool active, Guid tenantId, Employee loggedInEmployee);
|
||||
@ -22,6 +23,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
|
||||
|
||||
Task<ApiResponse<object>> GetListOFAllNotesAsync(Guid? projectId, int pageSize, int pageNumber, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> GetNoteListByContactIdAsync(Guid id, bool active, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> GetContactNotesFilterObjectAsync(Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> CreateContactNoteAsync(CreateContactNoteDto noteDto, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> UpdateContactNoteAsync(Guid id, UpdateContactNoteDto noteDto, Guid tenantId, Employee loggedInEmployee);
|
||||
Task<ApiResponse<object>> DeleteContactNoteAsync(Guid id, bool active, Guid tenantId, Employee loggedInEmployee);
|
||||
|
Loading…
x
Reference in New Issue
Block a user