460 lines
18 KiB
C#
460 lines
18 KiB
C#
using CoreModels.Enums.Department;
|
||
using DatabaseCore;
|
||
using DatabaseCore.Models.Department;
|
||
using DepartmentBusinessLogic.BindingModels;
|
||
using DepartmentBusinessLogic.Interfaces;
|
||
using DepartmentBusinessLogic.ViewModels;
|
||
using DepartmentDatabaseImplementation.Models;
|
||
using Microsoft.EntityFrameworkCore;
|
||
using ModuleTools.Enums;
|
||
using ModuleTools.Extensions;
|
||
using ModuleTools.Models;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Xml.Linq;
|
||
|
||
namespace DepartmentDatabaseImplementation.Implementations
|
||
{
|
||
/// <summary>
|
||
/// Реализация IAcademicPlanService
|
||
/// </summary>
|
||
public class AcademicPlanService :
|
||
AbstractGenerticEntityService<AcademicPlanGetBindingModel, AcademicPlanSetBindingModel, AcademicPlan, AcademicPlanListViewModel, AcademicPlanViewModel>,
|
||
IAcademicPlanService
|
||
{
|
||
protected override OperationResultModel AdditionalCheckingWhenAdding(DbContext context, AcademicPlanSetBindingModel model) => OperationResultModel.Success(null);
|
||
|
||
protected override OperationResultModel AdditionalCheckingWhenDeleting(DbContext context, AcademicPlan entity, AcademicPlanGetBindingModel model) => OperationResultModel.Success(null);
|
||
|
||
protected override IQueryable<AcademicPlan> AdditionalCheckingWhenReadingList(IQueryable<AcademicPlan> 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<AcademicPlanRecord>().Where(x => x.AcademicPlanId == model.Id);
|
||
foreach (var record in records)
|
||
{
|
||
var hours = context.Set<AcademicPlanRecordTimeNormHour>().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, DbContext context) => context.Set<AcademicPlan>().FirstOrDefault(x => x.EducationDirectionId == model.EducationDirectionId && x.YearEntrance == model.YearEntrance && x.Id != model.Id);
|
||
|
||
protected override IQueryable<AcademicPlan> IncludingWhenReading(IQueryable<AcademicPlan> query) => query.Include(x => x.EducationDirection);
|
||
|
||
protected override IQueryable<AcademicPlan> OrderingWhenReading(IQueryable<AcademicPlan> query) => query.OrderBy(x => x.EducationDirection.Cipher).ThenBy(x => x.YearEntrance);
|
||
|
||
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<string, decimal>();
|
||
|
||
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)
|
||
{
|
||
return OperationResultModel.Error("ошибка", $"Не найдена родительская дисциплина с кодом {parentValue}", ResultServiceStatusCode.NotFound);
|
||
}
|
||
|
||
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<TimeNorm>();
|
||
// если перед нами практика, то выбираем только один нужный тип нагрузки
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
} |