예제 #1
0
        private void Email_report_Daily_TER_avg_permonth(object obj)
        {
            var timer_data = (Timer_data)obj;

            using (var scope = scopeFactory.CreateScope())
            {
                var      dbContext   = scope.ServiceProvider.GetRequiredService <ScaffoldContext>();
                DateTime startDate   = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day).AddDays(-1);
                DateTime endDate     = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day).AddSeconds(-1);
                var      reportName  = new ReportName("TERperMonthperTonne;Средневзвешенное ТЭР на тонну по циклам производства");
                var      reportDates = new ReportDates(startDate, endDate, tesYear: DateTime.Now.Year);
                var      reportInfo  = new ReportInfo();

                reportInfo.EvalReportInfo(reportName,
                                          dbContext,
                                          reportDates
                                          );
                var excel_file = Excel_methods.Export_to_Excel_TERperMonthperTonne(reportInfo);


                string serverUrl = "http://192.168.0.147:8080/";


                string msg = $@"<html><body><h2>Здравствуйте. Отчет средневзвешенное ТЭР на тонну по циклам производства во вложении.</h2> <h4>Версию с графиками можно посмотреть и выгрузить здесь: <a href= ""{serverUrl}Reports/ShowReport?lastDay=1&report_name=TERperMonthperTonne%3B%D0%A1%D1%80%D0%B5%D0%B4%D0%BD%D0%B5%D0%B2%D0%B7%D0%B2%D0%B5%D1%88%D0%B5%D0%BD%D0%BD%D0%BE%D0%B5+%D0%A2%D0%AD%D0%A0+%D0%BD%D0%B0+%D1%82%D0%BE%D0%BD%D0%BD%D1%83+%D0%BF%D0%BE+%D1%86%D0%B8%D0%BA%D0%BB%D0%B0%D0%BC+%D0%BF%D1%80%D0%BE%D0%B8%D0%B7%D0%B2%D0%BE%D0%B4%D1%81%D1%82%D0%B2%D0%B0"">Дневной отчет средневзвешенное ТЭР на тонну по циклам производства</a><h4></body></html>";
                try
                {
                    StaticMethods.SendEmailReport(ref SentMsges_daily_TER_avg_permonth
                                                  , StaticMethods.Get_email_receivers(dbContext, "Daily_TER_avg_permonth")
                                                  //new List<string> {"*****@*****.**"} //debug
                                                  , "Средневзвешенное ТЭР на тонну по циклам производства"
                                                  , msg
                                                  , attachment_data: excel_file.FileContents);
                }
                catch (Exception e)
                {
                    CustomExceptionHandler(e);
                }
            }
        }
예제 #2
0
		public void EvalReportInfo(ReportName reportName, ScaffoldContext context, ReportDates reportDates,
			int currShiftIndex=-1,
			int export_excel = 0,			
			string selectedSortOfProduction=null,
			string[] baseStrings=null,//хранится выгрузки в base64 рисунки графиков			
			Controller curr_controller = null
			)
		{
			//В некоторых случаях, вроде экспорта в эксель, можно использовать уже вычисленные данные
			if (
			#region IsNeedCachedDateForReport
				(this.Successfull
				&&(export_excel==1
					&&!ReportListForRebuildForExcel.Contains(reportName.Eng))//Некоторые отчёты требуют не округлённые данные для экселя, так что формируем их заново
					|| shiftsReportNames.Contains(reportName.Eng))//Или для смен
				&& this.ReportName != null
				&& reportName.Eng == this.ReportName.Eng
				&& this.ReportDates.StartDate == reportDates.StartDate
				&& this.ReportDates.EndDate == reportDates.EndDate
			#endregion
				)
			{
				//Данные по сменам формируются из списка смен в периоде, но выводится только одна, так что обновляем эти данные
				if (shiftsReportNames.Contains(reportName.Eng))
				{
					this.CurrShiftIndex = currShiftIndex;
					ReportDates.RecalcShiftsDate(this);//Пересчитываем края текущей смены					
				}
				if (baseStrings != null)
				{
					this.BaseStrings = baseStrings;
				}
				this.SelectedSortOfProduction = selectedSortOfProduction;
				return;
			}
			#region init var
			this.Successfull = false;
			this.stopwatch.Restart();


			this.CurrShiftIndex = currShiftIndex;
			this.ReportDates = reportDates;
			this.SelectedSortOfProduction = selectedSortOfProduction;
			this.BaseStrings = baseStrings;
			this.ReportName = reportName;
			
			this.Dbcontext = context;			
			this.Curr_controller = curr_controller;
			
			this.IsByDay = IsByDay_report_list.Contains(reportName.Eng);
			isBDM1 = BDM1_reports_list.Contains(reportName.Eng);
			this.PlaceName = isBDM1 ? "БДМ-1" : "БДМ-2";			
			placeId = isBDM1 ? 1:2;
			
			

			this.roundNum = 3;
			this.Sums = new Dictionary<string, double[]>();			
			this.Records_List = new Dictionary<string, List<object>>();
			this.Records = new List<object>();
			#endregion
			switch (reportName.Eng)//на основе названия отчёта дополнительные операции над записями
			{
				case "ConsumptionByCycleByBDM1"://БДМ-1 по видам продукции
				case "ConsumptionByCycleByBDM2"://БДМ-2 по видам продукции
				case "ConsumptionByBDM1ByDay"://БДМ-1(Суточный)
				case "ConsumptionByBDM2ByDay"://БДМ-2(Суточный)
											  //делаем итого для нужных категорий
											  //double[] sums = StaticMethods.Generate_sums(RecordsToShow_ConsumptionByCycleByBDM);
					Records = Form_records<ConsumptionByCycleOfProduction>("ConsumptionByCycle").Select(r=>(object)r).ToList();
					var t_sum = Sums_CycleOfProduction(Records.Select(r => (ISums_CycleOfProduction)r).ToList());
					if (t_sum!=null)
					{
						Sums.Add("ConsumptionByCycleByBDM", t_sum);
					}
					
					break;
				case "TERperMonthperTonne"://Средневзвешенное ТЭР на тонну по циклам производства
										   //В данном отчете ограничение по датам используется для ограничения SKU по которым выводить годовой отчет, год передается отдельно
					Records_List = new Dictionary<string, List<object>>();
					Records_List.Add("TERperMonthperTonne",Form_records<TERperMonthperTonne>("TERperMonthperTonne").Select(r => (object)r).ToList());
					Records_List.Add("TERperCycleperTonne", Form_records<TERperCycleperTonne>("TERperCycleperTonne").Select(r => (object)r).ToList());
					Records_List.Add("TER_Plan", Form_records<TERperMonthperTonne>("TER_Plan").Select(r => (object)r).ToList());
					break;
				case "EnergyConsumptionByManufactureByHour"://Часовой расход электроэнергии по производству
					#region case "EnergyConsumptionByManufactureByHour"

					//Задача для каждого поля для указного для подсчёта, посчитать данные в разрезе списка индификаторов в Constants.places
					//Довольно интересный алгоритм, позволяющий делать группировку по динамическому Id закреплённому за местами Constants.places
					// причем за одно место может быть закреленно несколько ID
					//Получаем в результате массив double, где индекс массива это индекс места в Constants.places
					// А сам массив содержит информацию в разрезе часа, по всем местам.
					var precompute_data = Form_records<EnergyConsumptionByManufactureByHour>();
					if (precompute_data == null || precompute_data.Count == 0)
					{
						break;
					}
					//Собираем id по которым будем считать итоговую сумму по производству(колонка итого:)
					List<int> total_sums_place_ids_EnergyConsumptionByManufactureByHour = new List<int>();

					Constants.places_total.Values.ToList()
						.ForEach(r =>
						{ total_sums_place_ids_EnergyConsumptionByManufactureByHour.AddRange(r); }
							);

					////строка итого, храним Dictionary<string, double> для поддержки и других видов ТЭР, газа, пара и т.д.
					//List<Dictionary<string, double>> sums_EnergyConsumptionByManufactureByHour = new List<Dictionary<string, double>>();
					//подсчитываем данные по местам
					//var data_EnergyConsumptionByManufactureByHour; //= new Dictionary<string, List<double>>();
					var field_name_EnergyConsumptionByManufactureByHour = "EnergyConsumption";
					
					Records= precompute_data
							.Select(r => ((IHaveMeasureDate)r).Measure_Date)
							.Distinct()
							.Select(Measure_Date => {

								var values = SumField_byPlaceId(field_name_EnergyConsumptionByManufactureByHour, precompute_data.Where(r => ((IHaveMeasureDate)r).Measure_Date == Measure_Date).Select(r=>(EnergyConsumptionByManufactureByHour)r) .ToList(), roundNum, total_sums_place_ids_EnergyConsumptionByManufactureByHour);

								return new Data_EnergyConsumptionByManufactureByHour
								{
									Date = Measure_Date.ToShortDateString(),
									Time = Measure_Date.ToShortTimeString(),
									Values = values//массив из double с показаниями за текущий слайс на время и дату
								};

							}).ToList<object>();

					//Добавляем строковые итоги
					//Нужно пробежатся по срезам по часам и посчитать итоговые данные по каждому месту
					//напомню что индекс в массиве data это индекс места массиве Constants.places_total
					var sums_row_EnergyConsumptionByManufactureByHour = new double[places.Count + 1];//разменость +1 потому что ещё считаем последную колонку итого
					var param_values = typeof(Data_EnergyConsumptionByManufactureByHour).GetProperty("Values");
					foreach (var data in Records)
					{

						var curr_data = (List<double>)param_values.GetValue(data);
						for (int i = 0; i < curr_data.Count; i++)
						{
							sums_row_EnergyConsumptionByManufactureByHour[i] += curr_data[i];
						}

					}
					Sums.Add("row_EnergyConsumptionByManufactureByHour", sums_row_EnergyConsumptionByManufactureByHour);
					break;
				#endregion
				case "EnergyConsumptionByDevicesByDay"://Суточный расход электроэнергии по учётам
				case "EnergyConsumptionByDevicesByHour"://Часовой расход электроэнергии по учётам
					#region EnergyConsumptionByDevicesBy
					Stopwatch tempWatch = new Stopwatch();
					tempWatch.Start();
					//отличия только в группировках между этими отчетами, так что формируем признак
					//EnergyConsumptionByDevices
					//Собираем записи для формирования вывода
					//Т.к список устройств динамический, то под него нельзя создать класс, так что делаем группировки по ходу
					Records  = Form_records<EnergyConsumptionByDevices>("EnergyConsumptionByDevicesByDay").Select(r => (object)r).ToList();
					tempWatch.Stop();
					//Для строки Итого:
					Sums.Add("EnergyConsumptionByDevices", 
							Records
							.Select(r=>(EnergyConsumptionByDevices)r)
							.GroupBy(r => r.Device_Name,
							(g, r) => Math.Round(r.Sum(e => e.EnergyConsumption ?? 0), 3))
							.Append(0)
							.ToArray());



					//Для колонки Итого по производству:
					Sums.Add("EnergyConsumptionByDevices_col_production",
							Records
							.Select(r => (EnergyConsumptionByDevices)r)					
							.Where(r => Constants.EnergyConsumptionByDevices_total_devices.ContainsKey(r.Device_Name))//итого для строк считаем только для определенных колонок
							.GroupBy(r => r.Measure_Date, (g, rs) => rs.Sum(r => r.EnergyConsumption) ?? 0).ToArray());
					//Добавляем сумму по производству
					Sums["EnergyConsumptionByDevices"][Sums["EnergyConsumptionByDevices"].Length-1] = (Sums["EnergyConsumptionByDevices_col_production"].Sum(r => r));

										
					break;
				#endregion
				case "ConsumptionByManufactureByPeriod"://общая по производству
					#region "ConsumptionByManufactureByPeriod"
					Records = Form_records<ConsumptionByManufactureByPeriod>().Select(r=>(object)r).ToList();
					
					//Подготавливаем лист id мест по которым будем считать данные для итогов
					List<int> total_sums_place_ids = new List<int>();					
					Constants.places_total.Values.ToList()
						.ForEach(r =>
						{ total_sums_place_ids.AddRange(r); }
							);

					//Задача для каждого поля для указного для подсчёта,
					//посчитать данные в разрезе списка индификаторов в Constants.places
					var fInfo_ConsumptionByManufactureByPeriod = typeof(ConsumptionByManufactureByPeriod).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
					Records_List = new Dictionary<string, List<object>>(Constants.fields_to_sum_ConsumptionByManufactureByPeriod.Count);
					foreach (var field_name in Constants.fields_to_sum_ConsumptionByManufactureByPeriod)
					{
						//подсчитываем данные по местам
						Records_List.Add(field_name, 
							SumField_byPlaceId(
								field_name,
								Records
								 .Select(r=>(ConsumptionByManufactureByPeriod)r)
								 .ToList(),
								roundNum,
								total_sums_place_ids)
							.Select(r=>(object)r)
							.ToList());
					}
					break;
				#endregion
				case "ConsumptionByBDM1ByHour"://БДМ-1(Часовой)
				case "ConsumptionByBDM2ByHour"://БДМ-2(Часовой)
					#region ConsumptionByBDMByHour
					Records = Form_records<ConsumptionByBDMbyHour>("ConsumptionByBDMByHour").Select(r=>(object)r).ToList();
					if (Records==null||Records.Count==0)
					{
						break;
					}
					//Из-за того что для вывода по часового мы берем сетку по часам,
					//а циклы могот заканчиватся и начинатся внутри часа, то на эти цикла происходит дублирование по параметрам, 
					//так что пробегаемся по записям и ищем такие случаи, и объединяем их в одну запись 

					//берем элементы по count-2 потому что сравниваем два элемента и последний не счем сравнивать
					var temp_recs = new List<ConsumptionByBDMbyHour>();
					for (int i = 0; i < Records.Count - 1; i++)
					{
						var curr = (IHaveComposition)Records.ElementAt(i);
						var next = (IHaveComposition)Records.ElementAt(i + 1);
						var excludeProp = new Dictionary<string, bool>() {["ID"]=false,["Composition"]=false};

						if (IsEqualPropValue(firstObject: curr, secondObject: next, excludePropList: excludeProp))
						{
							curr.Composition += ", " + next.Composition;
							i++;
						}
						temp_recs.Add((ConsumptionByBDMbyHour)curr);
					}
					Records = temp_recs.Select(r=>(object)r).ToList();
					//Для строки Итого:
					Sums.Add("ConsumptionByBDMByHour",

						value:
						//чтобы получить итого по записям, выделяем нужные столбцы и добаляем столбец по кторому будем вести группировку
						GetSumsAndAvgProp(
							Records.Select(r => (ConsumptionByBDMbyHour)r).ToList(), 
							propForSumList: tesSumList.ToDictionary(r => r, r => false),
							propForAvgList: tesAvgList.ToDictionary(r => r, r => false))
						 .Select(d => (double)(d??0.0)).ToArray());//распаковываем в дабл
					break;
				#endregion
				case "SkuDataByShifts_BDM1":
				case "SkuDataByShifts_BDM2":
					#region SkuDataByShifts
					var ter_list_shifts = Constants.ter_list_shifts;
					//нарезаем указный период на смены
					var shifts_list = new List<Shift>();
					int shift_index = 0;

					reportDates.CurrShiftStart = reportDates.CurrShiftStart.AddHours(-reportDates.ShiftLength);
					reportDates.CurrShiftEnd = reportDates.CurrShiftEnd.AddHours(-reportDates.ShiftLength);
					while (true)
					{
						if (reportDates.CurrShiftStart > DateTime.Now || reportDates.CurrShiftStart > reportDates.EndDate)//поледняя смена не должна выходить за текущюю дату или конец преиода
						{
							break;
						}
						else
						{
							shifts_list.Add(new Shift() { shift_start = reportDates.CurrShiftStart, shift_end = reportDates.CurrShiftEnd, shift_index = shift_index });
						}
						reportDates.CurrShiftStart = reportDates.CurrShiftStart.AddHours(reportDates.ShiftLength);
						reportDates.CurrShiftEnd = reportDates.CurrShiftEnd.AddHours(reportDates.ShiftLength);
						shift_index++;
					}

					var shiftStart = DateTime.Now;
					var shiftEnd = DateTime.Now;
					//если смена не выбрана(-1) то выводим последнию смену в нарезке, иначе выбраную смену
					if (shifts_list.Count > 0)
					{
						shiftStart = shifts_list[GetCurShiftIndex(currShiftIndex, shifts_list.Count)].shift_start;
						shiftEnd = shifts_list[GetCurShiftIndex(currShiftIndex, shifts_list.Count)].shift_end;
					}
					else
					{
						shiftStart = reportDates.CurrShiftStart;
						shiftEnd = reportDates.CurrShiftEnd;
					}

					reportDates.CurrShiftStart= shiftStart;
					reportDates.CurrShiftEnd = shiftEnd;

					Records_List.Add("SkuDataByShifts",
						Form_records<SkuDataByShifts>("SkuDataByShifts")						
						.OrderBy(r => r.CycleDateBegin)
						.Select(r=>(object)r)
						.ToList());
					var sku_list = Records_List["SkuDataByShifts"]
									.Select(r => ((IHaveSku)r).Sku)
									.ToList();


					Records_List.Add("Shifts_plan",  
						context.StgPlanTer
						 .Where(r => r.Year == shiftStart.Year
									&& r.Month == shiftStart.Month
									&& sku_list.Contains(r.Sku)
									&& r.PlaceId == (isBDM1 ? 1 : 2))
						 .Select(r=>(object)r)
						 .ToList());



					Records_List.Add("Shifts_index_list", shifts_list.Select(r => (object)r.shift_index.ToString()).ToList());
					Records_List.Add("Shifts_dates_list", shifts_list
															.Select(r => $"{r.shift_start.ToShortDateString()} {r.shift_start.ToShortTimeString()}-{r.shift_end.ToShortDateString()} {r.shift_end.ToShortTimeString()}")
															.Select(r=>(object)r)
															.ToList());
				
					//if (export_excel == 1)
					//{ return Excel_methods.Export_to_Excel_SkuDataByShifts(new ExcelExport(), report_name, shiftStart, shiftEnd, placeName: place_name, this, baseStrings, RecordsToShow_SkuDataByShifts, ter_list_shifts, shiftId: RecordsToShow_SkuDataByShifts.Count > 0 ? RecordsToShow_SkuDataByShifts.FirstOrDefault().ShiftId : 0, machinist_name: RecordsToShow_SkuDataByShifts.Count > 0 ? RecordsToShow_SkuDataByShifts.FirstOrDefault().Machinist_name : ""); }
					break;
				#endregion
				default:
					break;
			}
			//Если нужен список продуктов
			if (Records?.Count>0? Records?.FirstOrDefault().GetType().GetInterface("IListSortOfProd") != null:false)
			{
				ListSortOfProd = Records.OrderBy(m => ((IListSortOfProd)m).SortofProduction).Select(m => ((IListSortOfProd)m).SortofProduction).Distinct().ToArray();
				if (SelectedSortOfProduction != null && SelectedSortOfProduction != "All")
					Records = Records.Where(r => ((IListSortOfProd)r).SortofProduction == SelectedSortOfProduction).ToList();
			}
			//Округляем все поля
			RoundProps();
			this.Successfull = true;			
		}