From c2abb00ba33a5476a4e561ccf12dd7f3b51c112e Mon Sep 17 00:00:00 2001 From: Yourdax Date: Tue, 30 Apr 2024 22:20:33 +0400 Subject: [PATCH] + not full BusinessLogic need to check database --- DiningRoom/DiningRoom.sln | 6 + .../BusinessLogics/ComponentLogic.cs | 108 ++++++++++++ .../BusinessLogics/OrderLogic.cs | 162 ++++++++++++++++++ .../BusinessLogics/ProductLogic.cs | 108 ++++++++++++ .../BusinessLogics/UserLogic.cs | 138 +++++++++++++++ .../DiningRoomBusinessLogic.csproj | 17 ++ .../StorageContracts/IUserStorage.cs | 3 +- .../Implements/UserStorage.cs | 15 +- .../Models/User.cs | 21 ++- 9 files changed, 570 insertions(+), 8 deletions(-) create mode 100644 DiningRoom/DiningRoomBusinessLogic/BusinessLogics/ComponentLogic.cs create mode 100644 DiningRoom/DiningRoomBusinessLogic/BusinessLogics/OrderLogic.cs create mode 100644 DiningRoom/DiningRoomBusinessLogic/BusinessLogics/ProductLogic.cs create mode 100644 DiningRoom/DiningRoomBusinessLogic/BusinessLogics/UserLogic.cs create mode 100644 DiningRoom/DiningRoomBusinessLogic/DiningRoomBusinessLogic.csproj diff --git a/DiningRoom/DiningRoom.sln b/DiningRoom/DiningRoom.sln index 6017c79..4802270 100644 --- a/DiningRoom/DiningRoom.sln +++ b/DiningRoom/DiningRoom.sln @@ -11,6 +11,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiningRoomDataModels", "Din EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiningRoomDatabaseImplement", "DiningRoomDatabaseImplement\DiningRoomDatabaseImplement.csproj", "{348BD2CC-C93D-42E8-A890-FC7807476625}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiningRoomBusinessLogic", "DiningRoomBusinessLogic\DiningRoomBusinessLogic.csproj", "{89A8AB71-ADD4-405D-AE0B-03ACB1A1BF24}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -33,6 +35,10 @@ Global {348BD2CC-C93D-42E8-A890-FC7807476625}.Debug|Any CPU.Build.0 = Debug|Any CPU {348BD2CC-C93D-42E8-A890-FC7807476625}.Release|Any CPU.ActiveCfg = Release|Any CPU {348BD2CC-C93D-42E8-A890-FC7807476625}.Release|Any CPU.Build.0 = Release|Any CPU + {89A8AB71-ADD4-405D-AE0B-03ACB1A1BF24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89A8AB71-ADD4-405D-AE0B-03ACB1A1BF24}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89A8AB71-ADD4-405D-AE0B-03ACB1A1BF24}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89A8AB71-ADD4-405D-AE0B-03ACB1A1BF24}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/ComponentLogic.cs b/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/ComponentLogic.cs new file mode 100644 index 0000000..ebafcc8 --- /dev/null +++ b/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/ComponentLogic.cs @@ -0,0 +1,108 @@ +using DiningRoomContracts.BindingModels; +using DiningRoomContracts.BusinessLogicContracts; +using DiningRoomContracts.SearchModels; +using DiningRoomContracts.StorageContracts; +using DiningRoomContracts.ViewModels; +using Microsoft.Extensions.Logging; + + +namespace DiningRoomBusinessLogic.BusinessLogics +{ + public class ComponentLogic : IComponentLogic + { + private readonly ILogger _logger; + private readonly IComponentStorage _componentStorage; + public ComponentLogic(ILogger logger, IComponentStorage componentStorage) + { + _logger = logger; + _componentStorage = componentStorage; + } + public List? ReadList(ComponentSearchModel? model) + { + _logger.LogInformation("ReadList. ComponentName:{ComponentName}. Id:{ Id}", model?.ComponentName, model?.Id); + var list = model == null ? _componentStorage.GetFullList() : _componentStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count:{Count}", list.Count); + return list; + } + public ComponentViewModel? ReadElement(ComponentSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. ComponentName:{ComponentName}. Id:{ Id}", model.ComponentName, model.Id); + var element = _componentStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); + return element; + } + public bool Create(ComponentBindingModel model) + { + CheckModel(model); + if (_componentStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + public bool Update(ComponentBindingModel model) + { + CheckModel(model); + if (_componentStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + public bool Delete(ComponentBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id:{Id}", model.Id); + if (_componentStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + private void CheckModel(ComponentBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.ComponentName)) + { + throw new ArgumentNullException("Нет названия продукта", nameof(model.ComponentName)); + } + if (model.Cost <= 0) + { + throw new ArgumentNullException("Цена продукта должна быть больше 0", nameof(model.Cost)); + } + _logger.LogInformation("Component. ComponentName:{ComponentName}. Cost:{ Cost}. Id: { Id}", model.ComponentName, model.Cost, model.Id); + var element = _componentStorage.GetElement(new ComponentSearchModel + { + ComponentName = model.ComponentName + }); + if (element != null && element.Id != model.Id) + { + throw new InvalidOperationException("Продукт с таким названием уже есть"); + } + } + } +} diff --git a/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/OrderLogic.cs b/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/OrderLogic.cs new file mode 100644 index 0000000..f0c2dc3 --- /dev/null +++ b/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/OrderLogic.cs @@ -0,0 +1,162 @@ +using DiningRoomContracts.BindingModels; +using DiningRoomContracts.BusinessLogicContracts; +using DiningRoomContracts.SearchModels; +using DiningRoomContracts.StorageContracts; +using DiningRoomContracts.ViewModels; +using DiningRoomDataModels.Enums; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiningRoomBusinessLogic.BusinessLogics +{ + public class OrderLogic : IOrderLogic + { + private readonly ILogger _logger; + //Хранение всех заказов + private readonly IOrderStorage _orderStorage; + + public OrderLogic(ILogger logger, IOrderStorage orderStorage) + { + _logger = logger; + _orderStorage = orderStorage; + } + + public List? ReadList(OrderSearchModel? model) + { + //model.UserId = -1 для swagger, чтобы можно было считать все заказы всех пользователей + var list = (model == null || model.UserId == -1) ? _orderStorage.GetFullList() : _orderStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count:{Count}", list.Count); + return list; + } + + + public OrderViewModel? ReadElement(OrderSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + var element = _orderStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement order not found"); + return null; + } + _logger.LogInformation("ReadElement order found. Id:{Id}", element.Id); + return element; + } + + private void CheckModel(OrderBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (model.DateCreate > DateTime.Now) + { + throw new ArgumentException($"Дата создания заказа {model.DateCreate} не может быть в будущем"); + } + } + + public bool Create(OrderBindingModel model) + { + CheckModel(model); + model.Status = OrderStatus.Принят; + if (_orderStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + + } + + + public bool Update(OrderBindingModel model) + { + CheckModel(model, false); + var order = _orderStorage.GetElement(new OrderSearchModel { Id = model.Id }); + if (order == null) + { + throw new ArgumentNullException(nameof(order)); + } + if (_orderStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + + public bool Delete(OrderBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id:{Id}", model.Id); + if (_orderStorage.Delete(model) == null) + { + _logger.LogWarning("Delete order operation failed"); + return false; + } + return true; + } + + + private bool ChangeStatus(OrderBindingModel model, OrderStatus newStatus) + { + CheckModel(model, false); + var order = _orderStorage.GetElement(new OrderSearchModel { Id = model.Id }); + if (order == null) + { + throw new ArgumentNullException(nameof(order)); + } + if (newStatus - model.Status == 1) + { + model.Status = newStatus; + + if (_orderStorage.Update(model) == null) + { + _logger.LogWarning("Update order operation failed"); + return false; + } + return true; + } + if (order.Status + 1 != newStatus) + { + _logger.LogWarning("Change status operation failed. Incorrect new status: {newStatus}. Current status: {currStatus}", newStatus, order.Status); + return false; + } + _logger.LogWarning("Changing status operation faled: current:{Status}: required:{newStatus}.", model.Status, newStatus); + throw new ArgumentException($"Невозможно присвоить статус {newStatus} заказу с текущим статусом {model.Status}"); + } + + //Перевод заказа в состояние выполнения + public bool TakeOrderInWork(OrderBindingModel model) + { + return ChangeStatus(model, OrderStatus.Выполняется); + } + + //Перевод заказа в состояние готовности + public bool FinishOrder(OrderBindingModel model) + { + return ChangeStatus(model, OrderStatus.Готов); + } + //Перевод заказа в состояние выдачи (окончательное завершение) + public bool DeliveryOrder(OrderBindingModel model) + { + return ChangeStatus(model, OrderStatus.Выдан); + } + } +} diff --git a/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/ProductLogic.cs b/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/ProductLogic.cs new file mode 100644 index 0000000..3fc0375 --- /dev/null +++ b/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/ProductLogic.cs @@ -0,0 +1,108 @@ +using DiningRoomContracts.BindingModels; +using DiningRoomContracts.BusinessLogicContracts; +using DiningRoomContracts.SearchModels; +using DiningRoomContracts.StorageContracts; +using DiningRoomContracts.ViewModels; +using Microsoft.Extensions.Logging; + + +namespace DiningRoomBusinessLogic.BusinessLogics +{ + public class ProductLogic : IProductLogic + { + private readonly ILogger _logger; + private readonly IProductStorage _ProductStorage; + public ProductLogic(ILogger logger, IProductStorage ProductStorage) + { + _logger = logger; + _ProductStorage = ProductStorage; + } + public List? ReadList(ProductSearchModel? model) + { + _logger.LogInformation("ReadList. ProductName:{ProductName}. Id:{ Id}", model?.ProductName, model?.Id); + var list = model == null ? _ProductStorage.GetFullList() : _ProductStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count:{Count}", list.Count); + return list; + } + public ProductViewModel? ReadElement(ProductSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. ProductName:{ProductName}. Id:{ Id}", model.ProductName, model.Id); + var element = _ProductStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); + return element; + } + public bool Create(ProductBindingModel model) + { + CheckModel(model); + if (_ProductStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + public bool Update(ProductBindingModel model) + { + CheckModel(model); + if (_ProductStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + public bool Delete(ProductBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id:{Id}", model.Id); + if (_ProductStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + private void CheckModel(ProductBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.ProductName)) + { + throw new ArgumentNullException("Нет названия блюда", nameof(model.ProductName)); + } + if (model.Cost <= 0) + { + throw new ArgumentNullException("Цена блюда должна быть больше 0", nameof(model.Cost)); + } + _logger.LogInformation("Product. ProductName:{ProductName}. Cost:{ Cost}. Id: { Id}", model.ProductName, model.Cost, model.Id); + var element = _ProductStorage.GetElement(new ProductSearchModel + { + ProductName = model.ProductName + }); + if (element != null && element.Id != model.Id) + { + throw new InvalidOperationException("Блюдо с таким названием уже есть"); + } + } + } +} diff --git a/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/UserLogic.cs b/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/UserLogic.cs new file mode 100644 index 0000000..a4385d4 --- /dev/null +++ b/DiningRoom/DiningRoomBusinessLogic/BusinessLogics/UserLogic.cs @@ -0,0 +1,138 @@ +using DiningRoomContracts.BindingModels; +using DiningRoomContracts.BusinessLogicContracts; +using DiningRoomContracts.SearchModels; +using DiningRoomContracts.StorageContracts; +using DiningRoomContracts.ViewModels; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DiningRoomBusinessLogic.BusinessLogics +{ + public class UserLogic : IUserLogic + { + private readonly ILogger _logger; + private readonly IUserStorage _userStorage; + + public UserLogic(ILogger logger, IUserStorage userStorage) + { + _logger = logger; + _userStorage = userStorage; + } + + + public List? ReadList(UserSearchModel? model) + { + _logger.LogInformation("User ReadList. Login:{Login} Emain:{Email} Id:{Id}", model?.Login, model?.Email, model?.Id); + var list = model == null ? _userStorage.GetFullList() : _userStorage.GetFilteredList(model); + if (list == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + _logger.LogInformation("ReadList. Count:{Count}", list.Count); + return list; + } + + public UserViewModel? ReadElement(UserSearchModel model) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + _logger.LogInformation("ReadElement. Login:{Login}. Email:{Email}. Id:{Id}", model?.Login, model?.Email, model?.Id); + var element = _userStorage.GetElement(model); + if (element == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + _logger.LogInformation("ReadElement find. Id:{Id}", element.Id); + return element; + } + + public bool Create(UserBindingModel model) + { + CheckModel(model); + if (_userStorage.Insert(model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + return true; + } + + public bool Update(UserBindingModel model) + { + CheckModel(model); + if (_userStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + return true; + } + + public bool Delete(UserBindingModel model) + { + CheckModel(model, false); + _logger.LogInformation("Delete. Id:{Id}", model.Id); + if (_userStorage.Delete(model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + return true; + } + + + private void CheckModel(UserBindingModel model, bool withParams = true) + { + if (model == null) + { + throw new ArgumentNullException(nameof(model)); + } + if (!withParams) + { + return; + } + if (string.IsNullOrEmpty(model.Login)) + { + throw new ArgumentNullException("Нет логина пользователя", nameof(model.Login)); + } + if (string.IsNullOrEmpty(model.Password)) + { + throw new ArgumentNullException("Нет пароля пользователя", nameof(model.Password)); + } + if (string.IsNullOrEmpty(model.Email)) + { + throw new ArgumentNullException("Нет почты пользователя", nameof(model.Email)); + } + + + //проверка уникальности логина + var user1 = _userStorage.GetElement(new UserSearchModel + { + Login = model.Login + }); + + if (user1 != null && user1.Id != model.Id) + { + throw new InvalidOperationException("Пользователь с таким логином уже есть"); + } + + //проверка уникальности почты + var user2 = _userStorage.GetElement(new UserSearchModel + { + Email = model.Email + }); + + if (user2 != null && user2.Id != model.Id) { + throw new InvalidOperationException("Пользователь с такой почтой уже есть"); + } + } + } +} diff --git a/DiningRoom/DiningRoomBusinessLogic/DiningRoomBusinessLogic.csproj b/DiningRoom/DiningRoomBusinessLogic/DiningRoomBusinessLogic.csproj new file mode 100644 index 0000000..4816fa0 --- /dev/null +++ b/DiningRoom/DiningRoomBusinessLogic/DiningRoomBusinessLogic.csproj @@ -0,0 +1,17 @@ + + + + net6.0 + enable + enable + + + + + + + + + + + diff --git a/DiningRoom/DiningRoomContracts/StorageContracts/IUserStorage.cs b/DiningRoom/DiningRoomContracts/StorageContracts/IUserStorage.cs index d2d0b5c..5eae223 100644 --- a/DiningRoom/DiningRoomContracts/StorageContracts/IUserStorage.cs +++ b/DiningRoom/DiningRoomContracts/StorageContracts/IUserStorage.cs @@ -12,7 +12,8 @@ namespace DiningRoomContracts.StorageContracts public interface IUserStorage { List GetFullList(); - UserViewModel? GetElement(UserSearchModel model); + List GetFilteredList(UserSearchModel model); + UserViewModel? GetElement(UserSearchModel model); UserViewModel? Insert(UserBindingModel model); UserViewModel? Update(UserBindingModel model); UserViewModel? Delete(UserBindingModel model); diff --git a/DiningRoom/DiningRoomDatabaseImplement/Implements/UserStorage.cs b/DiningRoom/DiningRoomDatabaseImplement/Implements/UserStorage.cs index 6d5fcc3..550b967 100644 --- a/DiningRoom/DiningRoomDatabaseImplement/Implements/UserStorage.cs +++ b/DiningRoom/DiningRoomDatabaseImplement/Implements/UserStorage.cs @@ -20,10 +20,19 @@ namespace DiningRoomDatabaseImplement.Implements using var context = new DiningRoomDatabase(); return context.Users.Select(x => x.GetViewModel).ToList(); } + public List GetFilteredList(UserSearchModel model) + { + if (model.Id == null) + { + return new(); + } + using var context = new DiningRoomDatabase(); + return context.Users.Where(x => x.Id == model.Id).Select(x => x.GetViewModel).ToList(); + } - public UserViewModel? GetElement(UserSearchModel model) + public UserViewModel? GetElement(UserSearchModel model) { - //!!!МБ ЭТУ ПРОВЕРКУ УБРАТЬ + if (string.IsNullOrEmpty(model.Login) && string.IsNullOrEmpty(model.Email) && !model.Id.HasValue) { return null; @@ -35,7 +44,7 @@ namespace DiningRoomDatabaseImplement.Implements { return context.Users.FirstOrDefault(x => x.Login == model.Login && x.Password == model.Password)?.GetViewModel; } - //!!!НИЖЕ МБ НЕ НАДО + //Получение по логину (пользователей с таким логином будет 1 или 0) if (!string.IsNullOrEmpty(model.Login)) { diff --git a/DiningRoom/DiningRoomDatabaseImplement/Models/User.cs b/DiningRoom/DiningRoomDatabaseImplement/Models/User.cs index 4839f6c..a0e4a1f 100644 --- a/DiningRoom/DiningRoomDatabaseImplement/Models/User.cs +++ b/DiningRoom/DiningRoomDatabaseImplement/Models/User.cs @@ -5,7 +5,9 @@ using DiningRoomDataModels.Models; using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using System.Linq; +using System.Reflection; using System.Text; using System.Threading.Tasks; @@ -21,13 +23,24 @@ namespace DiningRoomDatabaseImplement.Models [Required] public string Password { get; set; } = string.Empty; - //!!!МБ ТУТ НУЖНА ДОП. АННОТАЦИЯ ПРОВЕРКИ ПОЧТЫ + [Required] public string Email { get; set; } = string.Empty; + [ForeignKey("UserId")] + public virtual List Cards { get; set; } = new(); + [ForeignKey("UserId")] + public virtual List Orders { get; set; } = new(); + + [ForeignKey("UserId")] + public virtual List Drinks { get; set; } = new(); + [ForeignKey("UserId")] + public virtual List Components { get; set; } = new(); + + [ForeignKey("UserId")] + public virtual List Products { get; set; } = new(); - //!!!МБ ТУТ НАДО БУДЕТ СОЗДАТЬ 2 РАЗНЫХ МЕТОДА: СОЗДАНИЕ ИСПОЛНИТЕЛЯ и СОЗДАНИЕ ПОРУЧИТЕЛЯ (хотя мб где-то потом будем задавать роль в BindingModel) - public static User Create(UserBindingModel model) + public static User Create(UserBindingModel model) { return new User { @@ -49,7 +62,7 @@ namespace DiningRoomDatabaseImplement.Models Email = model.Email; } - //!!!МБ ТУТ НЕ НАДО РОЛЬ + public UserViewModel GetViewModel => new() { Id = Id,