diff --git a/AircraftPlant/AbstractShopListImplement/DataListSingleton.cs b/AircraftPlant/AbstractShopListImplement/DataListSingleton.cs index d931deb..3316230 100644 --- a/AircraftPlant/AbstractShopListImplement/DataListSingleton.cs +++ b/AircraftPlant/AbstractShopListImplement/DataListSingleton.cs @@ -35,6 +35,10 @@ namespace AircraftPlantListImplement /// Список классов-моделей магазинов /// public List Shops { get; set; } + /// + /// Список классов-моделей магазинов + /// + public List Shops { get; set; } /// /// Конструктор diff --git a/AircraftPlant/AbstractShopListImplement/Shop.cs b/AircraftPlant/AbstractShopListImplement/Shop.cs index 5e3481e..1287c01 100644 --- a/AircraftPlant/AbstractShopListImplement/Shop.cs +++ b/AircraftPlant/AbstractShopListImplement/Shop.cs @@ -39,6 +39,10 @@ namespace AircraftPlantListImplement.Models private set; } = new Dictionary(); /// + /// Максимальное количество изделий + /// + public int MaxPlanes { get; private set; } + /// /// Создание модели магазина /// /// @@ -57,6 +61,7 @@ namespace AircraftPlantListImplement.Models Address = model.Address, DateOpening = model.DateOpening, ShopPlanes = model.ShopPlanes + MaxPlanes = model.MaxPlanes }; } /// @@ -74,6 +79,7 @@ namespace AircraftPlantListImplement.Models Address = model.Address; DateOpening = model.DateOpening; ShopPlanes = model.ShopPlanes; + MaxPlanes = model.MaxPlanes; } /// /// Получение модели магазина @@ -84,7 +90,8 @@ namespace AircraftPlantListImplement.Models ShopName = ShopName, Address = Address, DateOpening = DateOpening, - ShopPlanes = ShopPlanes + ShopPlanes = ShopPlanes, + MaxPlanes = MaxPlanes }; } } diff --git a/AircraftPlant/AbstractShopListImplement/ShopStorage.cs b/AircraftPlant/AbstractShopListImplement/ShopStorage.cs index 3d60ed6..bde12c1 100644 --- a/AircraftPlant/AbstractShopListImplement/ShopStorage.cs +++ b/AircraftPlant/AbstractShopListImplement/ShopStorage.cs @@ -2,6 +2,7 @@ using AircraftPlantContracts.SearchModels; using AircraftPlantContracts.StoragesContracts; using AircraftPlantContracts.ViewModels; +using AircraftPlantDataModels.Models; using AircraftPlantListImplement.Models; using System; using System.Collections.Generic; @@ -143,5 +144,27 @@ namespace AircraftPlantListImplement.Implements } return null; } + /// + /// Продажа изделий + /// + /// + /// + /// + /// + public bool SellPlanes(IPlaneModel model, int count) + { + throw new NotImplementedException(); + } + /// + /// Проверка наличия в нужном количестве + /// + /// + /// + /// + /// + public bool CheckCount(IPlaneModel model, int count) + { + throw new NotImplementedException(); + } } } diff --git a/AircraftPlant/AircraftPlantBusinessLogic/OrderLogic.cs b/AircraftPlant/AircraftPlantBusinessLogic/OrderLogic.cs index 2ebbd1c..95af29c 100644 --- a/AircraftPlant/AircraftPlantBusinessLogic/OrderLogic.cs +++ b/AircraftPlant/AircraftPlantBusinessLogic/OrderLogic.cs @@ -4,6 +4,7 @@ using AircraftPlantContracts.SearchModels; using AircraftPlantContracts.StoragesContracts; using AircraftPlantContracts.ViewModels; using AircraftPlantDataModels.Enums; +using AircraftPlantDataModels.Models; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -114,6 +115,21 @@ namespace AircraftPlantBusinessLogic.BusinessLogics model.Status = newStatus; + if (newStatus == OrderStatus.Выдан) + { + var plane = _planeStorage.GetElement(new PlaneSearchModel { Id = element.PlaneId }); + if (plane == null) + { + _logger.LogWarning("Status change error. Plane not found"); + return false; + } + if (!CheckSupply(plane, element.Count)) + { + _logger.LogWarning("Status change error. Shop is overflowed"); + return false; + } + } + if (model.Status == OrderStatus.Выдан) { model.DateImplement = DateTime.Now; @@ -130,5 +146,72 @@ namespace AircraftPlantBusinessLogic.BusinessLogics } return true; } + public bool CheckSupply(IPlaneModel model, int count) + { + if (count <= 0) + { + _logger.LogWarning("Check supply operation error. Planes count < 0"); + return false; + } + + int sumCapacity = _shopStorage.GetFullList().Select(x => x.MaxPlanes).Sum(); + int sumCount = _shopStorage.GetFullList().Select(x => x.ShopPlanes.Select(y => y.Value.Item2).Sum()).Sum(); + int free = sumCapacity - sumCount; + if (free < count) + { + _logger.LogWarning("Check supply error. No place for new planes"); + return false; + } + + foreach (var shop in _shopStorage.GetFullList()) + { + free = shop.MaxPlanes; + foreach (var plane in shop.ShopPlanes) + { + free -= plane.Value.Item2; + } + + if (free == 0) + { + continue; + } + + if (free >= count) + { + if (_shopLogic.AddPlaneInShop(new() + { + Id = shop.Id + }, model, count)) + { + count = 0; + } + else + { + _logger.LogWarning("Supply error"); + return false; + } + } + else + { + if (_shopLogic.AddPlaneInShop(new() + { + Id = shop.Id + }, model, free)) + { + count -= free; + } + else + { + _logger.LogWarning("Supply error"); + return false; + } + } + if (count <= 0) + { + return true; + } + } + return false; + } } } \ No newline at end of file diff --git a/AircraftPlant/AircraftPlantBusinessLogic/ShopLogic.cs b/AircraftPlant/AircraftPlantBusinessLogic/ShopLogic.cs index f9db95b..8601f86 100644 --- a/AircraftPlant/AircraftPlantBusinessLogic/ShopLogic.cs +++ b/AircraftPlant/AircraftPlantBusinessLogic/ShopLogic.cs @@ -129,6 +129,25 @@ namespace AircraftPlantBusinessLogic.BusinessLogics }); return true; } + public bool SellPlanes(IPlaneModel plane, int count) + { + if (plane == null) + { + throw new ArgumentNullException(nameof(plane)); + } + if (count <= 0) + { + throw new ArgumentException("Количество изделий должно быть больше 0", nameof(count)); + } + + if (_shopStorage.SellPlanes(plane, count)) + { + _logger.LogInformation("Selling sucsess"); + return true; + } + _logger.LogInformation("Selling failed"); + return false; + } private void CheckModel(ShopBindingModel model, bool withParams = true) { if (model == null) diff --git a/AircraftPlant/AircraftPlantContracts»/BindingModels/ShopBindingModel.cs b/AircraftPlant/AircraftPlantContracts»/BindingModels/ShopBindingModel.cs index f371e22..2425ede 100644 --- a/AircraftPlant/AircraftPlantContracts»/BindingModels/ShopBindingModel.cs +++ b/AircraftPlant/AircraftPlantContracts»/BindingModels/ShopBindingModel.cs @@ -18,5 +18,6 @@ namespace AircraftPlantContracts.BindingModels get; set; } = new(); + public int MaxPlanes { get; set; } } } diff --git a/AircraftPlant/AircraftPlantContracts»/BusinessLogicsContracts/IShopLogic.cs b/AircraftPlant/AircraftPlantContracts»/BusinessLogicsContracts/IShopLogic.cs index 3c8ce2b..814c1f1 100644 --- a/AircraftPlant/AircraftPlantContracts»/BusinessLogicsContracts/IShopLogic.cs +++ b/AircraftPlant/AircraftPlantContracts»/BusinessLogicsContracts/IShopLogic.cs @@ -18,5 +18,6 @@ namespace AircraftPlantContracts.BusinessLogicsContracts bool Update(ShopBindingModel model); bool Delete(ShopBindingModel model); bool AddPlaneInShop(ShopSearchModel model, IPlaneModel plane, int count); + bool SellPlanes(IPlaneModel plane, int count); } } diff --git a/AircraftPlant/AircraftPlantContracts»/StoragesContracts/IShopStorage.cs b/AircraftPlant/AircraftPlantContracts»/StoragesContracts/IShopStorage.cs index 47b0af4..9f715bf 100644 --- a/AircraftPlant/AircraftPlantContracts»/StoragesContracts/IShopStorage.cs +++ b/AircraftPlant/AircraftPlantContracts»/StoragesContracts/IShopStorage.cs @@ -1,6 +1,7 @@ using AircraftPlantContracts.BindingModels; using AircraftPlantContracts.SearchModels; using AircraftPlantContracts.ViewModels; +using AircraftPlantDataModels.Models; using System; using System.Collections.Generic; using System.Linq; @@ -17,5 +18,7 @@ namespace AircraftPlantContracts.StoragesContracts ShopViewModel? Insert(ShopBindingModel model); ShopViewModel? Update(ShopBindingModel model); ShopViewModel? Delete(ShopBindingModel model); + bool SellPlanes(IPlaneModel model, int count); + bool CheckCount(IPlaneModel model, int count); } } diff --git a/AircraftPlant/AircraftPlantContracts»/ViewModels/ShopViewModel.cs b/AircraftPlant/AircraftPlantContracts»/ViewModels/ShopViewModel.cs index b65d879..26c6566 100644 --- a/AircraftPlant/AircraftPlantContracts»/ViewModels/ShopViewModel.cs +++ b/AircraftPlant/AircraftPlantContracts»/ViewModels/ShopViewModel.cs @@ -22,5 +22,7 @@ namespace AircraftPlantContracts.ViewModels get; set; } = new(); + [DisplayName("Максимальное количество изделий")] + public int MaxPlanes { get; set; } } } diff --git a/AircraftPlant/AircraftPlantDataModels/IShopModel.cs b/AircraftPlant/AircraftPlantDataModels/IShopModel.cs index 43e1362..21fe206 100644 --- a/AircraftPlant/AircraftPlantDataModels/IShopModel.cs +++ b/AircraftPlant/AircraftPlantDataModels/IShopModel.cs @@ -12,5 +12,6 @@ namespace AircraftPlantDataModels.Models string Address { get; } DateTime DateOpening { get; } Dictionary ShopPlanes { get; } + int MaxPlanes { get; } } } diff --git a/AircraftPlant/AircraftPlantFileImplement/DataFileSingleton.cs b/AircraftPlant/AircraftPlantFileImplement/DataFileSingleton.cs index 4d2ea23..1a3aa6f 100644 --- a/AircraftPlant/AircraftPlantFileImplement/DataFileSingleton.cs +++ b/AircraftPlant/AircraftPlantFileImplement/DataFileSingleton.cs @@ -14,9 +14,12 @@ namespace AircraftPlantFileImplement private readonly string ComponentFileName = "Component.xml"; private readonly string OrderFileName = "Order.xml"; private readonly string PlaneFileName = "Plane.xml"; + private readonly string ShopFileName = "Shop.xml"; public List Components { get; private set; } public List Orders { get; private set; } public List Planes { get; private set; } + public List Shops { get; set; } + public static DataFileSingleton GetInstance() { if (instance == null) @@ -28,11 +31,13 @@ namespace AircraftPlantFileImplement public void SaveComponents() => SaveData(Components, ComponentFileName, "Components", x => x.GetXElement); public void SavePlanes() => SaveData(Planes, PlaneFileName, "Planes", x => x.GetXElement); public void SaveOrders() => SaveData(Orders, OrderFileName, "Orders", x => x.GetXElement); + public void SaveShops() => SaveData(Shops, ShopFileName, "Shops", x => x.GetXEleme private DataFileSingleton() { Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!; Planes = LoadData(PlaneFileName, "Plane", x => Plane.Create(x)!)!; Orders = LoadData(OrderFileName, "Order", x => Order.Create(x)!)!; + Shops = LoadData(ShopFileName, "Shop", x => Shop.Create(x)!)!; } private static List? LoadData(string filename, string xmlNodeName, Func selectFunction) { diff --git a/AircraftPlant/AircraftPlantFileImplement/OrderStorage.cs b/AircraftPlant/AircraftPlantFileImplement/OrderStorage.cs index ca152f7..31e9bb8 100644 --- a/AircraftPlant/AircraftPlantFileImplement/OrderStorage.cs +++ b/AircraftPlant/AircraftPlantFileImplement/OrderStorage.cs @@ -8,6 +8,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Xml.Linq; namespace AircraftPlantFileImplement.Implements { @@ -20,7 +21,9 @@ namespace AircraftPlantFileImplement.Implements } public List GetFullList() { - return _source.Orders.Select(x => GetViewModel(x)).ToList(); + return _source.Orders + .Select(x => GetViewModel(x)) + .ToList(); } public List GetFilteredList(OrderSearchModel model) { @@ -28,7 +31,11 @@ namespace AircraftPlantFileImplement.Implements { return new(); } - return _source.Orders.Where(x => x.Id.Equals(model.Id)).Select(x => GetViewModel(x)).ToList(); + + return _source.Orders + .Where(x => x.Id.Equals(model.Id)) + .Select(x => GetViewModel(x)) + .ToList(); } public OrderViewModel? GetElement(OrderSearchModel model) { @@ -36,6 +43,7 @@ namespace AircraftPlantFileImplement.Implements { return null; } + return GetViewModel(_source.Orders.FirstOrDefault(x => (model.Id.HasValue && x.Id == model.Id))); } public OrderViewModel? Insert(OrderBindingModel model) @@ -47,6 +55,7 @@ namespace AircraftPlantFileImplement.Implements { return null; } + _source.Orders.Add(newOrder); _source.SaveOrders(); return GetViewModel(newOrder); @@ -58,6 +67,7 @@ namespace AircraftPlantFileImplement.Implements { return null; } + order.Update(model); _source.SaveOrders(); return GetViewModel(order); @@ -77,7 +87,10 @@ namespace AircraftPlantFileImplement.Implements { var viewModel = order.GetViewModel; var plane = _source.Planes.FirstOrDefault(x => x.Id == order.PlaneId); - viewModel.PlaneName = plane?.PlaneName; + if (plane != null) + { + viewModel.PlaneName = plane.PlaneName; + } return viewModel; } } diff --git a/AircraftPlant/AircraftPlantFileImplement/Shop.cs b/AircraftPlant/AircraftPlantFileImplement/Shop.cs new file mode 100644 index 0000000..347a33d --- /dev/null +++ b/AircraftPlant/AircraftPlantFileImplement/Shop.cs @@ -0,0 +1,102 @@ +using AircraftPlantContracts.BindingModels; +using AircraftPlantContracts.ViewModels; +using AircraftPlantDataModels.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace AircraftPlantFileImplement +{ + public class Shop : IShopModel + { + public int Id { get; private set; } + public string ShopName { get; private set; } = string.Empty; + public string Address { get; private set; } = string.Empty; + public DateTime DateOpening { get; private set; } + public Dictionary Planes { get; private set; } = new(); + private Dictionary? _shopPlanes = null; + public Dictionary ShopPlanes + { + get + { + if (_shopPlanes == null) + { + var source = DataFileSingleton.GetInstance(); + _shopPlanes = Planes.ToDictionary(x => x.Key, y => ((source.Planes.FirstOrDefault(z => z.Id == y.Key) as IPlaneModel)!, y.Value)); + } + return _shopPlanes; + } + } + public int MaxPlanes { get; private set; } + public static Shop? Create(XElement element) + { + if (element == null) + { + return null; + } + return new() + { + Id = Convert.ToInt32(element.Attribute("Id")!.Value), + ShopName = element.Element("ShopName")!.Value, + Address = element.Element("Address")!.Value, + DateOpening = Convert.ToDateTime(element.Element("DateOpening")!.Value), + Planes = element.Element("ShopPlanes")!.Elements("ShopPlanes")! + .ToDictionary(x => Convert.ToInt32(x.Element("Key")?.Value), x => Convert.ToInt32(x.Element("Value")?.Value)), + MaxPlanes = Convert.ToInt32(element.Element("MaxPlanes")!.Value) + }; + } + public static Shop? Create(ShopBindingModel? model) + { + if (model == null) + { + return null; + } + + return new Shop() + { + Id = model.Id, + ShopName = model.ShopName, + Address = model.Address, + DateOpening = model.DateOpening, + Planes = model.ShopPlanes.ToDictionary(x => x.Key, x => x.Value.Item2), + MaxPlanes = model.MaxPlanes + }; + } + public void Update(ShopBindingModel? model) + { + if (model == null) + { + return; + } + + ShopName = model.ShopName; + Address = model.Address; + DateOpening = model.DateOpening; + Planes = model.ShopPlanes.ToDictionary(x => x.Key, x => x.Value.Item2); + MaxPlanes = model.MaxPlanes; + _shopPlanes = null; + } + public ShopViewModel GetViewModel => new() + { + Id = Id, + ShopName = ShopName, + Address = Address, + DateOpening = DateOpening, + ShopPlanes = ShopPlanes, + MaxPlanes = MaxPlanes + }; + public XElement GetXElement => new("Shop", + new XAttribute("Id", Id), + new XElement("ShopName", ShopName), + new XElement("Address", Address), + new XElement("DateOpening", DateOpening.ToString()), + new XElement("ShopPlanes", Planes.Select(x => + new XElement("ShopPlanes", + new XElement("Key", x.Key), + new XElement("Value", x.Value))).ToArray()), + new XElement("MaxPlanes", MaxPlanes.ToString())); + } +} \ No newline at end of file diff --git a/AircraftPlant/AircraftPlantFileImplement/ShopStorage.cs b/AircraftPlant/AircraftPlantFileImplement/ShopStorage.cs new file mode 100644 index 0000000..32b7786 --- /dev/null +++ b/AircraftPlant/AircraftPlantFileImplement/ShopStorage.cs @@ -0,0 +1,138 @@ +using AircraftPlantContracts.BindingModels; +using AircraftPlantContracts.SearchModels; +using AircraftPlantContracts.StoragesContracts; +using AircraftPlantContracts.ViewModels; +using AircraftPlantDataModels.Models; +using AircraftPlantFileImplement; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using System.Threading.Tasks; + +namespace AircraftPlantFileImplement +{ + public class ShopStorage : IShopStorage + { + private readonly DataFileSingleton _source; + public ShopStorage() + { + _source = DataFileSingleton.GetInstance(); + } + public List GetFullList() + { + return _source.Shops + .Select(x => x.GetViewModel) + .ToList(); + } + public List GetFilteredList(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName)) + { + return new(); + } + + return _source.Shops + .Where(x => x.ShopName.Contains(model.ShopName)) + .Select(x => x.GetViewModel) + .ToList(); + } + public ShopViewModel? GetElement(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName) && !model.Id.HasValue) + { + return null; + } + + return _source.Shops + .FirstOrDefault(x => + (!string.IsNullOrEmpty(model.ShopName) && + x.ShopName == model.ShopName) || + (model.Id.HasValue && x.Id == model.Id)) + ?.GetViewModel; + } + public ShopViewModel? Insert(ShopBindingModel model) + { + model.Id = _source.Shops.Count > 0 ? _source.Shops.Max(x => x.Id) + 1 : 1; + + var newShop = Shop.Create(model); + if (newShop == null) + { + return null; + } + + _source.Shops.Add(newShop); + _source.SaveShops(); + return newShop.GetViewModel; + } + public ShopViewModel? Update(ShopBindingModel model) + { + var shop = _source.Shops.FirstOrDefault(x => x.Id == model.Id); + if (shop == null) + { + return null; + } + + shop.Update(model); + _source.SaveShops(); + return shop.GetViewModel; + } + public ShopViewModel? Delete(ShopBindingModel model) + { + var element = _source.Shops.FirstOrDefault(x => x.Id == model.Id); + if (element != null) + { + _source.Shops.Remove(element); + _source.SaveShops(); + return element.GetViewModel; + } + return null; + } + public bool SellPlanes(IPlaneModel model, int count) + { + var plane = _source.Planes.FirstOrDefault(x => x.Id == model.Id); + if (plane == null || !CheckCount(model, count)) + { + return false; + } + + foreach (var shop in _source.Shops) + { + var planes = shop.ShopPlanes; + foreach (var elem in planes.Where(x => x.Value.Item1.Id == plane.Id)) + { + var selling = Math.Min(elem.Value.Item2, count); + planes[elem.Value.Item1.Id] = (elem.Value.Item1, elem.Value.Item2 - selling); + count -= selling; + + if (count <= 0) + { + break; + } + } + + shop.Update(new ShopBindingModel + { + Id = model.Id, + ShopName = shop.ShopName, + Address = shop.Address, + DateOpening = shop.DateOpening, + ShopPlanes = planes, + MaxPlanes = shop.MaxPlanes + }); + } + + _source.SaveShops(); + return true; + } + public bool CheckCount(IPlaneModel model, int count) + { + int store = _source.Shops + .Select(x => x.ShopPlanes + .Select(y => (y.Value.Item1.Id == model.Id ? y.Value.Item2 : 0)) + .Sum()).Sum(); + return store >= count; + } + } +}