Files
2026-03-17 09:53:09 -05:00

749 lines
32 KiB
C#

using LCU.API.Internal.Operations.IncentiveApi.Exceptions;
using LCU.API.Internal.Operations.IncentiveApi.Services.DuplicateDetection;
using LCU.API.Internal.Operations.IncentiveApi.Models.DataTransfer;
using LCU.API.Internal.Operations.IncentiveApiLib.Extensions;
using LCU.API.Internal.Operations.IncentiveApi.Models;
using LCU.API.Internal.Operations.IncentiveApi.Models.ExternalActivities;
using LCU.API.Internal.Operations.IncentiveApiLib.Services;
using LCU.API.Internal.Operations.IncentiveApiLib.Repositories;
using LCU.Library.Internal.IncentiveApiModels.Entities;
using LCU.Library.Internal.IncentiveApiModels.Enums;
using LCU.Library.Internal.IncentiveApiModels.Common;
using LCU.API.Internal.Operations.IncentiveApi.Services.MicroApiServices;
using LCU.Library.Internal.IncentiveApiModels.Requests;
using LCU.Library.Internal.IncentiveApiModels.Results;
namespace LCU.API.Internal.Operations.IncentiveApi.Services;
public class ActivityService : IActivityService
{
private const string TransferredFromString = "Activity has been transferred from Activity ID: {0}";
private const string TransferredToString = "Activity has been transferred to Activity ID: {0}";
private readonly IActivityRepository _activityRepository;
private readonly IActivityChangeRepository _activityChangeRepository;
private readonly IActivityTransferActionRepository _activityTransferActionRepository;
private readonly IUserService _userService;
private readonly INotificationApiService _notificationService;
private readonly IUnitOfWork _unitOfWork;
private readonly IDuplicateDetectionService _duplicateDetectionService;
private readonly IAuthorizationService _authorizationService;
private readonly ProcessResult _incentiveProcessResult;
public ActivityService(
IActivityRepository activityRepository,
IActivityChangeRepository activityChangeRepository,
IActivityTransferActionRepository activityTransferActionRepository,
IUserService userService,
INotificationApiService notificationService,
IDuplicateDetectionService duplicateDetectionService,
IAuthorizationService authorizationService,
IUnitOfWork unitOfWork
)
{
_activityRepository = activityRepository;
_activityChangeRepository = activityChangeRepository;
_activityTransferActionRepository = activityTransferActionRepository;
_userService = userService;
_notificationService = notificationService;
_unitOfWork = unitOfWork;
_authorizationService = authorizationService;
_duplicateDetectionService = duplicateDetectionService;
_incentiveProcessResult = new ProcessResult();
}
public async Task<int> SaveActivityAsync(Activity activity)
{
if (LogGapInformation(activity))
{
Log.Information($"Activity {activity.Id} - {activity.Detail.MemberName} " +
$"GapEligible saved as : {activity.Detail.IsGapInsuranceEligible} {DateTime.UtcNow} ");
}
if (string.IsNullOrWhiteSpace(activity.EmployeeId))
{
throw new DeadActivityException(
$"Attempted to save activity missing EmployeeId.");
}
if (activity.DepartmentId < 0)
{
throw new DeadActivityException(
$"Attempted to save activity with invalid DepartmentId of {activity.DepartmentId}");
}
var appUser = await _userService.GetActiveUserByEmployeeIdAsync(activity.EmployeeId)
?? await _userService.GetUserByEmployeeIdAsync(activity.EmployeeId);
if (appUser == null)
{
throw new NotFoundException($"Employee Not Found For EmployeeId: {activity.EmployeeId}");
}
activity.AppUserId = appUser.Id;
activity.Accepted = activity.Accepted.Date.AddHours(12);
await _activityRepository.SaveActivityAsync(activity);
await _unitOfWork.CompleteAsync();
await MarkDuplicates(new List<Activity> { activity });
return activity.Id;
}
public static bool LogGapInformation(Activity activity)
{
return activity.Product == Product.Vehicle
&& activity.SourceSystem == SystemType.Dna
&& activity.Detail != null
&& activity.Detail.IsGapInsuranceEligible == false
&& activity.Detail.AccountBalance.HasValue
&& activity.Detail.AccountBalance.Value <= 100000
&& (!string.IsNullOrEmpty(activity.Detail?.MemberName))
&& (!activity.Detail.MemberName.ToLower().Contains(" inc") && !activity.Detail.MemberName.Contains(" llc"));
}
public async Task<Activity> CreateAndRetrieveActivity(Activity activity)
{
var newActivityId = await SaveActivityAsync(activity);
return await GetActivity(newActivityId);
}
public async Task MarkDuplicates(IReadOnlyCollection<Activity> activities)
{
foreach (var activity in activities)
{
var duplicates = await _duplicateDetectionService.TryFindDuplicates(activity);
if (duplicates == null || !duplicates.Any()) continue;
var change = new ActivityStateChange
{
ActivityId = activity.Id,
State = ActivityState.Rejected,
ActivityMatchId = duplicates.First().Id,
Note = $"Activity rejected, duplicate of {duplicates.First().Id}."
};
await ApplyStateChange(change);
}
}
public async Task SaveActivityRangeAsync(IReadOnlyCollection<Activity> activities)
{
await _activityRepository.SaveActivityRangeAsync(activities.ToList());
await _unitOfWork.CompleteAsync();
await MarkDuplicates(activities);
}
public async Task<ProcessResult> RunReferralStatusUpdates()
{
try
{
var activityUpdates = await MatchOrExpireReferrals();
var message = $"There were {activityUpdates.Count()} Referral Activity State Updates";
Log.Information(message);
_incentiveProcessResult.MessageStack.Add(message);
}
catch (Exception exception)
{
var message = $"There was an issue with Activity State Updates Process. Exception Message: {exception.Message}.";
_incentiveProcessResult.MessageStack.Add(message);
_incentiveProcessResult.Success = false;
}
return _incentiveProcessResult;
}
public async Task<IReadOnlyCollection<ActivityStateChange>> MatchOrExpireReferrals()
{
var activeReferrals = await _activityRepository.FindUnmatchedReferrals();
var changes = new List<ActivityStateChange>();
foreach (var referral in activeReferrals)
{
var matchedSale = await _activityRepository.FindUnmatchedSaleForReferral(referral);
if (matchedSale != null)
{
var acceptedStateChange = await ApplyAcceptedStateChange(referral, matchedSale);
changes.Add(acceptedStateChange);
if (referral.EmployeeId == matchedSale.EmployeeId
&& referral.Product == Product.NewChecking
&& matchedSale.Product == Product.NewChecking)
{
ActivityStateChange rejectedStateChange = await ApplyRejectedStateChange(referral, matchedSale);
changes.Add(rejectedStateChange);
}
continue;
}
var expireRange = referral.Product != Product.FirstMortgageReferral
? DateTime.Today.Subtract(TimeSpan.FromDays(60))
: DateTime.Today.Subtract(TimeSpan.FromDays(120));
if (referral.SourceCreated < expireRange)
{
var change = new ActivityStateChange
{
ActivityId = referral.Id,
State = ActivityState.Rejected,
Note = "Referral has expired."
};
await ApplyStateChange(change);
changes.Add(change);
}
}
return changes;
}
private async Task<ActivityStateChange> ApplyRejectedStateChange(Activity referral, Activity matchedSale)
{
var creditedEmployee = _userService.GetUserByEmployeeIdAsync(matchedSale.EmployeeId);
var rejectedStateChange = new ActivityStateChange
{
ActivityId = referral.Id,
State = ActivityState.Rejected,
ActivityMatchId = matchedSale.Id,
Note = $"Referral rejected as {creditedEmployee.Result.FullName} is also employee on {matchedSale.Id}."
};
await ApplyStateChange(rejectedStateChange);
return rejectedStateChange;
}
private async Task<ActivityStateChange> ApplyAcceptedStateChange(Activity referral, Activity matchedSale)
{
var acceptedStateChange = new ActivityStateChange
{
ActivityId = referral.Id,
State = ActivityState.Accepted,
ActivityMatchId = matchedSale.Id,
Note = $"Referral was matched to {matchedSale.Id}."
};
await ApplyStateChange(acceptedStateChange);
return acceptedStateChange;
}
public async Task<Activity> ApplyStateChange(ActivityStateChange activityStateChange, bool commitTransaction = true)
{
var existingActivity = await _activityRepository.GetActivityById(activityStateChange.ActivityId);
if (existingActivity == null)
{
throw new NotFoundException($"No activity with Id {activityStateChange.ActivityId} could be found");
}
if (activityStateChange.ActivityMatchId == activityStateChange.ActivityId)
{
throw new Exception("Activity cannot change a state against itself.");
}
if (existingActivity.State == activityStateChange.State &&
(activityStateChange.AcceptedDate == null || existingActivity.Accepted == activityStateChange.AcceptedDate))
{
await _activityChangeRepository.SaveActivityStateChange(activityStateChange);
await _unitOfWork.CompleteAsync();
return existingActivity;
}
existingActivity.State = activityStateChange.State;
if (activityStateChange.AcceptedDate != null)
{
existingActivity.Accepted = (DateTime)activityStateChange.AcceptedDate?.Date.AddHours(12);
}
if (activityStateChange.State == ActivityState.Accepted || activityStateChange.State == ActivityState.Rejected)
{
if (activityStateChange.AcceptedDate == null)
{
existingActivity.Accepted = DateTime.UtcNow.Date.AddHours(12);
}
if (activityStateChange.ActivityMatchId > 0)
{
var matchedActivity = await _activityRepository.GetActivityById(activityStateChange.ActivityMatchId);
if (matchedActivity == null)
{
throw new NotFoundException($"No matched activity with Id {activityStateChange.ActivityMatchId} could be found");
}
existingActivity.MatchingActivityId = activityStateChange.ActivityMatchId;
if (activityStateChange.State == ActivityState.Accepted)
{
matchedActivity.MatchingActivityId = activityStateChange.ActivityId;
}
}
}
await _activityChangeRepository.SaveActivityStateChange(activityStateChange);
if (commitTransaction)
{
await _unitOfWork.CompleteAsync();
}
return existingActivity;
}
public async Task<IReadOnlyCollection<Activity>> GetActivitiesAsync()
{
var activities = await _activityRepository.GetActivitiesAsync();
return activities ?? new List<Activity>();
}
public async Task<PagedResult<Activity>> ListByFilterAsync(ActivityFilter filter)
{
try
{
return await _activityRepository.GetPagedFilteredActivities(filter);
}
catch (Exception ex)
{
Log.Error(ex, $"Failed to retrieve filtered Actions limit: {filter.Limit}, page: {filter.Page}");
throw new ServerErrorException();
}
}
public async Task<IReadOnlyCollection<ActivityStateChange>> GetActivityStateChanges(int activityId)
{
return await _activityChangeRepository.GetActivityChangesByActivityId(activityId);
}
public async Task<IReadOnlyCollection<DepartmentProgress>> GetDepartmentActivityForMonthRangeAsync(
List<UserDepartment> userDepartments,
MonthRange monthRange
)
{
var deptProgress = new List<DepartmentProgress>();
foreach (var dept in userDepartments)
{
var isAssignedInMonthRange = dept.StartDate.Date < monthRange.EndTime.Date &&
(dept.EndDate == null ||
monthRange.StartTime.Date < dept.EndDate.Value.Date);
if (isAssignedInMonthRange)
{
var startDate = dept.StartDate.Date < monthRange.StartTime.Date
? monthRange.StartTime.Date
: dept.StartDate.Date;
var endDate = dept.EndDate == null ? monthRange.EndTime.Date
: dept.EndDate.Value.Date > monthRange.EndTime.Date ? monthRange.EndTime.Date
: dept.EndDate.Value.Date;
var monthRangeOfAssignment = new MonthRange
(
startDate.Year,
startDate.Month,
endDate.Year,
endDate.Month
);
var progress = new DepartmentProgress(dept.DepartmentId, monthRangeOfAssignment);
var departmentActivity = await _activityRepository.FindDepartmentActivityByMonthRange(
progress.DepartmentId, progress.MonthRange);
progress.ApplyActivity(departmentActivity);
deptProgress.Add(progress);
}
}
return deptProgress;
}
public async Task<Activity> GetActivity(int activityId)
{
var activity = await _activityRepository.GetActivityIncludingPayouts(activityId);
if (activity == null)
{
throw new NotFoundException($"No activity with Id {activityId} could be found");
}
return activity;
}
public async Task<Activity> GetActivityForStateUpdate(Activity queryActivity)
{
var activity = await _activityRepository.FindActivityForStateUpdate(queryActivity);
if (activity == null)
{
throw new NotFoundException(
$"No activity with matching query activity could be found. AccountNumber: {queryActivity.Detail.AccountNumber} MemberName:{queryActivity.Detail.MemberName}");
}
return activity;
}
public async Task<Activity> GetActivityForDetailUpdate(Activity queryActivity)
{
return await _activityRepository.FindActivityForDetailUpdate(queryActivity);
}
public async Task ValidateCanApplyActivityStateChange(AppUser appUser, ActivityStateChange activityStateChange)
{
var activity = await _activityRepository.GetActivityIncludingPayouts(activityStateChange.ActivityId);
if (activity == null)
{
throw new NotFoundException($"No activity with Id {activityStateChange.ActivityId} could be found");
}
if (activity.ActivityPayouts != null && activity.ActivityPayouts.Any())
{
throw new BadActivityStateChangeException("Cannot change the state of an activity that has a payout.");
}
if (activityStateChange.AcceptedDate != null)
{
var lastDateNotPaidOut = new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1).AddMonths(-1);
if (activityStateChange.AcceptedDate < lastDateNotPaidOut || activityStateChange.AcceptedDate > DateTime.Today.AddMonths(1))
{
throw new BadActivityStateChangeException(
"Cannot change the accepted date of an activity to a date that's already paid out, or is greater than 1 month from now.");
}
}
var required = activity.RequiredToChangeState(activityStateChange.State);
switch (required)
{
case StateChangeRequirement.NotAllowed:
case StateChangeRequirement.SystemOnly:
throw new BadActivityStateChangeException("Activity can not be changed to target state.");
case StateChangeRequirement.AdminOnly when appUser.HasRoleAnywhere(Role.Admin):
case StateChangeRequirement.AdminOrPermission when appUser.HasRoleAnywhere(Role.Admin)
|| await _authorizationService.AppUserCanMakeStateChange(appUser, activity,
activityStateChange.State):
case StateChangeRequirement.Hierarchical
when await _authorizationService.ValidateHierarchicalDepartmentPermission(appUser, Role.DepartmentManagerRoles, activity.DepartmentId)
|| await _authorizationService.AppUserCanMakeStateChange(appUser, activity, activityStateChange.State):
return;
default:
throw new NotAuthorizedException("User does not have the permission to change the activity state.");
}
}
public async Task<ActivityTransferAction> RequestTransfer(ActivityTransferRequest activityTransferRequest)
{
var activity =
await _activityRepository.GetActivityIncludingPayouts(activityTransferRequest.RequestedActivityId);
if (activity == null)
{
throw new NotFoundException(
$"No activity with Id {activityTransferRequest.RequestedActivityId} could be found");
}
if (activity.ActivityPayouts.Any())
{
throw new BadActivityTransferActionException(
"Cannot request a transfer of an activity that has a payout.");
}
if (!ActivityTransferAction.IsEligibleForTransfer(activity.State))
{
throw new BadActivityTransferActionException(
"Cannot request a transfer that isn't pending or approved.");
}
var newAppUser = await _userService.GetActiveUserByEmployeeIdAsync(activityTransferRequest.NewEmployeeId);
var activityTransferAction = new ActivityTransferAction
{
Id = 0,
ActivityStateBeforeTransfer = activity.State,
RequestedActivityId = activity.Id,
State = ActivityTransferState.Requested,
NewAppUserId = newAppUser.Id,
NewActivityDepartmentId = activityTransferRequest.NewDepartmentId,
NewActivityEmployeeId = activityTransferRequest.NewEmployeeId
};
await _activityTransferActionRepository.SaveTransferAsync(activityTransferAction);
var stateChange = new ActivityStateChange
{
ActivityId = activityTransferRequest.RequestedActivityId,
Note = "",
State = ActivityState.PendingTransfer
};
await ApplyStateChange(stateChange);
var initiatingManager = await _userService
.FindDepartmentManagers(activityTransferAction.RequestedActivity.DepartmentId);
var destinationManager = await _userService
.FindDepartmentManagers(activityTransferAction.NewActivityDepartmentId);
var recipients = initiatingManager
.Concat(destinationManager)
.Select(manager => manager.AdEmail)
.Distinct()
.ToList();
await _notificationService.SendTransferRequestInitiatedNotification(activityTransferAction, recipients);
return activityTransferAction;
}
public async Task<ActivityTransferAction> TransferToOwnDepartment(
ActivityTransferRequest activityTransferRequest,
AppUser employee
)
{
var existingActivity =
await _activityRepository.GetActivityIncludingPayouts(activityTransferRequest.RequestedActivityId);
if (existingActivity == null)
{
throw new NotFoundException(
$"No activity with Id {activityTransferRequest.RequestedActivityId} could be found");
}
if (!string.Equals(existingActivity.EmployeeId, employee.EmployeeId) ||
!string.Equals(activityTransferRequest.NewEmployeeId, employee.EmployeeId))
{
throw new NotAuthorizedException(
"This activity does not belong to the requesting user and cannot be transferred.");
}
if (!employee.HasDepartment(activityTransferRequest.NewDepartmentId))
{
throw new BadActivityTransferActionException(
"Cannot request a transfer of an activity to a department that the user is not assigned to.");
}
if (existingActivity.ActivityPayouts.Any())
{
throw new BadActivityTransferActionException(
"Cannot request a transfer of an activity that has a payout.");
}
if (existingActivity.State != ActivityState.Accepted)
{
throw new BadActivityTransferActionException(
"Cannot request a transfer to another assigned department for an activity that isn't accepted.");
}
var newAppUser = await _userService.GetActiveUserByEmployeeIdAsync(activityTransferRequest.NewEmployeeId);
var activityTransferAction = new ActivityTransferAction
{
Id = 0,
ActivityStateBeforeTransfer = existingActivity.State,
RequestedActivityId = existingActivity.Id,
State = ActivityTransferState.Accepted,
NewAppUserId = newAppUser.Id,
NewActivityDepartmentId = activityTransferRequest.NewDepartmentId,
NewActivityEmployeeId = activityTransferRequest.NewEmployeeId
};
var newActivity = Activity.CopyActivityForTransfer(existingActivity, activityTransferAction, employee.AdEmail);
activityTransferAction.NewActivity = newActivity;
await _activityTransferActionRepository.SaveTransferAsync(activityTransferAction);
await _unitOfWork.CompleteAsync();
var newStateChange = new ActivityStateChange
{
ActivityId = newActivity.Id,
ActivityMatchId = existingActivity.Id,
Note = string.Format(TransferredFromString, existingActivity.Id),
State = activityTransferAction.ActivityStateBeforeTransfer
};
await ApplyStateChange(newStateChange);
var stateChange = new ActivityStateChange
{
ActivityId = existingActivity.Id,
ActivityMatchId = newActivity.Id,
Note = string.Format(TransferredToString, newActivity.Id),
State = ActivityState.Transferred
};
await ApplyStateChange(stateChange);
return activityTransferAction;
}
public async Task<ActivityTransferAction> ApproveTransfer(
AppUser appUser,
ActivityTransferApprovalRequest transferApproval
)
{
var activityTransferAction = await GetActivityTransferAction(transferApproval);
var activity = await _activityRepository.GetActivityIncludingPayouts(activityTransferAction.RequestedActivityId);
var targetStateChange = transferApproval.ApprovalState == ActivityTransferState.Accepted
? ActivityState.Accepted
: activityTransferAction.ActivityStateBeforeTransfer;
var canApproveTransferFrom = await _authorizationService.AppUserCanMakeStateChange(appUser, activity, targetStateChange);
var canApproveTransferTo =
await _authorizationService.AppUserCanMakeStateChange(appUser, activity, targetStateChange, activityTransferAction.NewActivityDepartmentId);
if (!canApproveTransferFrom && !canApproveTransferTo)
{
throw new NotAuthorizedException("Employee is not allowed to approve for either department");
}
if (transferApproval.ApprovalState == ActivityTransferState.Rejected)
{
return await RejectTransfer(activityTransferAction);
}
if (transferApproval.ApprovalState == ActivityTransferState.Accepted)
{
var isApprovedByRequestedDepartment =
!string.IsNullOrEmpty(activityTransferAction.RequestedDepartmentApprover);
var isApprovedByNewDepartment = !string.IsNullOrEmpty(activityTransferAction.NewDepartmentApprover);
if (canApproveTransferFrom && !isApprovedByRequestedDepartment)
{
activityTransferAction.RequestedDepartmentApprover = appUser.FullName;
activityTransferAction.RequestedDepartmentApproved = DateTime.Now;
isApprovedByRequestedDepartment = true;
}
if (canApproveTransferTo && !isApprovedByNewDepartment)
{
activityTransferAction.NewDepartmentApprover = appUser.FullName;
activityTransferAction.NewDepartmentApproved = DateTime.Now;
isApprovedByNewDepartment = true;
}
if (isApprovedByRequestedDepartment && isApprovedByNewDepartment)
{
var existingActivity = await _activityRepository
.GetActivityIncludingPayouts(activityTransferAction.RequestedActivityId);
var newActivityEmployee = await _userService
.GetUserByEmployeeIdAsync(activityTransferAction.NewActivityEmployeeId);
var newActivity = Activity.CopyActivityForTransfer(existingActivity, activityTransferAction,
newActivityEmployee.AdEmail);
activityTransferAction.NewActivity = newActivity;
activityTransferAction.State = ActivityTransferState.Accepted;
await _unitOfWork.CompleteAsync();
var newStateChange = new ActivityStateChange
{
ActivityId = newActivity.Id,
ActivityMatchId = existingActivity.Id,
Note = string.Format(TransferredFromString, existingActivity.Id),
State = activityTransferAction.ActivityStateBeforeTransfer
};
await ApplyStateChange(newStateChange);
var stateChange = new ActivityStateChange
{
ActivityId = existingActivity.Id,
ActivityMatchId = newActivity.Id,
Note = string.Format(TransferredToString, newActivity.Id),
State = ActivityState.Transferred
};
await ApplyStateChange(stateChange);
}
else
{
await _unitOfWork.CompleteAsync();
}
}
return activityTransferAction;
}
public async Task<ActivityTransferAction> GetRequestedTransfer(int activityId)
{
return await _activityTransferActionRepository.GetRequestedTransferActionByActivityId(activityId);
}
private async Task<ActivityTransferAction> GetActivityTransferAction(
ActivityTransferApprovalRequest transferApproval
)
{
var activityTransferAction = await _activityTransferActionRepository
.GetTransferActionById(transferApproval.Id);
if (activityTransferAction == null)
{
throw new NotFoundException(
$"No activity transfer action with Id {transferApproval.Id} could be found");
}
if (activityTransferAction.State != ActivityTransferState.Requested)
{
throw new BadActivityTransferActionException("Approval has already been decided for this activity");
}
return activityTransferAction;
}
private async Task<ActivityTransferAction> RejectTransfer(ActivityTransferAction activityTransferAction)
{
activityTransferAction.State = ActivityTransferState.Rejected;
var stateChange = new ActivityStateChange
{
ActivityId = activityTransferAction.RequestedActivityId,
Note = "Activity transfer has been rejected.",
State = activityTransferAction.ActivityStateBeforeTransfer
};
await ApplyStateChange(stateChange);
return activityTransferAction;
}
public async Task CancelPendingTransfersBetween(MonthRange range)
{
var transfers = await _activityTransferActionRepository.GetActiveTransfersForStateAsync(ActivityState.Accepted);
foreach (var transfer in transfers)
{
if (transfer.RequestedActivity.Accepted.Date >= range.StartTime.Date && transfer.RequestedActivity.Accepted.Date <= range.EndTime.Date)
{
await RejectTransfer(transfer);
}
}
}
public async Task<List<IExternalActivity>> FilterExternalActivitiesByExistingSourceId(
List<IExternalActivity> incomingEternalActivities
)
{
var existingActivities =
await _activityRepository.GetActivitiesBySourceId(incomingEternalActivities.Select(x => x.GetSourceId())
.ToList());
return incomingEternalActivities
.Where(newActivity => !existingActivities.Any(existingActivity =>
existingActivity.Product == newActivity.GetProductType() &&
existingActivity.Type == newActivity.GetActivityType() &&
existingActivity.SourceId == newActivity.GetSourceId()))
.ToList();
}
public async Task<AuthorizedActivityCommands> GetActivityAuthorizedCommands(AppUser appUser, int activityId)
{
var activity = await _activityRepository.GetActivityIncludingPayouts(activityId);
if (activity == null)
{
throw new NotFoundException($"No activity with Id {activityId} could be found");
}
var allowedChanges = new List<ActivityState>();
var canApproveTransferFrom = false;
var canApproveTransferTo = false;
var activityTransferAction = await GetRequestedTransfer(activityId);
var targetDepartmentId = activityTransferAction == null || activity.State != ActivityState.PendingTransfer ? 0 : activityTransferAction.NewActivityDepartmentId;
var hasHierarchicalPermission = await _authorizationService.ValidateHierarchicalDepartmentPermission(appUser,
Role.DepartmentManagerRoles, activity.DepartmentId);
foreach (var stateDetail in ActivityStateDetail.ActivityStateDetails)
{
var changeRequirement = activity.RequiredToChangeState(stateDetail.State);
switch (changeRequirement)
{
case StateChangeRequirement.AdminOnly when appUser.HasRoleAnywhere(Role.Admin):
case StateChangeRequirement.AdminOrPermission when appUser.HasRoleAnywhere(Role.Admin)
|| await _authorizationService.AppUserCanMakeStateChange(appUser, activity,
stateDetail.State, targetDepartmentId):
case StateChangeRequirement.Hierarchical when hasHierarchicalPermission
|| await _authorizationService.AppUserCanMakeStateChange(appUser, activity,
stateDetail.State, targetDepartmentId):
allowedChanges.Add(stateDetail.State);
break;
}
}
if (activityTransferAction != null && allowedChanges.Contains(ActivityState.Transferred))
{
canApproveTransferFrom = await _authorizationService.AppUserCanMakeStateChange(appUser, activity, ActivityState.Transferred);
canApproveTransferTo = await _authorizationService.AppUserCanMakeStateChange(appUser, activity, ActivityState.Transferred,
activityTransferAction.NewActivityDepartmentId);
}
allowedChanges = allowedChanges.Distinct().ToList();
return new AuthorizedActivityCommands(allowedChanges.ToArray(), canApproveTransferFrom, canApproveTransferTo);
}
}