diff --git a/DepartmentPortal/Common/CommonTools/Attributes/EntityDependencyAttribute.cs b/DepartmentPortal/Common/CommonTools/Attributes/EntityDependencyAttribute.cs
new file mode 100644
index 0000000..190f05f
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/Attributes/EntityDependencyAttribute.cs
@@ -0,0 +1,39 @@
+using System;
+
+namespace CommonTools.Attributes
+{
+ ///
+ /// Описание зависимости сущности от другой сущности (требуется для сохранения и загрузки данных)
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class EntityDependencyAttribute : Attribute
+ {
+ ///
+ /// Название класса от котрого зависит этот класс
+ ///
+ public string ClassName { get; set; }
+
+ ///
+ /// Название поле в этом классе, которое ссылает на другой класс (идентификатор)
+ ///
+ public string ColumnName { get; set; }
+
+ ///
+ /// Описание зависимости
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// Конструктор
+ ///
+ /// Название класса от котрого зависит этот класс
+ /// Название поле в этом классе, которое ссылает на другой класс (идентификатор)
+ /// Описание зависимости
+ public EntityDependencyAttribute(string className, string columnName, string description)
+ {
+ ClassName = className;
+ ColumnName = columnName;
+ Description = description;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/Attributes/EntityDescriptionAttribute.cs b/DepartmentPortal/Common/CommonTools/Attributes/EntityDescriptionAttribute.cs
new file mode 100644
index 0000000..746b2c9
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/Attributes/EntityDescriptionAttribute.cs
@@ -0,0 +1,32 @@
+using System;
+
+namespace CommonTools.Attributes
+{
+ ///
+ /// Описание класса из базы данных, его назначение
+ ///
+ [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
+ public class EntityDescriptionAttribute : Attribute
+ {
+ ///
+ /// Название сущности, которую описывает класс
+ ///
+ public string EntityName { get; set; }
+
+ ///
+ /// Описание назначения сущности
+ ///
+ public string Description { get; set; }
+
+ ///
+ /// Конструктор
+ ///
+ /// Название сущности, которую описывает класс
+ /// Описание назначения сущности
+ public EntityDescriptionAttribute(string entityName, string description)
+ {
+ EntityName = entityName;
+ Description = description;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/BindingModels/AccessBindingModel.cs b/DepartmentPortal/Common/CommonTools/BindingModels/AccessBindingModel.cs
new file mode 100644
index 0000000..8e6675d
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/BindingModels/AccessBindingModel.cs
@@ -0,0 +1,20 @@
+using System;
+
+namespace CommonTools.BindingModels
+{
+ ///
+ /// Информация для доступа к выполнению операций
+ ///
+ public class AccessBindingModel
+ {
+ ///
+ /// Пропускать проверку (работает только для получения данных)
+ ///
+ public bool SkipCheck { get; set; }
+
+ ///
+ /// Идентификатор пользователя, который запрашивает выполнение операции
+ ///
+ public Guid? UserId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/BindingModels/GetBinidingModel.cs b/DepartmentPortal/Common/CommonTools/BindingModels/GetBinidingModel.cs
new file mode 100644
index 0000000..86f430c
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/BindingModels/GetBinidingModel.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace CommonTools.BindingModels
+{
+ ///
+ /// Получение записи по идентификатору
+ ///
+ public class GetBinidingModel : AccessBindingModel
+ {
+ ///
+ /// Идентификатор получаемой записи
+ ///
+ public Guid? Id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/BindingModels/PageSettingBinidingModel.cs b/DepartmentPortal/Common/CommonTools/BindingModels/PageSettingBinidingModel.cs
new file mode 100644
index 0000000..8391343
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/BindingModels/PageSettingBinidingModel.cs
@@ -0,0 +1,23 @@
+namespace CommonTools.BindingModels
+{
+ ///
+ /// Пагинация для получения записей
+ ///
+ public class PageSettingBinidingModel : AccessBindingModel
+ {
+ ///
+ /// Номер страницы, которую получаем
+ ///
+ public int? PageNumber { get; set; }
+
+ ///
+ /// Количество записей возвращаемых
+ ///
+ public int? PageSize { get; set; }
+
+ ///
+ /// Иной признак, по которму отбираем записи
+ ///
+ public string PageName { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/BindingModels/SetBinidingModel.cs b/DepartmentPortal/Common/CommonTools/BindingModels/SetBinidingModel.cs
new file mode 100644
index 0000000..b05bcd5
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/BindingModels/SetBinidingModel.cs
@@ -0,0 +1,15 @@
+using System;
+
+namespace CommonTools.BindingModels
+{
+ ///
+ /// Сохранение записи по идентификатору
+ ///
+ public class SetBinidingModel : AccessBindingModel
+ {
+ ///
+ /// Идентификатор записи
+ ///
+ public Guid Id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/CommonTools.csproj b/DepartmentPortal/Common/CommonTools/CommonTools.csproj
new file mode 100644
index 0000000..f208d30
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/CommonTools.csproj
@@ -0,0 +1,7 @@
+
+
+
+ net5.0
+
+
+
diff --git a/DepartmentPortal/Common/CommonTools/Enums/ResultServiceStatusCode.cs b/DepartmentPortal/Common/CommonTools/Enums/ResultServiceStatusCode.cs
new file mode 100644
index 0000000..be03c80
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/Enums/ResultServiceStatusCode.cs
@@ -0,0 +1,38 @@
+namespace CommonTools.Enums
+{
+ ///
+ /// Статус результата операции
+ ///
+ public enum ResultServiceStatusCode
+ {
+ ///
+ /// Успешно
+ ///
+ Success = 200,
+
+ ///
+ /// Ошибка общая
+ ///
+ Error = 400,
+
+ ///
+ /// Элемент уже сущствует
+ ///
+ ExsistItem = 401,
+
+ ///
+ /// Запись удалена
+ ///
+ WasDelete = 402,
+
+ ///
+ /// Не найдено
+ ///
+ NotFound = 404,
+
+ ///
+ /// Не найден файл
+ ///
+ FileNotFound = 405
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/Extensions/OperationResultExtensions.cs b/DepartmentPortal/Common/CommonTools/Extensions/OperationResultExtensions.cs
new file mode 100644
index 0000000..cee511d
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/Extensions/OperationResultExtensions.cs
@@ -0,0 +1,66 @@
+using CommonTools.Enums;
+using CommonTools.OperationResultModels;
+using System;
+
+namespace CommonTools.Extensions
+{
+ ///
+ /// Расширения для результата операции
+ ///
+ public static class OperationResultExtensions
+ {
+ ///
+ /// Добавление простой ошибки
+ ///
+ ///
+ ///
+ ///
+ public static void AddError(this OperationResultModel model, string key, string value) => model.AddError(key, value, ResultServiceStatusCode.Error);
+
+ ///
+ /// Добавление простой ошибки со сменой статуса
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void AddError(this OperationResultModel model, string key, string error, ResultServiceStatusCode statusCode)
+ {
+ model.Errors.Add((key, error));
+ model.StatusCode = statusCode;
+ }
+
+ ///
+ /// Добавление ошибки
+ ///
+ ///
+ ///
+ public static void AddError(this OperationResultModel model, Exception error) => model.AddError(error, ResultServiceStatusCode.Error);
+
+ ///
+ /// Добавление ошибки
+ ///
+ ///
+ ///
+ ///
+ public static void AddError(this OperationResultModel model, Exception error, ResultServiceStatusCode statusCode) => model.AddError("Ошибка", error, statusCode);
+
+ ///
+ /// Добавление ошибки (включая вложеннные)
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static void AddError(this OperationResultModel model, string key, Exception error, ResultServiceStatusCode statusCode)
+ {
+ model.Errors.Add((key, error.Message));
+ while (error.InnerException != null)
+ {
+ error = error.InnerException;
+ model.Errors.Add(("Inner error:", error.Message));
+ }
+ model.StatusCode = statusCode;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/OperationResultModels/OperationResultModel.cs b/DepartmentPortal/Common/CommonTools/OperationResultModels/OperationResultModel.cs
new file mode 100644
index 0000000..93d1616
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/OperationResultModels/OperationResultModel.cs
@@ -0,0 +1,79 @@
+using CommonTools.Enums;
+using CommonTools.ViewModels;
+using System.Collections.Generic;
+
+namespace CommonTools.OperationResultModels
+{
+ ///
+ /// Результат любой операции
+ ///
+ public class OperationResultModel
+ {
+ ///
+ /// Успешность операции (количество ошибок = 0)
+ ///
+ public bool IsSucceeded => Errors.Count == 0;
+
+ ///
+ /// Статус операции
+ ///
+ public ResultServiceStatusCode StatusCode { get; set; }
+
+ ///
+ /// Спсиок ошибок
+ ///
+ public List<(string Title, string Message)> Errors { get; private set; }
+
+ ///
+ /// Какой-то объект, получаемый по результатам операции (например, id)
+ ///
+ public object Result { get; private set; }
+
+ ///
+ /// Конструктор по умолчанию
+ ///
+ public OperationResultModel()
+ {
+ Errors = new List<(string Title, string Message)>();
+ StatusCode = ResultServiceStatusCode.Success;
+ }
+ }
+
+ ///
+ /// Результат любой операции
+ ///
+ ///
+ public class OperationResultModel
+ where T : ElementViewModel
+ {
+ ///
+ /// Успешность операции
+ ///
+ public bool IsSucceeded { get; private set; }
+
+ ///
+ /// Статус операции
+ ///
+ public ResultServiceStatusCode StatusCode { get; private set; }
+
+ ///
+ /// Спсиок ошибок
+ ///
+ public List> Errors { get; private set; }
+
+ ///
+ /// Какой-то объект, получаемый по результатам операции (например, id)
+ ///
+ public T Result { get; private set; }
+
+ ///
+ /// Конструктор по умолчанию
+ ///
+ public OperationResultModel()
+ {
+ Errors = new List>();
+ IsSucceeded = true;
+ StatusCode = 0;
+ }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/ViewModels/ElementViewModel.cs b/DepartmentPortal/Common/CommonTools/ViewModels/ElementViewModel.cs
new file mode 100644
index 0000000..1106ed9
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/ViewModels/ElementViewModel.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace CommonTools.ViewModels
+{
+ ///
+ /// Возвращаемая запись
+ ///
+ public class ElementViewModel
+ {
+ public Guid Id { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/Common/CommonTools/ViewModels/ListViewModel.cs b/DepartmentPortal/Common/CommonTools/ViewModels/ListViewModel.cs
new file mode 100644
index 0000000..64d6940
--- /dev/null
+++ b/DepartmentPortal/Common/CommonTools/ViewModels/ListViewModel.cs
@@ -0,0 +1,16 @@
+using System.Collections.Generic;
+
+namespace CommonTools.ViewModels
+{
+ ///
+ /// Список возвращаемых значений
+ ///
+ ///
+ public class ListViewModel
+ where T : ElementViewModel
+ {
+ public int MaxCount { get; set; }
+
+ public List List { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/DepartmentPortal/DepartmentPortal.sln b/DepartmentPortal/DepartmentPortal.sln
new file mode 100644
index 0000000..822b3d2
--- /dev/null
+++ b/DepartmentPortal/DepartmentPortal.sln
@@ -0,0 +1,30 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31112.23
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{6F154F8D-3437-45EE-9D89-02B96BDF3E8E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonTools", "Common\CommonTools\CommonTools.csproj", "{9E533D43-452A-40D6-852B-01E8391BBFF9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {9E533D43-452A-40D6-852B-01E8391BBFF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9E533D43-452A-40D6-852B-01E8391BBFF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9E533D43-452A-40D6-852B-01E8391BBFF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9E533D43-452A-40D6-852B-01E8391BBFF9}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {9E533D43-452A-40D6-852B-01E8391BBFF9} = {6F154F8D-3437-45EE-9D89-02B96BDF3E8E}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FBA0CB49-EF2D-4538-9D00-FCEDA24879A9}
+ EndGlobalSection
+EndGlobal