using LCU.API.Internal.Operations.IncentiveApi.Extensions; using LCU.API.Internal.Operations.IncentiveApi.Services.DispersalStrategy; using LCU.API.Internal.Operations.IncentiveApi.Models; using LCU.API.Internal.Operations.IncentiveApi.Models.GoalDispersal; 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.Common; using LCU.API.Internal.Operations.IncentiveApiLib.Persistence; using LCU.Library.Internal.IncentiveApiModels.Requests; namespace LCU.API.Internal.Operations.IncentiveApi.Services; public class GoalService : IGoalService { private readonly IGoalRepository _goalRepository; private readonly IGoalChangeRepository _goalChangeRepository; private readonly ICurrentUserService _currentUserService; private readonly IDispersalStrategyService _dispersalStrategyService; private readonly IDepartmentRepository _departmentRepository; private readonly IUserService _userService; private readonly IUnitOfWork _unitOfWork; public GoalService( IGoalRepository goalRepository, IGoalChangeRepository goalChangeRepository, ICurrentUserService currentUserService, IDispersalStrategyService dispersalStrategyService, IUnitOfWork unitOfWork, IUserService userService, IDepartmentRepository departmentRepository ) { _goalRepository = goalRepository; _goalChangeRepository = goalChangeRepository; _currentUserService = currentUserService; _unitOfWork = unitOfWork; _userService = userService; _departmentRepository = departmentRepository; _dispersalStrategyService = dispersalStrategyService; } public async Task> SaveGoalAsync(GoalChange goalChange) { return await SaveGoalRangeAsync(new List() { goalChange }); } private async Task ConfirmAppUserIdAndSaveGoalChange(GoalChange goalChange) { if (!goalChange.IsDepartmentGoalChange()) { var appUser = await _userService.GetUserByEmployeeIdAsync(goalChange.PersonId); goalChange.AppUserId = appUser.Id; } await _goalChangeRepository.SaveGoalChangeAsync(goalChange); return goalChange; } public async Task> SaveGoalRangeAsync(List goalChanges) { var goalsToSave = new List(); foreach (var goalChange in goalChanges) { await ConfirmAppUserIdAndSaveGoalChange(goalChange); var goal = await _goalRepository.FindExistingGoal(goalChange); if (goal != null) { var originalGoalValue = goal.Value; goal.Value = goalChange.Value; if (goal.IsDepartmentGoal() && originalGoalValue != goal.Value) { goalsToSave.AddRange(await CreatePersonnelGoalChangesFromDepartmentGoalChange(goalChange, originalGoalValue)); } } else { goal = new Goal() { AppUserId = goalChange.AppUserId, Product = goalChange.Product, EmployeeId = goalChange.PersonId, DepartmentId = goalChange.DepartmentId, StartDate = goalChange.StartDate.StartOfMonth(), EndDate = goalChange.EndDate.EndOfMonth(), Value = goalChange.Value }; await _goalRepository.SaveGoalAsync(goal); } goalsToSave.Add(goal); } await _unitOfWork.CompleteAsync(); return goalsToSave; } private async Task> CreatePersonnelGoalChangesFromDepartmentGoalChange(GoalChange goalChange, int originalGoalValue) { if (!goalChange.IsDepartmentGoalChange()) return new List(); var personnelGoals = new List(); var departmentPersonnelGoals = await GetMonthlyPersonnelGoalsAsync( new DepartmentPersonnelSearchRequest() { DepartmentId = goalChange.DepartmentId, IncludeAllPersonnel = true, Year = goalChange.StartDate.Year, Month = goalChange.StartDate.Month, }); var receipt = _dispersalStrategyService.ExtrapolateSingleDepartmentProduct( new DepartmentGoalExtrapolationRequest() { DepartmentGoalEndDate = goalChange.EndDate.EndOfMonth(), DepartmentGoalStartDate = goalChange.StartDate.StartOfMonth(), DepartmentId = goalChange.DepartmentId, NewDepartmentGoal = goalChange.Value, OriginalDepartmentGoal = originalGoalValue, Product = goalChange.Product }, departmentPersonnelGoals); foreach (var reDispersedGoalChange in receipt.GoalChanges) { await ConfirmAppUserIdAndSaveGoalChange(reDispersedGoalChange); var reDispersedGoal = await CreateOrUpdateGoalFromGoalChange(reDispersedGoalChange); personnelGoals.Add(reDispersedGoal); } return personnelGoals; } private async Task CreateOrUpdateGoalFromGoalChange(GoalChange goalChange) { var goal = await _goalRepository.FindExistingGoal(goalChange); if (goal != null) { goal.Value = goalChange.Value; } else { goal = new Goal() { Product = goalChange.Product, AppUserId = goalChange.AppUserId, EmployeeId = goalChange.PersonId, DepartmentId = goalChange.DepartmentId, StartDate = goalChange.StartDate.StartOfMonth(), EndDate = goalChange.EndDate.EndOfMonth(), Value = goalChange.Value }; await _goalRepository.SaveGoalAsync(goal); } return goal; } public async Task GetAnnualDepartmentGoalsAsync(int departmentId, int year) { var goals = new DepartmentGoals(departmentId, year); goals.ApplyAll(await _goalRepository.FindAnnualDepartmentGoals(departmentId, year)); return goals; } public async Task> GetAllAnnualDepartmentGoalsAsync(int year) { var departments = await _departmentRepository.GetAllDepartmentsAsync(); var departmentGoals = new List(); foreach (var department in departments) { if (department.Id != null) { departmentGoals.Add(await GetAnnualDepartmentGoalsAsync(department.Id.Value, year)); } } return departmentGoals; } public async Task GetMonthlyPersonnelGoalsAsync(DepartmentPersonnelSearchRequest searchRequest) { var users = await _userService.FindDepartmentAssignments(searchRequest); var goals = new PersonnelGoals(searchRequest.DepartmentId, searchRequest.Year, searchRequest.Month, users); goals.ApplyAll(await _goalRepository.FindMonthlyPersonnelGoals(searchRequest.DepartmentId, users, searchRequest.Year, searchRequest.Month)); return goals; } public async Task> GetGoalsAsync(GoalSearchRequest goalSearchRequest) { return await _goalRepository.GetGoalsAsync(goalSearchRequest); } public async Task> GetGoalChangesAsync() { return await _goalChangeRepository.GetGoalChangesAsync(); } public async Task GetEmployeeGoalsForMonthRangeAsync(AppUser employee, MonthRange monthRange) { var users = new List() { employee }; var goals = new EmployeeGoals(employee, monthRange); foreach (var dept in goals.Departments) { goals.ApplyAll( await _goalRepository.FindPersonnelGoalsByMonthRange(dept.DepartmentId, users, monthRange)); } return goals; } public async Task> GetEmployeeDepartmentsGoalsForMonthRangeAsync(AppUser employee, MonthRange monthRange) { var allGoals = new List(); foreach (var dept in employee.Departments) { 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 goals = new DepartmentGoalsForRange(dept.DepartmentId, monthRangeOfAssignment); var deptGoals = await _goalRepository.FindDepartmentGoalsByMonthRange(goals.DepartmentId, goals.MonthRange); goals.ApplyAll(deptGoals); allGoals.Add(goals); } } return allGoals; } }