diff --git a/AutoWorkshopBusinessLogic/BusinessLogics/ImplementerLogic.cs b/AutoWorkshopBusinessLogic/BusinessLogics/ImplementerLogic.cs new file mode 100644 index 0000000..4b39348 --- /dev/null +++ b/AutoWorkshopBusinessLogic/BusinessLogics/ImplementerLogic.cs @@ -0,0 +1,135 @@ +using AutoWorkshopContracts.BindingModels; +using AutoWorkshopContracts.BusinessLogicsContracts; +using AutoWorkshopContracts.SearchModels; +using AutoWorkshopContracts.StoragesContracts; +using AutoWorkshopContracts.ViewModels; +using Microsoft.Extensions.Logging; + +namespace AutoWorkshopBusinessLogic.BusinessLogics +{ + public class ImplementerLogic : IImplementerLogic + { + private readonly ILogger _logger; + private readonly IImplementerStorage _implementerStorage; + + public ImplementerLogic(ILogger Logger, IImplementerStorage ImplementerStorage) + { + _logger = Logger; + _implementerStorage = ImplementerStorage; + } + + public List? ReadList(ImplementerSearchModel? Model) + { + _logger.LogInformation("ReadList. ImplementerFIO: {ImplementerFIO}. Password: {Password}. Id: {Id}", + Model?.ImplementerFIO, Model?.Password?.Length, Model?.Id); + + var List = Model == null ? _implementerStorage.GetFullList() : _implementerStorage.GetFilteredList(Model); + + if (List == null) + { + _logger.LogWarning("ReadList return null list"); + return null; + } + + _logger.LogInformation("ReadList. Count: {Count}", List.Count); + return List; + } + + public ImplementerViewModel? ReadElement(ImplementerSearchModel Model) + { + if (Model is null) + { + throw new ArgumentNullException(nameof(Model)); + } + + _logger.LogInformation("ReadElement. ImplementerFIO: {ImplementerFIO}. Password: {Password}. Id: {Id}", + Model?.ImplementerFIO, Model?.Password?.Length, Model?.Id); + + var Element = _implementerStorage.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(ImplementerBindingModel Model) + { + CheckModel(Model); + + if (_implementerStorage.Insert(Model) == null) + { + _logger.LogWarning("Insert operation failed"); + return false; + } + + return true; + } + + public bool Update(ImplementerBindingModel Model) + { + CheckModel(Model); + + if (_implementerStorage.Update(Model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + + return true; + } + + public bool Delete(ImplementerBindingModel Model) + { + CheckModel(Model, false); + + _logger.LogInformation("Delete. Id:{Id}", Model.Id); + + if (_implementerStorage.Delete(Model) == null) + { + _logger.LogWarning("Delete operation failed"); + return false; + } + + return true; + } + + private void CheckModel(ImplementerBindingModel Model, bool WithParams = true) + { + if (Model == null) + throw new ArgumentNullException(nameof(Model)); + + if (!WithParams) + return; + + if (string.IsNullOrEmpty(Model.ImplementerFIO)) + throw new ArgumentNullException("Нет ФИО исполнителя", nameof(Model.ImplementerFIO)); + + if (string.IsNullOrEmpty(Model.Password)) + throw new ArgumentNullException("Нет пароля исполнителя", nameof(Model.Password)); + + if (Model.WorkExperience < 0) + throw new ArgumentNullException("Стаж должен быть неотрицательным целым числом", nameof(Model.WorkExperience)); + + if (Model.Qualification < 0) + throw new ArgumentNullException("Квалификация должна быть неотрицательным целым числом", nameof(Model.Qualification)); + + _logger.LogInformation("Implementer. ImplementerFIO: {ImplementerFIO}. Password: {Password}. WorkExperience: {WorkExperience}. Qualification: {Qualification}. Id: {Id}", + Model.ImplementerFIO, Model.Password, Model.WorkExperience, Model.Qualification, Model.Id); + + var Implementer = _implementerStorage.GetElement(new ImplementerSearchModel + { + ImplementerFIO = Model.ImplementerFIO + }); + + if (Implementer != null && Implementer.Id != Model.Id) + { + throw new InvalidOperationException("Исполнитель с таким ФИО уже есть"); + } + } + } +} diff --git a/AutoWorkshopBusinessLogic/BusinessLogics/OrderLogic.cs b/AutoWorkshopBusinessLogic/BusinessLogics/OrderLogic.cs index 246c491..dbd5691 100644 --- a/AutoWorkshopBusinessLogic/BusinessLogics/OrderLogic.cs +++ b/AutoWorkshopBusinessLogic/BusinessLogics/OrderLogic.cs @@ -14,6 +14,8 @@ namespace AutoWorkshopBusinessLogic.BusinessLogics private readonly IOrderStorage _orderStorage; + static readonly object _locker = new object(); + public OrderLogic(ILogger Logger, IOrderStorage OrderStorage) { _logger = Logger; @@ -22,19 +24,18 @@ namespace AutoWorkshopBusinessLogic.BusinessLogics public List? ReadList(OrderSearchModel? Model) { - _logger.LogInformation("ReadList. Id:{Id}", Model?.Id); + _logger.LogInformation("ReadList. ClientId: {ClientId}. Status: {Status}. ImplementerId: {ImplementerId}. DateFrom: {DateFrom}. DateTo: {DateTo}. OrderId: {Id}", + Model?.ClientId, Model?.Status, Model?.ImplementerId, Model?.DateFrom, Model?.DateTo, Model?.Id); + var List = Model is null ? _orderStorage.GetFullList() : _orderStorage.GetFilteredList(Model); - if (List is null) { _logger.LogWarning("ReadList return null list"); return null; } - _logger.LogInformation("ReadList. Count: {Count}", List.Count); return List; } - public bool CreateOrder(OrderBindingModel Model) { CheckModel(Model); @@ -76,6 +77,8 @@ namespace AutoWorkshopBusinessLogic.BusinessLogics } Model.RepairId = Order.RepairId; + Model.ClientId = Order.ClientId; + Model.ImplementerId = Order.ImplementerId; Model.Count = Order.Count; Model.Sum = Order.Sum; Model.DateCreate = Order.DateCreate; @@ -97,7 +100,10 @@ namespace AutoWorkshopBusinessLogic.BusinessLogics public bool TakeOrderInWork(OrderBindingModel Model) { - return ChangeOrderStatus(Model, OrderStatus.BeingProcessed); + lock (_locker) + { + return ChangeOrderStatus(Model, OrderStatus.BeingProcessed); + } } public bool FinishOrder(OrderBindingModel Model) @@ -129,5 +135,27 @@ namespace AutoWorkshopBusinessLogic.BusinessLogics Model.RepairId, Model.Count, Model.Sum, Model.Status, Model.DateCreate, Model.DateImplement, Model.Id); } + + public OrderViewModel? ReadElement(OrderSearchModel Model) + { + if (Model == null) + { + throw new ArgumentNullException(nameof(Model)); + } + + _logger.LogInformation("ReadElement. ClientId: {ClientId}. Status: {Status}. ImplementerId: {ImplementerId}. DateFrom: {DateFrom}. DateTo: {DateTo}. OrderId: {Id}", + Model.ClientId, Model.Status, Model.ImplementerId, Model.DateFrom, Model.DateTo, Model.Id); + + var Order = _orderStorage.GetElement(Model); + + if (Order == null) + { + _logger.LogWarning("ReadElement element not found"); + return null; + } + + _logger.LogInformation("ReadElement find. Id: {Id}", Order.Id); + return Order; + } } } diff --git a/AutoWorkshopBusinessLogic/BusinessLogics/WorkModeling.cs b/AutoWorkshopBusinessLogic/BusinessLogics/WorkModeling.cs new file mode 100644 index 0000000..b1876a6 --- /dev/null +++ b/AutoWorkshopBusinessLogic/BusinessLogics/WorkModeling.cs @@ -0,0 +1,143 @@ +using AutoWorkshopContracts.BindingModels; +using AutoWorkshopContracts.BusinessLogicContracts; +using AutoWorkshopContracts.BusinessLogicsContracts; +using AutoWorkshopContracts.SearchModels; +using AutoWorkshopContracts.ViewModels; +using AutoWorkshopDataModels.Enums; +using Microsoft.Extensions.Logging; + +namespace AutoWorkshopBusinessLogic.BusinessLogics +{ + public class WorkModeling : IWorkProcess + { + private readonly ILogger _logger; + + private readonly Random _rnd; + + private IOrderLogic? _orderLogic; + + public WorkModeling(ILogger Logger) + { + _logger = Logger; + _rnd = new Random(1000); + } + + public void DoWork(IImplementerLogic ImplementerLogic, IOrderLogic OrderLogic) + { + _orderLogic = OrderLogic; + + var Implementers = ImplementerLogic.ReadList(null); + + if (Implementers == null) + { + _logger.LogWarning("DoWork. Implementers is null"); + return; + } + + var Orders = _orderLogic.ReadList(new OrderSearchModel { Status = OrderStatus.Accepted }); + + if (Orders == null || Orders.Count == 0) + { + _logger.LogWarning("DoWork. Orders is null or empty"); + return; + } + + _logger.LogDebug("DoWork for {Count} orders", Orders.Count); + + foreach (var Implementer in Implementers) + { + Task.Run(() => WorkerWorkAsync(Implementer, Orders)); + } + } + + private async Task WorkerWorkAsync(ImplementerViewModel Implementer, List Orders) + { + if (_orderLogic == null || Implementer == null) + { + return; + } + + await RunOrderInWork(Implementer); + + await Task.Run(() => + { + foreach (var Order in Orders) + { + try + { + _logger.LogDebug("DoWork. Worker {Id} try get order {Order}", Implementer.Id, Order.Id); + + _orderLogic.TakeOrderInWork(new OrderBindingModel + { + Id = Order.Id, + ImplementerId = Implementer.Id + }); + + Thread.Sleep(Implementer.WorkExperience * _rnd.Next(100, 1000) * Order.Count); + + _logger.LogDebug("DoWork. Worker {Id} finish order {Order}", Implementer.Id, Order.Id); + _orderLogic.FinishOrder(new OrderBindingModel + { + Id = Order.Id + }); + } + + catch (InvalidOperationException ex) + { + _logger.LogWarning(ex, "Error try get work"); + } + + catch (Exception ex) + { + _logger.LogError(ex, "Error while do work"); + throw; + } + + Thread.Sleep(Implementer.Qualification * _rnd.Next(10, 100)); + } + }); + } + + private async Task RunOrderInWork(ImplementerViewModel Implementer) + { + if (_orderLogic == null || Implementer == null) + return; + + try + { + var RunOrder = await Task.Run(() => _orderLogic.ReadElement(new OrderSearchModel + { + ImplementerId = Implementer.Id, + Status = OrderStatus.BeingProcessed + })); + + if (RunOrder == null) + { + return; + } + + _logger.LogDebug("DoWork. Worker {Id} back to order {Order}", Implementer.Id, RunOrder.Id); + Thread.Sleep(Implementer.WorkExperience * _rnd.Next(100, 300) * RunOrder.Count); + + _logger.LogDebug("DoWork. Worker {Id} finish order {Order}", Implementer.Id, RunOrder.Id); + _orderLogic.FinishOrder(new OrderBindingModel + { + Id = RunOrder.Id + }); + + Thread.Sleep(Implementer.Qualification * _rnd.Next(10, 100)); + } + + catch (InvalidOperationException ex) + { + _logger.LogWarning(ex, "Error try get work"); + } + + catch (Exception ex) + { + _logger.LogError(ex, "Error while do work"); + throw; + } + } + } +} diff --git a/AutoWorkshopContracts/BindingModels/ImplementerBindingModel.cs b/AutoWorkshopContracts/BindingModels/ImplementerBindingModel.cs new file mode 100644 index 0000000..a9fe78d --- /dev/null +++ b/AutoWorkshopContracts/BindingModels/ImplementerBindingModel.cs @@ -0,0 +1,17 @@ +using AutoWorkshopDataModels.Models; + +namespace AutoWorkshopContracts.BindingModels +{ + public class ImplementerBindingModel : IImplementerModel + { + public int Id { get; set; } + + public string ImplementerFIO { get; set; } = string.Empty; + + public string Password { get; set; } = string.Empty; + + public int WorkExperience { get; set; } + + public int Qualification { get; set; } + } +} diff --git a/AutoWorkshopContracts/BindingModels/OrderBindingModel.cs b/AutoWorkshopContracts/BindingModels/OrderBindingModel.cs index cad16c1..199b492 100644 --- a/AutoWorkshopContracts/BindingModels/OrderBindingModel.cs +++ b/AutoWorkshopContracts/BindingModels/OrderBindingModel.cs @@ -8,6 +8,7 @@ namespace AutoWorkshopContracts.BindingModels public int Id { get; set; } public int RepairId { get; set; } public int ClientId { get; set; } + public int? ImplementerId { get; set; } public int Count { get; set; } public double Sum { get; set; } public OrderStatus Status { get; set; } = OrderStatus.Undefined; diff --git a/AutoWorkshopContracts/BusinessLogicContracts/IImplementerLogic.cs b/AutoWorkshopContracts/BusinessLogicContracts/IImplementerLogic.cs new file mode 100644 index 0000000..5a186fd --- /dev/null +++ b/AutoWorkshopContracts/BusinessLogicContracts/IImplementerLogic.cs @@ -0,0 +1,19 @@ +using AutoWorkshopContracts.BindingModels; +using AutoWorkshopContracts.SearchModels; +using AutoWorkshopContracts.ViewModels; + +namespace AutoWorkshopContracts.BusinessLogicsContracts +{ + public interface IImplementerLogic + { + List? ReadList(ImplementerSearchModel? Model); + + ImplementerViewModel? ReadElement(ImplementerSearchModel Model); + + bool Create(ImplementerBindingModel Model); + + bool Update(ImplementerBindingModel Model); + + bool Delete(ImplementerBindingModel Model); + } +} diff --git a/AutoWorkshopContracts/BusinessLogicContracts/IOrderLogic.cs b/AutoWorkshopContracts/BusinessLogicContracts/IOrderLogic.cs index 6c298b7..a69ceae 100644 --- a/AutoWorkshopContracts/BusinessLogicContracts/IOrderLogic.cs +++ b/AutoWorkshopContracts/BusinessLogicContracts/IOrderLogic.cs @@ -11,5 +11,6 @@ namespace AutoWorkshopContracts.BusinessLogicContracts bool TakeOrderInWork(OrderBindingModel Model); bool FinishOrder(OrderBindingModel Model); bool DeliveryOrder(OrderBindingModel Model); + OrderViewModel? ReadElement(OrderSearchModel Model); } } diff --git a/AutoWorkshopContracts/BusinessLogicContracts/IWorkProcess.cs b/AutoWorkshopContracts/BusinessLogicContracts/IWorkProcess.cs new file mode 100644 index 0000000..24c8ef5 --- /dev/null +++ b/AutoWorkshopContracts/BusinessLogicContracts/IWorkProcess.cs @@ -0,0 +1,9 @@ +using AutoWorkshopContracts.BusinessLogicsContracts; + +namespace AutoWorkshopContracts.BusinessLogicContracts +{ + public interface IWorkProcess + { + void DoWork(IImplementerLogic ImplementerLogic, IOrderLogic OrderLogic); + } +} diff --git a/AutoWorkshopContracts/SearchModels/ImplementerSearchModel.cs b/AutoWorkshopContracts/SearchModels/ImplementerSearchModel.cs new file mode 100644 index 0000000..258a1b8 --- /dev/null +++ b/AutoWorkshopContracts/SearchModels/ImplementerSearchModel.cs @@ -0,0 +1,11 @@ +namespace AutoWorkshopContracts.SearchModels +{ + public class ImplementerSearchModel + { + public int? Id { get; set; } + + public string? ImplementerFIO { get; set; } + + public string? Password { get; set; } + } +} diff --git a/AutoWorkshopContracts/SearchModels/OrderSearchModel.cs b/AutoWorkshopContracts/SearchModels/OrderSearchModel.cs index e040df1..5f18f78 100644 --- a/AutoWorkshopContracts/SearchModels/OrderSearchModel.cs +++ b/AutoWorkshopContracts/SearchModels/OrderSearchModel.cs @@ -1,4 +1,6 @@ -namespace AutoWorkshopContracts.SearchModels +using AutoWorkshopDataModels.Enums; + +namespace AutoWorkshopContracts.SearchModels { public class OrderSearchModel { @@ -6,6 +8,10 @@ public int? ClientId { get; set; } + public OrderStatus? Status { get; set; } + + public int? ImplementerId { get; set; } + public DateTime? DateFrom { get; set; } public DateTime? DateTo { get; set; } diff --git a/AutoWorkshopContracts/StoragesContracts/IImplementerStorage.cs b/AutoWorkshopContracts/StoragesContracts/IImplementerStorage.cs new file mode 100644 index 0000000..822b70a --- /dev/null +++ b/AutoWorkshopContracts/StoragesContracts/IImplementerStorage.cs @@ -0,0 +1,21 @@ +using AutoWorkshopContracts.BindingModels; +using AutoWorkshopContracts.SearchModels; +using AutoWorkshopContracts.ViewModels; + +namespace AutoWorkshopContracts.StoragesContracts +{ + public interface IImplementerStorage + { + List GetFullList(); + + List GetFilteredList(ImplementerSearchModel Model); + + ImplementerViewModel? GetElement(ImplementerSearchModel Model); + + ImplementerViewModel? Insert(ImplementerBindingModel Model); + + ImplementerViewModel? Update(ImplementerBindingModel Model); + + ImplementerViewModel? Delete(ImplementerBindingModel Model); + } +} diff --git a/AutoWorkshopContracts/ViewModels/ImplementerViewModel.cs b/AutoWorkshopContracts/ViewModels/ImplementerViewModel.cs new file mode 100644 index 0000000..cf93e02 --- /dev/null +++ b/AutoWorkshopContracts/ViewModels/ImplementerViewModel.cs @@ -0,0 +1,22 @@ +using AutoWorkshopDataModels.Models; +using System.ComponentModel; + +namespace AutoWorkshopContracts.ViewModels +{ + public class ImplementerViewModel : IImplementerModel + { + public int Id { get; set; } + + [DisplayName("ФИО исполнителя")] + public string ImplementerFIO { get; set; } = string.Empty; + + [DisplayName("Пароль")] + public string Password { get; set; } = string.Empty; + + [DisplayName("Стаж работы")] + public int WorkExperience { get; set; } + + [DisplayName("Квалификация")] + public int Qualification { get; set; } + } +} diff --git a/AutoWorkshopContracts/ViewModels/OrderViewModel.cs b/AutoWorkshopContracts/ViewModels/OrderViewModel.cs index df0608e..2a423b0 100644 --- a/AutoWorkshopContracts/ViewModels/OrderViewModel.cs +++ b/AutoWorkshopContracts/ViewModels/OrderViewModel.cs @@ -19,6 +19,11 @@ namespace AutoWorkshopContracts.ViewModels [DisplayName("Клиент")] public string ClientFIO { get; set; } = string.Empty; + public int? ImplementerId { get; set; } + + [DisplayName("Исполнитель")] + public string? ImplementerFIO { get; set; } + [DisplayName("Количество")] public int Count { get; set; } diff --git a/AutoWorkshopDataModels/Models/IImplementerModel.cs b/AutoWorkshopDataModels/Models/IImplementerModel.cs new file mode 100644 index 0000000..0a925e0 --- /dev/null +++ b/AutoWorkshopDataModels/Models/IImplementerModel.cs @@ -0,0 +1,13 @@ +namespace AutoWorkshopDataModels.Models +{ + public interface IImplementerModel : IId + { + string ImplementerFIO { get; } + + string Password { get; } + + int WorkExperience { get; } + + int Qualification { get; } + } +} diff --git a/AutoWorkshopDataModels/Models/IOrderModel.cs b/AutoWorkshopDataModels/Models/IOrderModel.cs index 7df19c4..190a54f 100644 --- a/AutoWorkshopDataModels/Models/IOrderModel.cs +++ b/AutoWorkshopDataModels/Models/IOrderModel.cs @@ -6,6 +6,7 @@ namespace AutoWorkshopDataModels.Models { int RepairId { get; } int ClientId { get; } + int? ImplementerId { get; } int Count { get; } double Sum { get; } OrderStatus Status { get; } diff --git a/ТП. Лабораторная 06.pdf b/ТП. Лабораторная 06.pdf new file mode 100644 index 0000000..3a9f33e Binary files /dev/null and b/ТП. Лабораторная 06.pdf differ