private static async Task CreateEmployeeWorkDay(int day, int employeeCvId, ApplicationDbContext _context) { var newDay = new EmployeeWorkDay { Day = day, EmployeeCvId = employeeCvId }; var check = _context.EmployeeWorkDays.Where(a => a.Day == day && a.EmployeeCvId == employeeCvId); if (check.Any()) { return; } try { await _context.EmployeeWorkDays.AddAsync(newDay); _context.SaveChanges(); } catch (Exception ex) { } }
/// <summary> /// This is the horizontal version of the dashboard. It shows the orders of all apartments for 31 days, since the date entered by the user, /// or since today. (the default) /// </summary> /// <param name="fromDate">Date entered in the date picker, or null</param> /// <param name="wideDashboard">When "on" means that the user wants to get the wide version of the dashboard. /// In this mode, each column is wider (about 4 normal columns), we show only 3 days, and we put more data into\ /// each order element.</param> /// <returns></returns> //public void s21Dashboard(DateTime startDate, string wideDashboard = "off") //{ // this.FromDate = startDate; // //Currntly for both normal mode and wide mode we dislay 31 days. The number of days can be set here. // //We display one month. The calculation is: the number of days displayed are equal to the month length of the starting month. // //In most cases this will yield an end date which is one less that the starting date. The only exception is January 30 and 31, which will // //end at 1 or 2 of March. // //For example: start date end date // // 10/11/2019 9/12/2019 // // 31/12/2019 30/1/2020 // // 30/1/2019 1/3/2019 (except for leap year, where it will be 29/2/2020) // // 1/11/2019 30/11/2019 // // 1/12/2019 31/12/2019 // // 1/2/2020 29/2/2020 (2020 is leap year) // int dashboardDays = FakeDateTime.monthLength(startDate); // List<Money> revenuePerDay = null; // List<Money> expensePerDay = null; // List<string> expenseTypes = null; // EmployeeWorkDay[] empWorkDaysArray = null; // List<Employee> maidList = null; // List<Money> revenuePerApartment = null; // List<double> aveargeDaysPerApartment = null; // List<int> percentOccupancyPerApartment = null; // var apartmentDayBlocks = s21dashboardPreparation( // startDate, // dashboardDays, // ref revenuePerDay, // ref expensePerDay, // ref expenseTypes, // ref revenuePerApartment, // ref aveargeDaysPerApartment, // ref percentOccupancyPerApartment, // ref empWorkDaysArray, // ref maidList); // if (Session["lastOrderDetails"] != null) // { // ViewBag.highlightOrderId = (int)Session["lastOrderDetails"]; // } // else // { // ViewBag.highlightOrderId = 0; // } // return View("s21Dashboard"); //} /// <summary> /// The function reads the orders for all apartments starting from the date set by the user and for a full month (30 or 31 days, /// and for February 28 or 29 days) /// </summary> ///<param name="fromDate">starting date of the dashboard</param> ///<param name="days">the number of days we wish to display.(depends on the starting month)</param> ///<param name="revenuePerDay">An output parameter - will contain the list of revenues per day</param> ///<param name="expensePerDay">total expenses for each day</param> ///<param name="percentOccupancyPerApartment">Number of days the apartment is occupied divided by total number of days (rounded to ///whole percent)</param> ///<param name="revenuePerApartment">Total revenue per apartment for that month</param> ///<param name="averageDaysPerApartment">contains the average number of days per rent for each apartment. We include in this average ///only rents that have started in the displayed month. IF a rent started in that month and spans to the next month ///the average takes into account the total time for that rent - not only the portion will falls in this month</param> ///<param name="empWorkDaysArray">An array containing an employeeWorkDay record for each day in the month. ///Days for which no record found - will be null. Days for which more than one recrod found - will contain ///the last record. </param> ///<param name="maidList">A list of maids (employees of role="maid") - ouitput parameter</param> /// <returns>List of apartment orders. For each apartment: /// list of DayBlocks. /// A dayBlock is either a single free day, or an order which can span 1 or more days. Note that a day block may not /// be identical to the corresponding order because the order may start before the "fromDate" or end after the "fromDate+31". /// Note that the list contains first all real apartments, then "waiting" apartments</returns> public List <List <DayBlock> > s21dashboardPreparation(DateTime fromDate, int days, ref List <Money> revenuePerDay, ref List <Money> expensePerDay, ref List <string> expenseTypes, ref List <Money> revenuePerApartment, ref List <double> averageDaysPerApartment, ref List <int> percentOccupancyPerApartment, ref EmployeeWorkDay[] empWorkDaysArray, ref List <Employee> maidList) { //for each apartment //for each day from from_date to from_date+3 //lastOrderId = 0; //orderLength = 0; //apartmentDay = read apartmentDay record for apartment and day //if record does not exist or record status == free - this is a free day - add a free block //order = apartmentDay->order //if order.isFirstDay - create a new busy block //add the day to the busy block //if order.isLastDay - write busy block //write last busy block //a 2 dimensional array - a list of apartments, and for each apartment - a list of day blocks //where each day block is either a free day or an order. using (citylifedb8_blContext db = new citylifedb8_blContext()) { var apartmentDayBlocks = new List <List <DayBlock> >(); revenuePerDay = new List <Money>(); expensePerDay = new List <Money>(); for (int i = 0; i < days; i++) { revenuePerDay.Add(new Money(0m, "UAH")); } var lastDate = fromDate.AddDays(days - 1); revenuePerApartment = new List <Money>(); averageDaysPerApartment = new List <double>(); percentOccupancyPerApartment = new List <int>(); //Calculate the expenses for each date in the range for (DateTime aDate = fromDate; aDate <= lastDate; aDate = aDate.AddDays(1)) { //Read all expenses for the date and sum them var expenseListCentsForDate = (from expense in db.Expense where expense.Date == aDate select expense.Amount).ToList(); //The expenses are kept as cents in the DB int expensesCentsForDate = 0; if (expenseListCentsForDate.Count() > 0) { expensesCentsForDate = expenseListCentsForDate.Sum(); } Money expensesForDate = new Money(expensesCentsForDate, "UAH"); expensePerDay.Add(expensesForDate); } //Sort apartments by type (first all "normal" apartments then the "waiting" apartments), then by their number var sortedApartments = (from anApartment in db.Apartment orderby anApartment.Type, anApartment.Number select anApartment).ToList(); Order anOrder = new Order() //create a fictitious order with id = 0 { Id = 0 }; foreach (var anApartment in sortedApartments) { var dayBlocks = new List <DayBlock>(); DayBlock aDayBlock = null; int dayNumber = 0; Money apartmentRevenue = new Money(0m, "UAH"); double apartmentOccupiedDays = 0; //Use float for the percentage calculation later double totalRents = 0.0; //Counter for how many orders are during the month for that apartment. //We keep it as double in order to calculate the average (which should be in float) int totalRentDays = 0; //the total amount of rented days for that apartment in that month. We take into account only rents that started //in the displayed month. //Get all apartment days of the current apartment for the desired month var apartmentDaysForMonth = (from theApartmentDay in db.ApartmentDay where theApartmentDay.Apartment.Id == anApartment.Id && theApartmentDay.Date >= fromDate && theApartmentDay.Date <= lastDate orderby theApartmentDay.Date select theApartmentDay).ToList(); int apartmentDaysI = 0; ApartmentDay anApartmentDay; int apartmentDaysCount = apartmentDaysForMonth.Count(); for (var aDate = fromDate; aDate <= lastDate; aDate = aDate.AddDays(1)) { if (apartmentDaysCount > apartmentDaysI && apartmentDaysForMonth[apartmentDaysI].Date == aDate) { //The current apartmentDays record matches the on-hand date - an apartmentDay exists anApartmentDay = apartmentDaysForMonth[apartmentDaysI]; apartmentDaysI++; } else { //An apartment day does not exist - it will be null anApartmentDay = null; } if (anApartmentDay == null || anApartmentDay.Status == (int)ApartOccuStatus.Free) { //This is a free day if (aDayBlock != null) { //Although this should not occur (assuming that the apartmentDays table matches the orders checkin and checkout dates) //But anyway - we will write the dayBlock to the list dayBlocks.Add(aDayBlock); } aDayBlock = new DayBlock() { apartmentNumber = anApartment.Number, status = OrderStatus.Free, firstDate = aDate.ToString("yyyy-MM-dd") }; //"Free" status denotes a free day dayBlocks.Add(aDayBlock); aDayBlock = null; } else { //this is a busy day. Read the order record if (anOrder.Id != anApartmentDay.OrderId) { //We did not read this order yet - read it anOrder = db.Order.Find(anApartmentDay.OrderId); // anOrder = db.Order.Single(record => record.Id == anApartmentDay.Order.Id); //Check if this order started today if (anOrder.CheckinDate == aDate) { //take this order into account for calculation of average days per rent totalRents++; totalRentDays += anOrder.DayCount; } else { //This is a new order but it started before the first day of the dispalyed month - do not take it into consideration //for calculating average rent days. } } else { //the order is for more than one day. We have already read this order in the previous cycle in the date loop } //At this point anOrder contains the order pointed by the on-hand apartmentDay record //Add the revenue of that day to the total revenu per day revenuePerDay[dayNumber] += anApartmentDay.revenueAsMoney(); apartmentRevenue += anApartmentDay.revenueAsMoney(); apartmentOccupiedDays++; if (aDayBlock == null) { //This is the first time we see this order - open a new DayBlock object. Note that if the report starts from //1/12/2019 and we have an order that started on 39/11/2019 and continued to 4/12/2019 - then the first time we //encounted this order is not in the checkin date of it. aDayBlock = new DayBlock(anOrder) { days = 1, firstDate = aDate.ToString("yyyy-MM-dd"), }; } else { //This is a continuation of the order - increment the number of days aDayBlock.days++; } if (anOrder.isLastDay(aDate)) { //This is the last day of the order - write the day block dayBlocks.Add(aDayBlock); aDayBlock = null; } } dayNumber++; } //At this point we finished going on all dates for a specific apartment. It is possible that the last DayBlock was not yet written //if its checkout date is beyond the last day of the report (our report is from 1/12/2019 till 31/12/2019, but the checkout date //of the last order is 2/1/2020) if (aDayBlock != null) { dayBlocks.Add(aDayBlock); aDayBlock = null; } //Add the dayBlocks list into the apartmentDayBlocks. Check if it is a "waiting" apartment. apartmentDayBlocks.Add(dayBlocks); //Add the apartment revenue and apartment occupacy percentage - only for "normal" apartments revenuePerApartment.Add(apartmentRevenue); double apartmentOccupancyPercent = apartmentOccupiedDays / days * 100.0; int apartmentOccupancyPercentRounded = (int)Math.Round(apartmentOccupancyPercent); percentOccupancyPerApartment.Add(apartmentOccupancyPercentRounded); //calculate the average rent days per apartment double averageRentDays = 0.0; if (totalRents > 0) { averageRentDays = totalRentDays / totalRents; } averageDaysPerApartment.Add(averageRentDays); } //At this point the apartmentDayBlocks variable contaiins a list of list of day blocks //Calculate the list of employee work days. The list contains a single record for each day (or null, if no employee is assigned //for that day). If 2 employees are assigned for the same day - only one is taken (the last one) //empWorkDaysList = new List<EmployeeWorkDay>(); empWorkDaysArray = new EmployeeWorkDay[days]; var empWorkDays = from anEmpWorkDay in db.EmployeeWorkDay where anEmpWorkDay.DateAndTime >= fromDate && anEmpWorkDay.DateAndTime <= lastDate orderby anEmpWorkDay.DateAndTime select anEmpWorkDay; foreach (var anEmpWorkDays in empWorkDays) { int dayNumber = (int)Math.Round((anEmpWorkDays.DateAndTime.Date - fromDate).TotalDays, 0); empWorkDaysArray[dayNumber] = anEmpWorkDays; } maidList = db.Employee.Where(emp => emp.Role == "maid").ToList(); //Add all maids to the maid list expenseTypes = (from expenseType in db.ExpenseType select expenseType.NameKey).ToList(); return(apartmentDayBlocks); } }