Added an API to get list of branch types

This commit is contained in:
ashutosh.nehete 2025-11-20 14:35:02 +05:30
parent a31266ee4a
commit 24e45037da
3 changed files with 122 additions and 0 deletions

View File

@ -116,6 +116,15 @@ namespace Marco.Pms.Services.Controllers
return StatusCode(response.StatusCode, response);
}
[HttpGet("branch-type/list")]
public async Task<IActionResult> GetBranchTypeList([FromQuery] string? searchString)
{
Employee loggedInEmployee = await _userHelper.GetCurrentEmployeeAsync();
var response = await _serviceProject.GetBranchTypeListAsync(searchString, loggedInEmployee, tenantId);
return StatusCode(response.StatusCode, response);
}
[HttpPost("branch/create")]
public async Task<IActionResult> CreateProjectBranch([FromBody] ProjectBranchDto model)
{

View File

@ -18,6 +18,7 @@ namespace Marco.Pms.Services.Service.ServiceInterfaces
#region =================================================================== Project Branch Functions ===================================================================
Task<ApiResponse<object>> GetProjectBranchListByProjectAsync(Guid projectId, bool isActive, string? searchString, int pageNumber, int pageSize, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> GetProjectBranchDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> GetBranchTypeListAsync(string? searchString, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> CreateProjectBranchAsync(ProjectBranchDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> UpdateProjectBranchAsync(Guid id, ProjectBranchDto model, Employee loggedInEmployee, Guid tenantId);
Task<ApiResponse<object>> DeleteProjectBranchAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId);

View File

@ -614,6 +614,11 @@ namespace Marco.Pms.Services.Service
public async Task<ApiResponse<object>> GetProjectBranchListByProjectAsync(Guid projectId, bool isActive, string? searchString, int pageNumber, int pageSize,
Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("GetProjectBranchListByProjectAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
// Log method invocation with parameters for audit and debugging
_logger.LogInfo("Fetching project branches for ProjectId: {ProjectId}, IsActive: {IsActive}, Page: {PageNumber}, Size: {PageSize}", projectId, isActive, pageNumber, pageSize);
@ -692,6 +697,11 @@ namespace Marco.Pms.Services.Service
/// <returns>ApiResponse with the branch details or a standardized error.</returns>
public async Task<ApiResponse<object>> GetProjectBranchDetailsAsync(Guid id, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("GetProjectBranchDetailsAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
_logger.LogInfo("Attempting to fetch details for ProjectBranchId: {ProjectBranchId}, TenantId: {TenantId} by EmployeeId: {EmployeeId}",
id, tenantId, loggedInEmployee.Id);
@ -739,6 +749,55 @@ namespace Marco.Pms.Services.Service
}
}
/// <summary>
/// Retrieves a filtered, distinct list of project branch types for a specified tenant.
/// Supports optional search filtering, optimized for read-only access.
/// </summary>
/// <param name="searchString">Optional search string to filter branch types.</param>
/// <param name="loggedInEmployee">The employee requesting data, for audit logging.</param>
/// <param name="tenantId">Tenant identifier to scope data in a multi-tenant environment.</param>
/// <returns>ApiResponse with list of branch types or error message.</returns>
public async Task<ApiResponse<object>> GetBranchTypeListAsync(string? searchString, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("GetBranchTypeListAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
_logger.LogInfo("Fetching distinct project branch types for TenantId: {TenantId}, RequestedBy: {EmployeeId}", tenantId, loggedInEmployee.Id);
try
{
// Build initial query with no tracking for optimized read performance
var branchTypeQuery = _context.ProjectBranches
.AsNoTracking()
.Where(pb => pb.TenantId == tenantId)
.Select(pb => pb.BranchType);
// Apply search filter if provided
if (!string.IsNullOrWhiteSpace(searchString))
{
_logger.LogDebug("Applying search filter for branch types with searchString: {SearchString}", searchString);
branchTypeQuery = branchTypeQuery.Where(bt => bt.Contains(searchString));
}
// Get distinct branch types asynchronously
var branchTypes = await branchTypeQuery
.Distinct()
.OrderBy(bt => bt)
.ToListAsync();
_logger.LogInfo("Fetched {Count} distinct branch types for TenantId: {TenantId}", branchTypes.Count, tenantId);
return ApiResponse<object>.SuccessResponse(branchTypes, $"{branchTypes.Count} project branch types fetched successfully.", 200);
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching branch types for TenantId: {TenantId}", tenantId);
return ApiResponse<object>.ErrorResponse("Failed to fetch branch types due to an internal error.", ex.Message, 500);
}
}
/// <summary>
/// Creates a new project branch associated with a specific service project.
/// Applies enterprise-grade validation, logging, and exception handling.
@ -749,6 +808,13 @@ namespace Marco.Pms.Services.Service
/// <returns>ApiResponse containing created project branch details or error info.</returns>
public async Task<ApiResponse<object>> CreateProjectBranchAsync(ProjectBranchDto model, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("CreateProjectBranchAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
_logger.LogInfo("Starting project branch creation. ProjectId: {ProjectId}, TenantId: {TenantId}, CreatedBy: {EmployeeId}",
model.ProjectId, tenantId, loggedInEmployee.Id);
@ -807,6 +873,12 @@ namespace Marco.Pms.Services.Service
/// <returns>ApiResponse indicating success or failure with detailed messages.</returns>
public async Task<ApiResponse<object>> UpdateProjectBranchAsync(Guid id, ProjectBranchDto model, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("UpdateProjectBranchAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
// Validate ID consistency between route parameter and payload DTO
if (!model.Id.HasValue && model.Id != id)
{
@ -892,6 +964,11 @@ namespace Marco.Pms.Services.Service
/// <returns>ApiResponse indicating the result of the operation, with status and descriptive message.</returns>
public async Task<ApiResponse<object>> DeleteProjectBranchAsync(Guid id, bool isActive, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("DeleteProjectBranchAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
_logger.LogInfo("Starting soft delete operation for ProjectBranchId: {ProjectBranchId}, TenantId: {TenantId}, By EmployeeId: {EmployeeId}",
id, tenantId, loggedInEmployee.Id);
@ -1704,6 +1781,11 @@ namespace Marco.Pms.Services.Service
/// <returns>ApiResponse containing the created job ticket view or error details.</returns>
public async Task<ApiResponse<object>> CreateJobTicketAsync(CreateJobTicketDto model, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("CreateJobTicketAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
await using var transaction = await _context.Database.BeginTransactionAsync();
try
{
@ -2519,6 +2601,11 @@ namespace Marco.Pms.Services.Service
/// <returns>ApiResponse containing updated comment details or error information.</returns>
public async Task<ApiResponse<object>> UpdateCommentAsync(Guid id, JobCommentDto model, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("UpdateCommentAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
// Transaction ensures atomic update of comment and attachments.
await using var transaction = await _context.Database.BeginTransactionAsync();
try
@ -2733,6 +2820,11 @@ namespace Marco.Pms.Services.Service
#region =================================================================== Job Tagging Functions ===================================================================
public async Task<ApiResponse<object>> GetAttendanceForSelfAsync(Guid jobTicketId, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("GetAttendanceForSelfAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
_logger.LogInfo("GetAttendanceForSelfAsync initiated for EmployeeId: {EmployeeId}, JobTicketId: {JobTicketId}", loggedInEmployee.Id, jobTicketId);
try
@ -2807,6 +2899,12 @@ namespace Marco.Pms.Services.Service
}
public async Task<ApiResponse<object>> GetAttendanceLogForAttendanceAsync(Guid jobAttendanceId, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("GetAttendanceLogForAttendanceAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
_logger.LogInfo("GetAttendanceLogForAttendanceAsync called for JobAttendanceId: {JobAttendanceId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}", jobAttendanceId, tenantId, loggedInEmployee.Id);
try
@ -2885,6 +2983,13 @@ namespace Marco.Pms.Services.Service
}
public async Task<ApiResponse<object>> GetAttendanceForJobTeamAsync(Guid jobTicketId, DateTime? startDate, DateTime? endDate, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("GetAttendanceForJobTeamAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
_logger.LogInfo("GetAttendanceForJobTeamAsync called for JobTicketId: {JobTicketId}, TenantId: {TenantId}, EmployeeId: {EmployeeId}", jobTicketId, tenantId, loggedInEmployee.Id);
try
@ -2942,6 +3047,13 @@ namespace Marco.Pms.Services.Service
}
public async Task<ApiResponse<object>> ManageJobTaggingAsync(JobAttendanceDto model, Employee loggedInEmployee, Guid tenantId)
{
if (tenantId == Guid.Empty)
{
_logger.LogWarning("ManageJobTaggingAsync called with invalid tenant context by employee {EmployeeId}", loggedInEmployee.Id);
return ApiResponse<object>.ErrorResponse("Access Denied", "Invalid tenant context.", 403);
}
_logger.LogInfo("ManageJobTaggingAsync called for EmployeeId: {EmployeeId}, JobTicketId: {JobTicketId}", loggedInEmployee.Id, model.JobTcketId);
try