using LCU.API.Internal.Operations.IncentiveApi.Exceptions; using LCU.API.Internal.Operations.IncentiveApi.Services; using LCU.API.Internal.Operations.IncentiveApi.Services.AutoDecision; using LCU.API.Internal.Operations.IncentiveApiLib.Services; using LCU.API.Internal.Operations.IncentiveApi.Models.DataTransfer; using LCU.API.Internal.Operations.IncentiveApi.Models; using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.FeatureManagement.Mvc; using LCU.API.Internal.Operations.IncentiveApi.Authorization; using LCU.API.Internal.Operations.IncentiveApi.Configuration; using LCU.Library.Internal.IncentiveApiModels.Enums; using LCU.Library.Internal.IncentiveApiModels.Entities; using LCU.Library.Internal.IncentiveApiModels.Common; using LCU.API.Internal.Operations.IncentiveApiLib.Persistence; namespace LCU.API.Internal.Operations.IncentiveApi.Controllers; [FeatureGate(FeatureFlags.EnableControllers)] [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] [ApiController] [Route("api/[controller]")] public class ActivityController : ControllerBase { private readonly IActivityService _activityService; private readonly IActivityDetailService _activityDetailService; private readonly IDashboardService _dashboardService; private readonly IUserService _userService; private readonly ICurrentUserService _currentUser; private readonly IActivityDecisionService _activityDecisionService; private readonly IEStatementService _eStatementService; public ActivityController(IActivityService activityService, IActivityDetailService activityDetailService, IUserService userService, ICurrentUserService currentUser, IDashboardService dashboardService, IActivityDecisionService activityDecisionService, IEStatementService eStatementService) { _activityService = activityService; _activityDetailService = activityDetailService; _userService = userService; _currentUser = currentUser; _dashboardService = dashboardService; _activityDecisionService = activityDecisionService; _eStatementService = eStatementService; } [HttpGet("paged")] [ProducesResponseType(typeof(PagedResponse), 200)] public async Task Get([FromQuery] ActivityFilter filter) { try { var searchResult = await _activityService.ListByFilterAsync(filter); foreach (var activity in searchResult.Items) { activity?.TransformForView(); } var result = new PagedResponse(searchResult, filter, Url, Request); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}"); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("me", Name = "GetCurrentUserProgress")] [RequirePermission("VIEW_DASHBOARD")] public async Task GetCurrentUserProgress([FromQuery] int fromMonth, [FromQuery] int fromYear, [FromQuery] int toMonth, [FromQuery] int toYear, [FromQuery] string employeeId = "") { try { var monthRange = new MonthRange(fromYear, fromMonth, toYear, toMonth); var appUser = _currentUser.GetCurrentUser(); if (appUser?.Email == null) { return Unauthorized("No AD User Found."); } var employee = await _userService.GetUserByAdEmailAsync(appUser.Email); if (!string.IsNullOrWhiteSpace(employeeId)) { employee = await _userService.GetUserByEmployeeIdAsync(employeeId); } if (employee == null) { return NoContent(); } var result = await _dashboardService.GetEmployeeProgressForMonthRangeAsync(employee, monthRange); result?.TransformForView(); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}"); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("me/departments", Name = "GetCurrentUserDepartmentProgress")] [RequirePermission("VIEW_DASHBOARD,VIEW_PERFORMANCE_FOR_DEPARTMENT")] public async Task GetCurrentUserDepartmentProgress([FromQuery] int fromMonth, [FromQuery] int fromYear, [FromQuery] int toMonth, [FromQuery] int toYear, [FromQuery] int departmentId = 0) { try { var monthRange = new MonthRange(fromYear, fromMonth, toYear, toMonth); var appUser = _currentUser.GetCurrentUser(); if (appUser?.Email == null) { return Unauthorized("No AD User Found."); } var employee = await _userService.GetUserByAdEmailAsync(appUser.Email); if (employee == null) { return NoContent(); } var result = new List(); if (departmentId != 0) { result.Add( await _dashboardService.GetDepartmentProgressForMonthRangeAsync(departmentId, monthRange)); } else { result.AddRange( await _dashboardService.GetDepartmentProgressForMonthRangeAsync(employee.Departments, monthRange)); } foreach (var departmentProgress in result) { departmentProgress?.TransformForView(); } return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}"); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("region", Name = "GetRegionProgress")] [RequirePermission("VIEW_DASHBOARD,VIEW_PERFORMANCE_FOR_REGION")] public async Task GetRegionProgress([FromQuery] int fromMonth, [FromQuery] int fromYear, [FromQuery] int toMonth, [FromQuery] int toYear, [FromQuery] string regionCode) { try { var monthRange = new MonthRange(fromYear, fromMonth, toYear, toMonth); var appUser = _currentUser.GetCurrentUser(); if (appUser?.Email == null) { return Unauthorized("No AD User Found."); } var employee = await _userService.GetUserByAdEmailAsync(appUser.Email); if (employee == null) { return NoContent(); } List regions = new List(); if (string.IsNullOrEmpty(regionCode)) { var userDept = employee.Departments.FirstOrDefault(x => x.Role == Role.RegionalManager); if (userDept == null) { return Unauthorized("No User-Dept for region found."); } regions.Add(Region.FindByCode(userDept.Department.RegionCode)); } else if (regionCode == "ALL") { regions = Region.Regions; } else { regions.Add(Region.FindByCode(regionCode)); } if (!regions.Any()) { return NoContent(); } var regionProgress = new List(); foreach (var region in regions) { var result = await _dashboardService.GetRegionProgressForMonthRangeAsync(region, monthRange); regionProgress.Add(result); } foreach (var region in regionProgress) { region?.TransformForView(); } return Ok(regionProgress); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}"); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("businessLine", Name = "GetBusinessLineProgress")] [RequirePermission("VIEW_DASHBOARD,VIEW_PERFORMANCE_FOR_BUSINESS_LINE")] public async Task GetBusinessLineProgress([FromQuery] int fromMonth, [FromQuery] int fromYear, [FromQuery] int toMonth, [FromQuery] int toYear, [FromQuery] string businessLineCode) { try { var monthRange = new MonthRange(fromYear, fromMonth, toYear, toMonth); var appUser = _currentUser.GetCurrentUser(); if (appUser?.Email == null) { return Unauthorized("No AD User Found."); } var employee = await _userService.GetUserByAdEmailAsync(appUser.Email); if (employee == null) { return NoContent(); } List bls = new List(); if (string.IsNullOrEmpty(businessLineCode)) { var userDept = employee.FindDepartmentForRole(Role.BusinessLineManager); if (userDept == null) { return Unauthorized("No User-Dept for business line found."); } bls.Add(BusinessLine.FindByCode(userDept.Department.BusinessLineCode)); } else if (businessLineCode == "ALL") { bls = BusinessLine.BusinessLines; } else { bls.Add(BusinessLine.FindByCode(businessLineCode)); } if (!bls.Any()) { return NoContent(); } var blProgress = new List(); foreach (var bl in bls) { var result = await _dashboardService.GetBusinessLineProgressForMonthRangeAsync(bl, monthRange); blProgress.Add(result); } foreach (var bl in blProgress) { bl?.TransformForView(); } return Ok(blProgress); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}"); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpPost] public async Task CreateActivity([FromBody] Activity activity) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var result = await _activityService.SaveActivityAsync(activity); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpPost("StateChange")] [HttpPost("ManualStateChange")] public async Task ManuallyUpdateActivityState([FromBody] ActivityStateChange activityStateChange) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var appUser = _currentUser.GetCurrentUser(); if (appUser?.Email == null) { return Unauthorized("No AD User Found."); } var employee = await _userService.GetUserByAdEmailAsync(appUser.Email); if (employee == null) { return Unauthorized("No AD User Found."); } await _activityService.ValidateCanApplyActivityStateChange(employee, activityStateChange); var result = await _activityService.ApplyStateChange(activityStateChange); result?.TransformForView(); return Ok(result); } catch (BadActivityStateChangeException ex) { return BadRequest(ex.Message); } catch (NotAuthorizedException ex) { return StatusCode(403, ex.Message); } catch (NotFoundException) { return BadRequest("Activity Not Found."); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("{activityId}/StateChanges")] public async Task GetActivityStateChanges([FromRoute] int activityId) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var result = await _activityService.GetActivityStateChanges(activityId); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("{activityId:int}/DetailChanges")] public async Task GetActivityDetailChanges([FromRoute] int activityId) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var activity = await _activityService.GetActivity(activityId); var result = await _activityDetailService.GetAllActivityDetailUpdates(activity.Detail.Id); if (result == null || !result.Any()) { NoContent(); } return Ok(result); } catch (NotFoundException) { return NotFound($"No activity with Id {activityId} could be found"); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("{activityId}/AvailableCommands")] public async Task GetActivityAuthorizedCommands([FromRoute] int activityId, [FromQuery] string employeeId) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var appUser = _currentUser.GetCurrentUser(); if (appUser?.Email == null) { return Unauthorized("No AD User Found."); } var employee = await _userService.GetUserByAdEmailAsync(appUser.Email); if (!string.IsNullOrWhiteSpace(employeeId)) { employee = await _userService.GetUserByEmployeeIdAsync(employeeId); } if (employee == null) { return Unauthorized("No AD User Found."); } var result = await _activityService.GetActivityAuthorizedCommands(employee, activityId); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("{activityId}")] public async Task Get([FromRoute] int activityId) { try { var result = await _activityService.GetActivity(activityId); result?.TransformForView(); return Ok(result); } catch (NotFoundException) { return BadRequest("Activity Not Found."); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpPost("RequestTransfer")] [RequirePermission("TRANSFER_ACTIVITIES_BETWEEN_DEPARTMENTS, TRANSFER_ACTIVITIES_BETWEEN_ASSOCIATES")] public async Task RequestTransfer([FromBody] ActivityTransferRequest transferRequest) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var result = await _activityService.RequestTransfer(transferRequest); result?.TransformForView(); return Ok(result); } catch (NotFoundException) { return BadRequest("Activity Not Found."); } catch (BadActivityTransferActionException ex) { return BadRequest(ex.Message); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpPost("RequestTransferToOwnDepartment")] public async Task RequestTransferToOwnDepartment([FromBody] ActivityTransferRequest transferRequest) { try { var appUser = _currentUser.GetCurrentUser(); if (appUser?.Email == null) { return Unauthorized("No AD User Found."); } var employee = await _userService.GetUserByAdEmailAsync(appUser.Email); if (employee == null) { return NoContent(); } if (!ModelState.IsValid) { return BadRequest(ModelState); } var result = await _activityService.TransferToOwnDepartment(transferRequest, employee); result?.TransformForView(); return Ok(result); } catch (NotFoundException) { return BadRequest("Activity Not Found."); } catch (BadActivityTransferActionException ex) { return BadRequest(ex.Message); } catch (NotAuthorizedException ex) { return Unauthorized(ex.Message); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpPost("ApproveTransfer")] [RequirePermission("TRANSFER_ACTIVITIES_BETWEEN_DEPARTMENTS, TRANSFER_ACTIVITIES_BETWEEN_ASSOCIATES")] public async Task ApproveTransfer([FromBody] ActivityTransferApprovalRequest approvalRequest) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var appUser = _currentUser.GetCurrentUser(); if (appUser?.Email == null) { return Unauthorized("No AD User Found."); } var employee = await _userService.GetUserByAdEmailAsync(appUser.Email); if (employee == null) { return Unauthorized("No AD User Found."); } var result = await _activityService.ApproveTransfer(employee, approvalRequest); result?.TransformForView(); return Ok(result); } catch (NotFoundException) { return BadRequest("Activity Transfer Not Found."); } catch (NotAuthorizedException ex) { return StatusCode(403, ex.Message); } catch (BadActivityTransferActionException ex) { return BadRequest(ex.Message); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("{activityId}/RequestedTransferAction")] public async Task GetTransferAction([FromRoute] int activityId) { try { if (!ModelState.IsValid) { return BadRequest(ModelState); } var result = await _activityService.GetRequestedTransfer(activityId); result?.TransformForView(); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("")] [Obsolete("Added here for legacy client support, please use Paginated version")] public async Task Get() { try { var result = await _activityService.GetActivitiesAsync(); foreach (var activity in result) { activity?.TransformForView(); } return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}"); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("matchActivities")] [Obsolete("Moved to Processing Controller, please use endpoint QueueNightlyIncentiveProcess/UpdateReferralStatusProcess. Date: 1/1/2025")] public async Task GetMatchActivityTemp() { try { var results = await _activityService.MatchOrExpireReferrals(); return Ok(results); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}"); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("updateEStatementReferrals")] [Obsolete("Moved to Processing Controller, please use endpoint QueueNightlyIncentiveProcess/UpdateEStatementProcess. Date: 1/1/2025")] public async Task GetDeliveryMethodsForEStatements() { try { var results = await _eStatementService.UpdateOrExpireEStatementReferral(); return Ok(results); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}"); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("RunDailyManualReviewRequery")] [Obsolete("Moved to Processing Controller, please use endpoint QueueNightlyIncentiveProcess/UpdateAccountDecisionProcess. Date: 1/1/2025")] public async Task RunDailyManualReviewRequery() { try { var result = await _activityDecisionService.UpdateAndDecideManualReviewActivities(); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("RunDailyLICStationRequery")] [Obsolete("Moved to Processing Controller, please use endpoint QueueNightlyIncentiveProcess/UpdateLICSalesProcess. Date: 1/1/2025")] public async Task RunDailyLICRequery() { try { var result = await _activityDecisionService.UpdateAndDecideLicReferralActivities(); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("RunDailyDirectDepositRequery")] [Obsolete("Moved to Processing Controller, please use endpoint QueueNightlyIncentiveProcess/UpdateDirectDepositReferralsProcess. Date: 1/1/2025")] public async Task RunDailyDirectDepositRequery() { try { var result = await _activityDecisionService.UpdateAndDecideDirectDepositPendingReferralActivities(); return Ok(result); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("RunDecisionService")] [Obsolete("Moved to Processing Controller, please use endpoint QueueNightlyIncentiveProcess/UpdateAccountDecisionProcess. Date: 1/1/2025")] public async Task RunDecisionService() { try { Log.Information("RunDecisionService was forced"); var decisioned = await _activityDecisionService.DecisionActivityByState(ActivityState.Created); Log.Information($"Auto-decisioned {decisioned.Count} activities in Created state"); decisioned = await _activityDecisionService.DecisionActivityByState(ActivityState.ManualReview); Log.Information($"Auto-decisioned {decisioned.Count} activities in Manual Review state"); decisioned = await _activityDecisionService.UpdateAndDecideManualReviewActivities(); Log.Information($"Updated and Auto-Decisioned {decisioned.Count} Activities"); decisioned = await _activityDecisionService.UpdateAndDecideDpEligibleLoanActivities(); Log.Information($"Updated and Auto-Decisioned {decisioned.Count} Debt Protection Eligible Loan Activities"); return Ok(); } catch (Exception ex) { Log.Error(ex, $"Failure in {GetType().Name}."); return StatusCode(StatusCodes.Status500InternalServerError); } } }