private IActionResult GetDepartmentWorkloadResult(int departmentId, DateTime dateFrom, DateTime dateTo, WorkloadPeriod workloadPeriod)
        {
            var departmentWorkload = _workloadSvc.GetDepartmentWorkload(departmentId, new DateTimeRange(dateFrom.Date, dateTo.Date), workloadPeriod);

            var departmentWorkloadDto = new DepartmentWorkloadDto
            {
                DepartmentId    = departmentId,
                PeriodStartDate = dateFrom.Date,
                PeriodEndDate   = dateTo.Date
            };

            if (departmentWorkload.EmployeeWorkloads.Count > 0)
            {
                foreach (var workloadRecord in departmentWorkload.EmployeeWorkloads[0].WorkloadRecords)
                {
                    departmentWorkloadDto.DateRanges.Add(new DateTimeRange(workloadRecord.DateFrom, workloadRecord.DateTo));
                }
                foreach (var employeeWorkload in departmentWorkload.EmployeeWorkloads)
                {
                    var employeeWorkloadDto = new CommonEmployeeWorkloadDto
                    {
                        EmployeeId       = employeeWorkload.Employee.ID,
                        EmployeeFullName = employeeWorkload.Employee.FullName
                    };
                    foreach (var workloadRecord in employeeWorkload.WorkloadRecords)
                    {
                        int totalPercents = (int)Math.Round(workloadRecord.TotalPercents);
                        employeeWorkloadDto.Workloads.Add(totalPercents);
                    }
                    departmentWorkloadDto.EmployeesWorkloads.Add(employeeWorkloadDto);
                }
            }
            return(Ok(departmentWorkloadDto));
        }
        public IActionResult GetEmployeesWorkloadForChildDepartment(int departmentId, int childDepartmentId, DateTime dateFrom, DateTime dateTo, WorkloadPeriod workloadPeriod)
        {
            if (dateFrom > dateTo)
            {
                return(BadRequest("Дата начала периода должна быть меньше или равна дате окончания периода"));
            }

            var childDepartment = _departmentSvc.GetById(childDepartmentId);

            if (childDepartment == null)
            {
                return(NotFound());
            }

            if (childDepartment.ParentDepartmentID != departmentId)
            {
                return(BadRequest("Указанное подразделение не является родительским к указанному дочернему подразделению"));
            }

            return(GetDepartmentWorkloadResult(childDepartmentId, dateFrom, dateTo, workloadPeriod));
        }
        public IActionResult GetEmployeesWorkloadForProjectManager(int employeeId, DateTime dateFrom, DateTime dateTo, WorkloadPeriod workloadPeriod)
        {
            if (dateFrom > dateTo)
            {
                return(BadRequest("Дата начала периода должна быть меньше или равна дате окончания периода"));
            }

            var employee = _employeeSvc.GetById(employeeId);

            if (employee == null)
            {
                return(NotFound());
            }
            var dateRange = new DateTimeRange(dateFrom, dateTo);

            var subordinatesWorkload    = _workloadSvc.GetPMSubordinatesWorkload(employeeId, dateRange, workloadPeriod);
            var subordinatesWorkloadDto = new SubordinatesWorkloadDto
            {
                ManagerEmployeeId = employee.ID
            };

            if (subordinatesWorkload.SubordinateEmployeesWorkloads.Count > 0)
            {
                foreach (var workloadRecord in subordinatesWorkload.SubordinateEmployeesWorkloads[0].WorkloadRecords[0].WorkloadRecords)
                {
                    subordinatesWorkloadDto.DateRanges.Add(new DateTimeRange(workloadRecord.DateFrom, workloadRecord.DateTo));
                }
                foreach (var employeeItem in subordinatesWorkload.SubordinateEmployeesWorkloads)
                {
                    var subordinateEmployeeDto = new EmployeeProjectWorkloadDto
                    {
                        Employee = new BasicEmployeeDto(employeeItem.Employee)
                    };
                    foreach (var workloadItem in employeeItem.WorkloadRecords[0].WorkloadRecords)
                    {
                        subordinateEmployeeDto.TotalWorkloadPercents.Add((int)Math.Round(workloadItem.TotalPercents));
                    }
                    foreach (var projectItem in employeeItem.WorkloadRecords)
                    {
                        var projectWorkloadDto = new EmployeeProjectWorkloadRecordDto
                        {
                            Project = new BasicProjectDto(projectItem.Project)
                        };
                        foreach (var workloadItem in projectItem.WorkloadRecords)
                        {
                            projectWorkloadDto.WorkloadPercents.Add((int)Math.Round(workloadItem.CurrentProjectPercents));
                        }
                        subordinateEmployeeDto.ProjectWorkloads.Add(projectWorkloadDto);
                    }
                    subordinatesWorkloadDto.EmployeesWorkloads.Add(subordinateEmployeeDto);
                }
            }

            return(Ok(subordinatesWorkloadDto));
        }
        public IActionResult GetEmployeesWorkloadForDepartment(int departmentId, DateTime dateFrom, DateTime dateTo, WorkloadPeriod workloadPeriod)
        {
            if (dateFrom > dateTo)
            {
                return(BadRequest("Дата начала периода должна быть меньше или равна дате окончания периода"));
            }

            var department = _departmentSvc.GetById(departmentId);

            if (department == null)
            {
                return(NotFound());
            }

            return(GetDepartmentWorkloadResult(departmentId, dateFrom, dateTo, workloadPeriod));
        }
        public DepartmentWorkload GetDepartmentWorkload(int departmentId, DateTimeRange dateRange, WorkloadPeriod workloadPeriodStep)
        {
            var dateOnlyRange         = new DateTimeRange(dateRange.Begin.Date, dateRange.End.Date);
            var departmentEmployees   = EmployeeSvc.GetEmployeesInDepartment(departmentId, dateOnlyRange, true);
            var membershipByEmployees = GetProjectMembershipByEmployees(dateOnlyRange, departmentEmployees);
            var workhoursByDate       = ProductionCalendarSvc.GetWorkHoursByDate(dateOnlyRange);
            var departmentWorkload    = new DepartmentWorkload
            {
                DepartmentId = departmentId,
                DateFrom     = dateOnlyRange.Begin.Date,
                DateTo       = dateOnlyRange.End.Date
            };
            var employeeWorkloads = GetEmployeesWorkloadForDateRange(departmentEmployees, dateOnlyRange, workloadPeriodStep, membershipByEmployees, workhoursByDate, 0);

            departmentWorkload.EmployeeWorkloads.AddRange(employeeWorkloads);
            departmentWorkload.TotalHours = departmentWorkload.EmployeeWorkloads.Sum(ew => ew.WorkloadRecords.Sum(wr => wr.CurrentProjectHours));
            return(departmentWorkload);
        }
        private EmployeeWorkload GetEmployeeWorkloadForDateRange(Employee employee, DateTimeRange dateRange, WorkloadPeriod periodStep, IDictionary <DateTime, int> workhoursByDate, IDictionary <DateTime, Workload> dailyWorkload)
        {
            var employeeWorkload = new EmployeeWorkload
            {
                Employee = employee
            };

            DateTime dateFrom = dateRange.Begin.Date;

            DateTime dateTo;

            if (periodStep == WorkloadPeriod.Week)
            {
                int daysToSunday = (7 - (int)dateFrom.DayOfWeek) % 7;
                dateTo = dateFrom.AddDays(daysToSunday);
            }
            else if (periodStep == WorkloadPeriod.Month)
            {
                int lastDayOfMonth = DateTime.DaysInMonth(dateFrom.Year, dateFrom.Month);
                dateTo = new DateTime(dateFrom.Year, dateFrom.Month, lastDayOfMonth);
            }
            else
            {
                throw new NotImplementedException($"Обработка периода загрузки {periodStep} не реализована");
            }

            while (dateTo <= dateRange.End.Date)
            {
                EmployeeWorkloadRecord employeeWorkloadRecord = CalculateWorkloadForPeriod(dateFrom, dateTo, dailyWorkload, workhoursByDate);
                employeeWorkload.WorkloadRecords.Add(employeeWorkloadRecord);
                dateFrom = dateTo.AddDays(1);
                if (periodStep == WorkloadPeriod.Week)
                {
                    dateTo = dateTo.AddDays(7);
                }
                else if (periodStep == WorkloadPeriod.Month)
                {
                    dateTo = dateTo.AddMonths(1);
                    int lastDayOfMonth = DateTime.DaysInMonth(dateTo.Year, dateTo.Month);
                    dateTo = new DateTime(dateTo.Year, dateTo.Month, lastDayOfMonth);
                }
            }

            dateTo = dateRange.End.Date;
            if (dateFrom <= dateTo)
            {
                EmployeeWorkloadRecord employeeWorkloadRecord = CalculateWorkloadForPeriod(dateFrom, dateTo, dailyWorkload, workhoursByDate);
                employeeWorkload.WorkloadRecords.Add(employeeWorkloadRecord);
            }

            return(employeeWorkload);
        }
        private IList <EmployeeWorkload> GetEmployeesWorkloadForDateRange(IEnumerable <Employee> employees, DateTimeRange dateRange, WorkloadPeriod periodStep, IDictionary <int, List <ProjectMember> > membershipByEmployees, IDictionary <DateTime, int> workhoursByDate, int projectId)
        {
            var employeeWorkloads = new List <EmployeeWorkload>();

            foreach (var employee in employees)
            {
                if (!membershipByEmployees.TryGetValue(employee.ID, out var projectMemberships))
                {
                    projectMemberships = new List <ProjectMember>();
                }
                var dailyWorkload = GetEmployeeDailyWorkload(projectId, dateRange, projectMemberships, workhoursByDate);

                EmployeeWorkload employeeWorkload = GetEmployeeWorkloadForDateRange(employee, dateRange, periodStep, workhoursByDate, dailyWorkload);
                employeeWorkloads.Add(employeeWorkload);
            }
            return(employeeWorkloads);
        }
        public SubordinatesWorkload GetPMSubordinatesWorkload(int projectManagerId, DateTimeRange dateRange, WorkloadPeriod workloadPeriodStep)
        {
            // TODO: Логика тяжеловесная и запутанная, надо подумать над возможными улучшениями
            var dateOnlyRange         = new DateTimeRange(dateRange.Begin.Date, dateRange.End.Date);
            var employees             = GetProjectManagerSubordinates(projectManagerId, dateOnlyRange);
            var membershipByEmployees = GetProjectMembershipByEmployees(dateOnlyRange, employees);
            var workhoursByDate       = ProductionCalendarSvc.GetWorkHoursByDate(dateOnlyRange);

            var projectComparer = new FuncBasedComparer <Project>((first, second) =>
            {
                if (first.EmployeePMID == projectManagerId && second.EmployeePMID != projectManagerId)
                {
                    return(-1);
                }
                if (first.EmployeePMID != projectManagerId && second.EmployeePMID == projectManagerId)
                {
                    return(1);
                }
                int res = string.Compare(first.FullName, second.FullName);
                if (res != 0)
                {
                    res = first.ID - second.ID;
                }
                return(res);
            });

            var workload = new SubordinatesWorkload();

            foreach (var employee in employees)
            {
                var employeeProjects = ProjectMembershipSvc.GetProjectsForEmployee(employee.ID, dateOnlyRange);
                employeeProjects = employeeProjects.OrderBy(e => e, projectComparer).ToList();
                var employeeProjectWorkload = new EmployeeProjectWorkload();
                employeeProjectWorkload.Employee = employee;
                foreach (var project in employeeProjects)
                {
                    if (!membershipByEmployees.TryGetValue(employee.ID, out var projectMemberships))
                    {
                        projectMemberships = new List <ProjectMember>();
                    }
                    var dailyWorkload = GetEmployeeDailyWorkload(project.ID, dateRange, projectMemberships, workhoursByDate);

                    var employeeWorkload = GetEmployeeWorkloadForDateRange(employee, dateRange, workloadPeriodStep, workhoursByDate, dailyWorkload);
                    var workloadRecord   = new EmployeeProjectWorkloadRecord();
                    workloadRecord.Project = project;
                    workloadRecord.WorkloadRecords.AddRange(employeeWorkload.WorkloadRecords);
                    employeeProjectWorkload.WorkloadRecords.Add(workloadRecord);
                }
                if (employeeProjectWorkload.WorkloadRecords.Count > 0)
                {
                    workload.SubordinateEmployeesWorkloads.Add(employeeProjectWorkload);
                }
            }
            return(workload);
        }