using CoreDatabase; using CoreDatabase.Models.Department; using CoreModels.Enums.Department; using DepartmentContract.BindingModels; using DepartmentContract.Services.IGenericEntityService; using DepartmentContract.ViewModels; using DepartmentDatabaseImplementation.Models; using Microsoft.EntityFrameworkCore; using System; using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using ToolsModule.ManagmentEntity; using ToolsModule.ManagmentExtension; namespace DepartmentDatabaseImplementation.Implementations.AbstractGenerticEntityService { /// /// Реализация IAcademicPlanService /// public class AcademicPlanService : AbstractGenerticEntityService, IAcademicPlanService { protected override OperationResultModel AdditionalCheckingWhenAdding(DbContext context, AcademicPlanSetBindingModel model) => OperationResultModel.Success(null); protected override OperationResultModel AdditionalCheckingWhenDeleting(DbContext context, AcademicPlan entity, AcademicPlanGetBindingModel model) { if (context.Set().Any(x => x.AcademicPlanId == model.Id && x.AcademicCourse != AcademicCourse.Неопределен)) { return OperationResultModel.Error("Error:", "Есть учебные группы, относящиеся к этому учебному плану", ResultServiceStatusCode.ExsistItem); } return OperationResultModel.Success(null); } protected override IQueryable AdditionalCheckingWhenReadingList(IQueryable query, AcademicPlanGetBindingModel model) { if (model.EducationDirectionId.HasValue) { query = query.Where(x => x.EducationDirectionId == model.EducationDirectionId.Value); } return query; } protected override OperationResultModel AdditionalCheckingWhenUpdateing(DbContext context, AcademicPlanSetBindingModel model) => OperationResultModel.Success(null); protected override void AdditionalDeleting(DbContext context, AcademicPlan entity, AcademicPlanGetBindingModel model) { var records = context.Set().Where(x => x.AcademicPlanId == model.Id); foreach (var record in records) { var hours = context.Set().Where(x => x.AcademicPlanRecordId == record.Id); foreach (var hour in hours) { hour.IsDeleted = true; hour.DateDelete = DateTime.Now; } context.SaveChanges(); record.IsDeleted = true; record.DateDelete = DateTime.Now; } context.SaveChanges(); } protected override AcademicPlan GetUniqueEntity(AcademicPlanSetBindingModel model, IQueryable query) => query.FirstOrDefault(x => x.EducationDirectionId == model.EducationDirectionId && x.YearStart == model.YearStart && x.Id != model.Id); protected override IQueryable IncludingWhenReading(IQueryable query) => query.Include(x => x.EducationDirection); protected override IQueryable OrderingWhenReading(IQueryable query) => query.OrderBy(x => x.EducationDirection.Cipher).ThenBy(x => x.YearStart); protected override bool AdditionalCheckForSingleGet(AcademicPlanGetBindingModel model) { if (model.EducationDirectionShortName.IsNotEmpty() && model.Year.HasValue) { return true; } return base.AdditionalCheckForSingleGet(model); } protected override AcademicPlan GetSingleRecord(IQueryable list, AcademicPlanGetBindingModel model) { if (model.EducationDirectionShortName.IsNotEmpty() && model.Year.HasValue) { return list.FirstOrDefault(x => x.EducationDirection.ShortName == model.EducationDirectionShortName && x.YearStart == model.Year); } return base.GetSingleRecord(list, model); } public OperationResultModel LoadPlx(AcademicPlanLoadPlxModel model) { using var context = DatabaseManager.GetContext; using var transaction = context.Database.BeginTransaction(); var result = new OperationResultModel(); try { #region Получаем настройки //Получаем номер кафедры var kafedraNumber = context.EnviromentSettings.FirstOrDefault(x => x.Key == "Кафедра"); if (kafedraNumber == null) { throw new Exception("Настройки среды. Не найден ключ Кафедра"); } #endregion var academicPlan = context.AcademicPlans.Include(x => x.EducationDirection).FirstOrDefault(x => x.Id == model.AcademicPlanId && !x.IsDeleted && x.EducationDirectionId.HasValue); if (academicPlan == null) { return OperationResultModel.Error("Error:", "Учебный план не найден", ResultServiceStatusCode.NotFound); } #region помечаем как удаленные все записи плана, потом все найденные восстановим var aprs = context.AcademicPlanRecords.Where(x => x.AcademicPlanId == academicPlan.Id).ToList(); foreach (var apr in aprs) { var apres = context.AcademicPlanRecordTimeNormHours.Where(x => x.AcademicPlanRecordId == apr.Id); foreach (var apre in apres) { apre.IsDeleted = true; apre.DateDelete = DateTime.Now; } apr.IsDeleted = true; apr.DateDelete = DateTime.Now; context.SaveChanges(); } #endregion var xml = XDocument.Load(model.FileName)?.Element("Документ")?.Elements()?.Elements()?.Elements(); if (xml != null) { var plxModel = new ParsPlxModel { AcademicPlanId = academicPlan.Id, BlockTypes = new(), DisicplineTypes = new(), DisciplineBlocks = new(), TimeNorms = new(), Practics = new(), Hours = new(), Disciplines = new() }; #region СправочникВидОбъекта - виды дисциплин - базовая, алтернативная и т.п. foreach (var elem in xml.Where(x => x.Name.LocalName == "СправочникВидОбъекта")) { plxModel.DisicplineTypes.Add((TypeName: elem.Attribute("Наименование").Value, Code: elem.Attribute("Код").Value)); } #endregion #region ПланыЦиклы foreach (var elem in xml.Where(x => x.Name.LocalName == "ПланыЦиклы")) { plxModel.BlockTypes.Add(new BlueAsteriskBlockType { Identificator = elem.Attribute("Идентификатор").Value, Code = elem.Attribute("Код").Value, BlockName = elem.Attribute("Цикл").Value, IsFacultative = Convert.ToBoolean(elem.Attribute("Факультативы").Value) }); } #endregion #region СправочникТипОбъекта - блоки дисциплин foreach (var elem in xml.Where(x => x.Name.LocalName == "СправочникТипОбъекта")) { var disciplineBlock = context.DisciplineBlocks.FirstOrDefault(x => x.DisciplineBlockBlueAsteriskName == elem.Attribute("Название").Value); if (disciplineBlock != null) { plxModel.DisciplineBlocks.Add(( Code: elem.Attribute("Код").Value, Entity: disciplineBlock )); } } #endregion #region СправочникВидыРабот - нормы времени foreach (var elem in xml.Where(x => x.Name.LocalName == "СправочникВидыРабот")) { if (!plxModel.TimeNorms.Exists(x => x.Code == elem.Attribute("Код").Value)) { var timeNorms = context.TimeNorms.Where(x => x.KindOfLoadBlueAsteriskName == elem.Attribute("Название").Value); foreach (var tn in timeNorms) { plxModel.TimeNorms.Add(( Code: elem.Attribute("Код").Value, Entity: tn )); } } } #endregion #region СправочникВидыПрактик - нормы времени (практики) foreach (var elem in xml.Where(x => x.Name.LocalName == "СправочникВидыПрактик")) { if (!plxModel.Practics.Exists(x => x.Code == elem.Attribute("Код").Value)) { var timeNorms = context.TimeNorms.Where(x => x.KindOfLoadBlueAsteriskPracticName == elem.Attribute("Наименование").Value); foreach (var tn in timeNorms) { plxModel.Practics.Add(( Code: elem.Attribute("Код").Value, Entity: tn )); } } } #endregion #region ПланыНовыеЧасы - часы по дисциплинам var attributeNames = plxModel.TimeNorms.Select(x => x.Entity.KindOfLoadBlueAsteriskAttributeName).Distinct(); foreach (var elem in xml.Where(x => x.Name.LocalName == "ПланыНовыеЧасы")) { var objectCode = elem.Attribute("КодОбъекта")?.Value; if (objectCode.IsEmpty()) { throw new Exception(string.Format("Не найден атрибут КодОбъекта")); } var timeNormCode = elem.Attribute("КодВидаРаботы")?.Value; if (timeNormCode.IsEmpty()) { throw new Exception(string.Format("Не найден атрибут КодВидаРаботы")); } var attributeKurs = elem.Attribute("Курс")?.Value; if (attributeKurs.IsEmpty()) { throw new Exception(string.Format("Не найдена атрибут Курс")); } var attributeSemester = elem.Attribute("Семестр")?.Value; if (attributeSemester.IsEmpty()) { throw new Exception(string.Format("Не найдена атрибут Семестр")); } var semester = attributeKurs switch { "1" => (attributeSemester == "1") ? Semester.Первый : Semester.Второй, "2" => (attributeSemester == "1") ? Semester.Третий : Semester.Четвертый, "3" => (attributeSemester == "1") ? Semester.Пятый : Semester.Шестой, "4" => (attributeSemester == "1") ? Semester.Седьмой : Semester.Восьмой, _ => Semester.Первый, }; var hours = new Dictionary(); foreach (var attr in attributeNames) { if (attr.IsNotEmpty()) { var hour = elem.Attribute(attr)?.Value; if (hour.IsNotEmpty() && !hours.ContainsKey(attr)) { if (decimal.TryParse(hour, out decimal h)) { hours.Add(attr, h); } else { if (hour.Contains('.')) { hour = hour.Replace('.', ','); } else if (hour.Contains(',')) { hour = hour.Replace(',', '.'); } if (decimal.TryParse(hour, out h)) { hours.Add(attr, h); } } } } } plxModel.Hours.Add(( DisciplineCode: objectCode, TimeNormCode: timeNormCode, Semester: semester, plxModel.TimeNorms.FirstOrDefault(x => x.Code == timeNormCode).Entity, Hours: hours )); } #endregion #region ПланыСтроки - сами записи учебного плана foreach (var elem in xml.Where(x => x.Name.LocalName == "ПланыСтроки")) { #region получение дисциплины var disciplineBlock = plxModel.DisciplineBlocks.FirstOrDefault(x => x.Code == elem.Attribute("ТипОбъекта")?.Value).Entity; if (disciplineBlock == null) { return OperationResultModel.Error("ошибка", $"Не найден блок дисциплин с кодом {elem.Attribute("ТипОбъекта")?.Value}", ResultServiceStatusCode.NotFound); } var disciplineName = elem.Attribute("Дисциплина")?.Value; // ищем по названию в планах дисциплину var discipline = context.Disciplines.FirstOrDefault(x => x.DisciplineBlueAsteriskName == disciplineName); if (discipline == null) { // ищем по названию дисциплину discipline = context.Disciplines.FirstOrDefault(x => x.DisciplineName == disciplineName); if (discipline == null) { discipline = new Discipline { DisciplineName = disciplineName, DisciplineBlockId = disciplineBlock.Id, DisciplineBlueAsteriskName = disciplineName }; context.Disciplines.Add(discipline); context.SaveChanges(); } else { discipline.DisciplineBlueAsteriskName = disciplineName; context.SaveChanges(); } } plxModel.Discipline = ( Code: elem.Attribute("Код")?.Value, Practic: elem.Attribute("ВидПрактики")?.Value, Entity: discipline ); plxModel.Disciplines.Add(plxModel.Discipline); #endregion //смотрим код кафедры bool inKafedra = elem.Attribute("КодКафедры")?.Value == kafedraNumber.Value; bool isFacultative = elem.Attribute("ДисциплинаКод")?.Value?.StartsWith("ФТД") ?? false; var zet = elem.Attribute("ЗЕТфакт")?.Value; // вытаскиваем часы по дисциплине foreach (var hour in plxModel.Hours.Where(x => x.DisciplineCode == plxModel.Discipline.Code)) { #region Родитель AcademicPlanRecord parent = null; var parentValue = elem.Attribute("КодРодителя")?.Value; if (parentValue.IsNotEmpty()) { var parentDiscipilne = plxModel.Disciplines.FirstOrDefault(x => x.Code == parentValue); if (parentDiscipilne != default) { parent = context.AcademicPlanRecords.FirstOrDefault(apr => apr.AcademicPlanId == model.AcademicPlanId && apr.DisciplineId == parentDiscipilne.Entity.Id && apr.Semester == hour.Semester); if (parent == null) { // возмжно, родитель будет описан позже, заполняем данными дочернего класса пока что parent = new AcademicPlanRecord { AcademicPlanId = model.AcademicPlanId, DisciplineId = parentDiscipilne.Entity.Id, InDepartment = inKafedra, Semester = hour.Semester, Zet = zet.IsNotEmpty() ? Convert.ToInt32(zet) : 0, IsParent = true, IsFacultative = isFacultative }; context.AcademicPlanRecords.Add(parent); context.SaveChanges(); } else if (parent.IsDeleted) { parent.IsDeleted = false; parent.DateDelete = null; context.SaveChanges(); } if (!parent.IsParent) { parent.IsParent = true; context.SaveChanges(); } } } #endregion #region Запись учебного плана var record = context.AcademicPlanRecords.FirstOrDefault(apr => apr.AcademicPlanId == model.AcademicPlanId && apr.DisciplineId == discipline.Id && apr.Semester == hour.Semester); if (record == null) { record = new AcademicPlanRecord { AcademicPlanId = model.AcademicPlanId, DisciplineId = discipline.Id, Zet = zet.IsNotEmpty() ? Convert.ToInt32(zet) : 0, Semester = hour.Semester, AcademicPlanRecordParentId = parent?.Id, IsParent = false, IsFacultative = isFacultative, InDepartment = inKafedra }; context.AcademicPlanRecords.Add(record); context.SaveChanges(); } else if (record.IsDeleted) { record.IsDeleted = false; record.DateDelete = null; context.SaveChanges(); } #endregion #region if (record != null) { var timeNorms = new List(); // если перед нами практика, то выбираем только один нужный тип нагрузки if (plxModel.Discipline.Practic.IsNotEmpty()) { timeNorms.AddRange(plxModel.Practics.Where(x => x.Code == hour.TimeNormCode && x.Entity.DisciplineBlockId == plxModel.Discipline.Entity.DisciplineBlockId && (!x.Entity.TimeNormEducationDirectionQualification.HasValue || x.Entity.TimeNormEducationDirectionQualification == academicPlan.EducationDirection.Qualification) && x.Code == plxModel.Discipline.Practic).Select(x => x.Entity)); } else { timeNorms.AddRange(plxModel.TimeNorms.Where(x => x.Code == hour.TimeNormCode && x.Entity.DisciplineBlockId == plxModel.Discipline.Entity.DisciplineBlockId && (!x.Entity.TimeNormEducationDirectionQualification.HasValue || x.Entity.TimeNormEducationDirectionQualification == academicPlan.EducationDirection.Qualification)).Select(x => x.Entity)); } foreach (var timeNorm in timeNorms) { decimal planHours = 1; if (timeNorm.KindOfLoadBlueAsteriskAttributeName.IsNotEmpty()) { if (!hour.Hours.ContainsKey(timeNorm.KindOfLoadBlueAsteriskAttributeName)) { return OperationResultModel.Error("ошибка", $"Не найдена атрибут {timeNorm.KindOfLoadBlueAsteriskAttributeName} по дисциплине с кодом {plxModel.Discipline.Code}", ResultServiceStatusCode.NotFound); } planHours = Math.Abs(hour.Hours[timeNorm.KindOfLoadBlueAsteriskAttributeName]); } var recordelement = context.AcademicPlanRecordTimeNormHours.FirstOrDefault(apre => apre.AcademicPlanRecordId == record.Id && apre.TimeNormId == timeNorm.Id); if (recordelement == null) { context.AcademicPlanRecordTimeNormHours.Add(new AcademicPlanRecordTimeNormHour { AcademicPlanRecordId = record.Id, TimeNormId = timeNorm.Id, PlanHours = planHours }); } else { if (recordelement.IsDeleted) { recordelement.IsDeleted = false; recordelement.DateDelete = null; } recordelement.PlanHours = planHours; } context.SaveChanges(); } } #endregion } } #endregion } transaction.Commit(); return result; } catch (Exception ex) { transaction.Rollback(); return OperationResultModel.Error(ex, ResultServiceStatusCode.Error); } } } }