public List <BauSchedule> GenerateBauSchedules(DateTime startDate, DateTime endDate, int numberOfShifts, int numberOfEmployees)
        {
            List <Shift>    shifts    = EntityGenerator.GenerateShifts(numberOfShifts);
            List <Employee> employees = EntityGenerator.GenerateEmployees(numberOfEmployees);

            // Determine total slots available based on the period and number of shifts
            var numSlots = startDate.GetTotalWorkingDays(endDate, false) * numberOfShifts; //  Example: 20 slots = 2 slots by day * 10 days

            // Determine max number of employees allowed by shift
            var maxEmployeesByShift = Math.Ceiling(((double)numSlots) / ((double)numberOfEmployees)); // Example: 2 slots/employees = 20 slots / 10 employees

            List <BauSchedule> bauSchedule = new List <BauSchedule>();

            // Iterate through all days in the provided period
            for (DateTime currentDate = startDate; currentDate.Date <= endDate.Date; currentDate = currentDate.AddDays(1))
            {
                // BUSINESS RULE: only consider weekdays
                if (currentDate.DayOfWeek == DayOfWeek.Saturday || currentDate.DayOfWeek == DayOfWeek.Sunday)
                {
                    continue;
                }

                BauSchedule currentSchedule = new BauSchedule(currentDate);

                // Iterate through all shifts
                foreach (var currentShift in shifts)
                {
                    // choose randomly a employee which haven't filled all slots yet
                    var randomEmployee = employees
                                         .Where(e => e.Schedules.Count < maxEmployeesByShift)
                                         // BUSINESS RULE: An engineer can do at most one half day shift in a day
                                         .Where(e => e.Schedules.LastOrDefault() == null || e.Schedules.LastOrDefault().Date != currentDate.Date)
                                         // BUSINESS RULE: An engineer cannot have half day shifts on consecutive days
                                         .Where(e => e.Schedules.LastOrDefault() == null || e.Schedules.LastOrDefault().Date != new DateTime(currentDate.Year, currentDate.Month, currentDate.Day).AddDays(-1).Date)
                                         // Enforce a full cycle of employees
                                         .Where(e => e.Schedules.Count <= employees.Min(min => min.Schedules.Count))
                                         // BUSINESS RULE: This should select engineers at random
                                         .OrderBy(random => Guid.NewGuid()).FirstOrDefault();

                    if (randomEmployee != null)
                    {
                        // Using DDD to modify a domain entity
                        randomEmployee.AddSchedule(new BauSchedule(currentDate));
                        currentSchedule.Baus.Add(new Bau(randomEmployee, currentShift));
                    }
                }
                bauSchedule.Add(currentSchedule);
            }
            return(bauSchedule);
        }
        public void Should_return_employee_with_one_bauschedule_and_last_assigned_date()
        {
            // Arrange
            var employee = new Employee(1, "Employee 1");
            var expectedLastAssignedDate = DateTime.Now;
            var bauSchedule = new BauSchedule(expectedLastAssignedDate);

            // Act
            employee.AddSchedule(bauSchedule);
            var result = employee.LastAssignedDate;

            // Assert
            Assert.Equal(expectedLastAssignedDate, result);
        }
            public void Should_return_JsonResult_with_bauschedules()
            {
                // Assert
                var startDate    = new DateTime(2018, 6, 11);
                var endDate      = new DateTime(2018, 6, 22);
                var numShifts    = 2;
                var numEmployees = 10;

                var expectedBauSchedules = new List <BauSchedule>();
                var bauSchedule1         = new BauSchedule(startDate);

                bauSchedule1.Baus.AddRange(new Bau[]
                {
                    new Bau(new Employee(1, "Employee 1"), new Shift("Shift 1")),
                    new Bau(new Employee(1, "Employee 2"), new Shift("Shift 2"))
                });
                var bauSchedule2 = new BauSchedule(startDate.AddDays(1));

                bauSchedule2.Baus.AddRange(new Bau[]
                {
                    new Bau(new Employee(1, "Employee 3"), new Shift("Shift 1")),
                    new Bau(new Employee(1, "Employee 4"), new Shift("Shift 2"))
                });
                var bauSchedule3 = new BauSchedule(startDate.AddDays(2));

                bauSchedule3.Baus.AddRange(new Bau[]
                {
                    new Bau(new Employee(1, "Employee 5"), new Shift("Shift 1")),
                    new Bau(new Employee(1, "Employee 6"), new Shift("Shift 2"))
                });
                expectedBauSchedules.AddRange(new BauSchedule[] { bauSchedule1, bauSchedule2, bauSchedule3 });

                BauServiceMock
                .Setup(x => x.GenerateBauSchedules(startDate, endDate, numShifts, numEmployees))
                .Returns(expectedBauSchedules);     // Mocked the GenerateBauSchedules() method

                // Act
                var result = ControllerUnderTest.GenerateBauSchedule(startDate, endDate, numShifts, numEmployees);

                // Assert
                var jsonResult = Assert.IsType <JsonResult>(result);

                Assert.Same(expectedBauSchedules, jsonResult.Value);
            }