diff --git a/TravelCompany/TravelCompany/FormShop.cs b/TravelCompany/TravelCompany/FormShop.cs index e177fe6..282374c 100644 --- a/TravelCompany/TravelCompany/FormShop.cs +++ b/TravelCompany/TravelCompany/FormShop.cs @@ -101,8 +101,9 @@ namespace TravelCompany.Forms ShopName = textBoxName.Text, Adress = textBoxAdress.Text, OpeningDate = dateTimeOpen.Value, - TravelMaxCount = (int)numericUpTravelMaxCount.Value - }; + TravelMaxCount = (int)numericUpTravelMaxCount.Value, + ShopTravels = null + }; var operationResult = _id.HasValue ? _logic.Update(model) : _logic.Create(model); if (!operationResult) { diff --git a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/OrderLogic.cs b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/OrderLogic.cs index faa2329..07811b6 100644 --- a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/OrderLogic.cs +++ b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/OrderLogic.cs @@ -1,15 +1,10 @@ -using TravelCompanyContracts.BindingModels; +using TravelCompanyDataModels.Enums; +using Microsoft.Extensions.Logging; +using TravelCompanyContracts.BindingModels; using TravelCompanyContracts.BusinessLogicsContracts; using TravelCompanyContracts.SearchModels; using TravelCompanyContracts.StoragesContracts; using TravelCompanyContracts.ViewModels; -using TravelCompanyDataModels.Enums; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace TravelCompanyBusinessLogic.BusinessLogic { @@ -17,10 +12,9 @@ namespace TravelCompanyBusinessLogic.BusinessLogic { private readonly ILogger _logger; private readonly IOrderStorage _orderStorage; + static readonly object _locker = new object(); private readonly IShopStorage _shopStorage; - static readonly object locker = new object(); - public OrderLogic(ILogger logger, IOrderStorage orderStorage, IShopStorage shopStorage) { _logger = logger; @@ -34,7 +28,8 @@ namespace TravelCompanyBusinessLogic.BusinessLogic { throw new ArgumentNullException(nameof(model)); } - _logger.LogInformation("ReadElement. Id:{ Id}", model.Id); + _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 element = _orderStorage.GetElement(model); if (element == null) { @@ -47,7 +42,8 @@ namespace TravelCompanyBusinessLogic.BusinessLogic public List? ReadList(OrderSearchModel? model) { - _logger.LogInformation("ReadList. OrderId:{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 == null ? _orderStorage.GetFullList() : _orderStorage.GetFilteredList(model); if (list == null) { @@ -61,11 +57,9 @@ namespace TravelCompanyBusinessLogic.BusinessLogic public bool CreateOrder(OrderBindingModel model) { CheckModel(model); - if (model.Status != OrderStatus.Неизвестен) return false; model.Status = OrderStatus.Принят; - if (_orderStorage.Insert(model) == null) { _logger.LogWarning("Insert operation failed"); @@ -76,42 +70,42 @@ namespace TravelCompanyBusinessLogic.BusinessLogic public bool TakeOrderInWork(OrderBindingModel model) { - lock (locker) + lock (_locker) { - return ToNextStatus(model, OrderStatus.Выполняется); + return ChangeStatus(model, OrderStatus.Выполняется); } } public bool FinishOrder(OrderBindingModel model) { - return ToNextStatus(model, OrderStatus.Готов); + return ChangeStatus(model, OrderStatus.Готов); } public bool DeliveryOrder(OrderBindingModel model) { - return ToNextStatus(model, OrderStatus.Выдан); - } - - public bool ToNextStatus(OrderBindingModel model, OrderStatus orderStatus) - { - CheckModel(model, false); - var element = _orderStorage.GetElement(new OrderSearchModel { Id = model.Id }); - if (element == null) + lock (_locker) { - _logger.LogWarning("Read operation failed"); - return false; + model = FillOrderBindingModel(model); + if (model.Status != OrderStatus.Готов && model.Status != OrderStatus.Ожидает) + { + _logger.LogWarning("Changing status operation faled: Current-{Status}:required-Выдан.", model.Status); + throw new InvalidOperationException($"Невозможно приствоить статус выдан заказу с текущим статусом {model.Status}"); + } + if (!_shopStorage.RestockingShops(new SupplyBindingModel + { + TravelId = model.TravelId, + Count = model.Count + })) + { + if (model.Status == OrderStatus.Готов || model.Status == OrderStatus.Ожидает) + { + model.Status = OrderStatus.Ожидает; + return UpdateOrder(model); + } + } + model.Status = OrderStatus.Выдан; + return UpdateOrder(model); } - if (element.Status != orderStatus - 1) - { - _logger.LogWarning("Status change operation failed"); - throw new InvalidOperationException("Текущий статус заказа не может быть переведен в выбранный"); - } - model.Status = orderStatus; - if (model.Status == OrderStatus.Готов) model.DateImplement = DateTime.Now; - if (element.ImplementerId.HasValue) - model.ImplementerId = element.ImplementerId; - _orderStorage.Update(model); - return true; } private void CheckModel(OrderBindingModel model, bool withParams = true) @@ -126,13 +120,69 @@ namespace TravelCompanyBusinessLogic.BusinessLogic } if (model.Count <= 0) { - throw new ArgumentNullException("Количество изделий должно быть больше 0", nameof(model.Count)); + throw new ArgumentException("Колличество пиццы в заказе не может быть меньше 1", nameof(model.Count)); } if (model.Sum <= 0) { - throw new ArgumentNullException("Цена заказа должна быть больше 0", nameof(model.Sum)); + throw new ArgumentException("Стоимость заказа на может быть меньше 1", nameof(model.Sum)); } - _logger.LogInformation("Travel. TravelId:{TravelId}.Count:{Count}.Sum:{Sum}Id:{Id}", model.TravelId, model.Count, model.Sum, model.Id); + if (model.DateImplement.HasValue && model.DateImplement < model.DateCreate) + { + throw new ArithmeticException($"Дата выдачи заказа {model.DateImplement} не может быть раньше даты его создания {model.DateCreate}"); + } + _logger.LogInformation("Travel. TravelId:{TravelId}.Count:{Count}.Sum:{Sum}Id:{Id}", + model.TravelId, model.Count, model.Sum, model.Id); + } + private bool ChangeStatus(OrderBindingModel model, OrderStatus requiredStatus) + { + model = FillOrderBindingModel(model); + + if (requiredStatus - model.Status == 1) + { + model.Status = requiredStatus; + if (model.Status == OrderStatus.Готов) + model.DateImplement = DateTime.Now; + return UpdateOrder(model); + } + _logger.LogWarning("Changing status operation faled: Current-{Status}:required-{requiredStatus}.", model.Status, requiredStatus); + throw new InvalidOperationException($"Невозможно приствоить статус {requiredStatus} заказу с текущим статусом {model.Status}"); + } + + private OrderBindingModel FillOrderBindingModel(OrderBindingModel model) + { + CheckModel(model, false); + var element = _orderStorage.GetElement(new OrderSearchModel() + { + Id = model.Id + }); + if (element == null) + { + throw new InvalidOperationException(nameof(element)); + } + model.Id = element.Id; + model.DateCreate = element.DateCreate; + model.TravelId = element.TravelId; + model.DateImplement = element.DateImplement; + model.ClientId = element.ClientId; + model.Status = element.Status; + model.Count = element.Count; + model.Sum = element.Sum; + if (!model.ImplementerId.HasValue) + { + model.ImplementerId = element.ImplementerId; + } + return model; + } + + private bool UpdateOrder(OrderBindingModel model) + { + if (_orderStorage.Update(model) == null) + { + _logger.LogWarning("Update operation failed"); + return false; + } + _logger.LogWarning("Update operation sucsess"); + return true; } } } diff --git a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/WorkModeling.cs b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/WorkModeling.cs index 1efc64b..1138db7 100644 --- a/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/WorkModeling.cs +++ b/TravelCompany/TravelCompanyBusinessLogic/BusinessLogic/WorkModeling.cs @@ -1,145 +1,181 @@ -using TravelCompanyContracts.BindingModels; +using Microsoft.Extensions.Logging; +using TravelCompanyContracts.BindingModels; using TravelCompanyContracts.BusinessLogicsContracts; using TravelCompanyContracts.SearchModels; using TravelCompanyContracts.ViewModels; using TravelCompanyDataModels.Enums; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace TravelCompanyBusinessLogic.BusinessLogic +namespace TravelCompanyBusinessLogic.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.Принят - }); - 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); + public class WorkModeling : IWorkProcess + { + private readonly ILogger _logger; - _orderLogic.FinishOrder(new OrderBindingModel - { - Id = order.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; - } - } - }); - } - /// Ищем заказ, которые уже в работе (вдруг исполнителя прервали) - 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.Выполняется - })); - 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; - } - } - } + 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.Выдан }); + int count = _orderLogic.ReadList(null).Count; + if (orders == null || count == orders.Count) + { + _logger.LogWarning("DoWork. Orders is null or empty"); + return; + } + orders = _orderLogic.ReadList(null); + _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 DeliverWaitingOrder(implementer); + 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 + }); + _orderLogic.DeliveryOrder(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.Выполняется + })); + 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 + }); + _orderLogic.DeliveryOrder(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; + } + } + + private async Task DeliverWaitingOrder(ImplementerViewModel implementer) + { + if (_orderLogic == null || implementer == null) + { + return; + } + var waitingOrders = await Task.Run(() => _orderLogic.ReadList(new OrderSearchModel + { + ImplementerId = implementer.Id, + Status = OrderStatus.Ожидает + })); + if (waitingOrders == null || waitingOrders.Count == 0) + { + return; + } + _logger.LogInformation("DeliverWaitingOrder. Find some waitig order for implementer:{id}.Count:{count}", implementer.Id, waitingOrders.Count); + foreach (var waitingOrder in waitingOrders) + { + try + { + _logger.LogInformation("DeliverWaitingOrder. Trying to deliver order id:{id}", waitingOrder.Id); + var res = _orderLogic.DeliveryOrder(new OrderBindingModel + { + Id = waitingOrder.Id + }); + } + catch (ArgumentException ex) + { + _logger.LogWarning(ex, "DeliverWaitingOrder. Fault"); + } + catch (InvalidOperationException ex) + { + _logger.LogWarning(ex, "Error try deliver order"); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error while do work"); + throw; + } + } + } + } } diff --git a/TravelCompany/TravelCompanyDataModels/Enums/OrderStatus.cs b/TravelCompany/TravelCompanyDataModels/Enums/OrderStatus.cs index 0e8a2ca..b2fd709 100644 --- a/TravelCompany/TravelCompanyDataModels/Enums/OrderStatus.cs +++ b/TravelCompany/TravelCompanyDataModels/Enums/OrderStatus.cs @@ -6,6 +6,7 @@ Принят = 0, Выполняется = 1, Готов = 2, - Выдан = 3, + Ожидает = 3, + Выдан = 4, } } \ No newline at end of file diff --git a/TravelCompany/TravelCompanyDatabaseImplement/Models/Shop.cs b/TravelCompany/TravelCompanyDatabaseImplement/Models/Shop.cs index 0c5729c..3a912a5 100644 --- a/TravelCompany/TravelCompanyDatabaseImplement/Models/Shop.cs +++ b/TravelCompany/TravelCompanyDatabaseImplement/Models/Shop.cs @@ -75,27 +75,32 @@ namespace TravelCompanyDatabaseImplement.Models public void UpdateTravels(TravelCompanyDataBase context, ShopBindingModel model) { - var ShopTravels = context.ShopTravels.Where(rec => rec.ShopId == model.Id).ToList(); - if (ShopTravels != null && ShopTravels.Count > 0) + if (model.ShopTravels == null) + return; + var shopTravels = context.ShopTravels.Where(rec => + rec.ShopId == model.Id).ToList(); + if (shopTravels != null && shopTravels.Count > 0) { - context.ShopTravels.RemoveRange(ShopTravels.Where(rec => !model.ShopTravels.ContainsKey(rec.TravelId))); + context.ShopTravels.RemoveRange(shopTravels.Where(rec +=> !model.ShopTravels.ContainsKey(rec.TravelId))); + context.SaveChanges(); - ShopTravels = context.ShopTravels.Where(rec => rec.ShopId == model.Id).ToList(); - foreach (var updateTravel in ShopTravels) + foreach (var updateTravel in shopTravels) { - updateTravel.Count = model.ShopTravels[updateTravel.TravelId].Item2; + updateTravel.Count = + model.ShopTravels[updateTravel.TravelId].Item2; model.ShopTravels.Remove(updateTravel.TravelId); } context.SaveChanges(); } var shop = context.Shops.First(x => x.Id == Id); - foreach (var ar in model.ShopTravels) + foreach (var pc in model.ShopTravels) { context.ShopTravels.Add(new ShopTravels { Shop = shop, - Travel = context.Travels.First(x => x.Id == ar.Key), - Count = ar.Value.Item2 + Travel = context.Travels.First(x => x.Id == pc.Key), + Count = pc.Value.Item2 }); context.SaveChanges(); }