diff --git a/Confectionery/Confectionery/FormShop.Designer.cs b/Confectionery/Confectionery/FormShop.Designer.cs index 1cdb588..d304929 100644 --- a/Confectionery/Confectionery/FormShop.Designer.cs +++ b/Confectionery/Confectionery/FormShop.Designer.cs @@ -40,6 +40,8 @@ this.PastryId = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.PastryName = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.Count = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.textBoxCapacity = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit(); this.SuspendLayout(); // @@ -77,7 +79,7 @@ // // buttonCancel // - this.buttonCancel.Location = new System.Drawing.Point(376, 276); + this.buttonCancel.Location = new System.Drawing.Point(376, 313); this.buttonCancel.Name = "buttonCancel"; this.buttonCancel.Size = new System.Drawing.Size(94, 29); this.buttonCancel.TabIndex = 7; @@ -87,7 +89,7 @@ // // buttonSave // - this.buttonSave.Location = new System.Drawing.Point(276, 276); + this.buttonSave.Location = new System.Drawing.Point(276, 313); this.buttonSave.Name = "buttonSave"; this.buttonSave.Size = new System.Drawing.Size(94, 29); this.buttonSave.TabIndex = 6; @@ -120,7 +122,7 @@ this.PastryId, this.PastryName, this.Count}); - this.dataGridView.Location = new System.Drawing.Point(120, 105); + this.dataGridView.Location = new System.Drawing.Point(120, 142); this.dataGridView.MultiSelect = false; this.dataGridView.Name = "dataGridView"; this.dataGridView.RowHeadersVisible = false; @@ -155,11 +157,29 @@ this.Count.ReadOnly = true; this.Count.Width = 125; // + // textBoxCapacity + // + this.textBoxCapacity.Location = new System.Drawing.Point(120, 105); + this.textBoxCapacity.Name = "textBoxCapacity"; + this.textBoxCapacity.Size = new System.Drawing.Size(350, 27); + this.textBoxCapacity.TabIndex = 16; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(11, 108); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(103, 20); + this.label3.TabIndex = 15; + this.label3.Text = "Вместимость:"; + // // FormShop // this.AutoScaleDimensions = new System.Drawing.SizeF(8F, 20F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(478, 317); + this.ClientSize = new System.Drawing.Size(478, 354); + this.Controls.Add(this.textBoxCapacity); + this.Controls.Add(this.label3); this.Controls.Add(this.dataGridView); this.Controls.Add(this.label2); this.Controls.Add(this.openingDateTimePicker); @@ -192,5 +212,7 @@ private DataGridViewTextBoxColumn PastryId; private DataGridViewTextBoxColumn PastryName; private DataGridViewTextBoxColumn Count; + private TextBox textBoxCapacity; + private Label label3; } } \ No newline at end of file diff --git a/Confectionery/Confectionery/FormShop.cs b/Confectionery/Confectionery/FormShop.cs index 8e48dbc..a1a749f 100644 --- a/Confectionery/Confectionery/FormShop.cs +++ b/Confectionery/Confectionery/FormShop.cs @@ -43,6 +43,11 @@ namespace Confectionery MessageBox.Show("Заполните адрес", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } + if (string.IsNullOrEmpty(textBoxCapacity.Text)) + { + MessageBox.Show("Заполните вместимость", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + return; + } _logger.LogInformation("Сохранение магазина"); try { @@ -52,6 +57,7 @@ namespace Confectionery ShopName = textBoxName.Text, ShopAdress = textBoxAdress.Text, OpeningDate = openingDateTimePicker.Value.Date, + PastryCapacity = Convert.ToInt32(textBoxCapacity.Text), ShopPastries = _shopPastries }; var operationResult = _id.HasValue ? _logic.Update(model) : _logic.Create(model); @@ -83,6 +89,7 @@ namespace Confectionery textBoxName.Text = view.ShopName; textBoxAdress.Text = view.ShopAdress; openingDateTimePicker.Value = view.OpeningDate; + textBoxCapacity.Text = view.PastryCapacity.ToString(); _shopPastries = view.ShopPastries; foreach (var pc in view.ShopPastries) { diff --git a/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/OrderLogic.cs b/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/OrderLogic.cs index f35b2ce..aa757af 100644 --- a/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/OrderLogic.cs +++ b/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/OrderLogic.cs @@ -17,11 +17,13 @@ namespace ConfectioneryBusinessLogic.BusinessLogics { private readonly ILogger _logger; private readonly IOrderStorage _orderStorage; + private readonly IShopStorage _shopStorage; - public OrderLogic(ILogger logger, IOrderStorage orderStorage) + public OrderLogic(ILogger logger, IOrderStorage orderStorage, IShopStorage shopStorage) { _logger = logger; _orderStorage = orderStorage; + _shopStorage = shopStorage; } public bool CreateOrder(OrderBindingModel model) @@ -54,6 +56,7 @@ namespace ConfectioneryBusinessLogic.BusinessLogics _logger.LogWarning("Status change operation failed"); throw new InvalidOperationException("Заказ должен быть переведен в статус готовности перед выдачей!"); } + model.Status = OrderStatus.Выдан; model.DateImplement = DateTime.Now; _orderStorage.Update(model); @@ -77,6 +80,8 @@ namespace ConfectioneryBusinessLogic.BusinessLogics _logger.LogWarning("Status change operation failed"); throw new InvalidOperationException("Заказ должен быть переведен в статус выполнения перед готовностью!"); } + bool hasFreeSpace = _shopStorage.Supply(element.PastryId, element.Count); + if (!hasFreeSpace) throw new InvalidOperationException("В магазинах недостаточно места, чтобы вместить данный заказ!"); model.Status = OrderStatus.Готов; _orderStorage.Update(model); return true; diff --git a/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/ShopLogic.cs b/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/ShopLogic.cs index 1ba2248..c4b8908 100644 --- a/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/ShopLogic.cs +++ b/Confectionery/ConfectioneryBusinessLogic/BusinessLogics/ShopLogic.cs @@ -106,6 +106,10 @@ namespace ConfectioneryBusinessLogic.BusinessLogics { throw new ArgumentNullException("Нет адресса иагазина", nameof(model.ShopAdress)); } + if (model.PastryCapacity <= 0) + { + throw new InvalidOperationException("Вместимоcть должна быть больше 0"); + } _logger.LogInformation("Shop. ShopName:{ShopName}. Id:{Id}", model.ShopName, model.Id); var element = _shopStorage.GetElement(new ShopSearchModel { @@ -152,7 +156,8 @@ namespace ConfectioneryBusinessLogic.BusinessLogics ShopName = element.ShopName, ShopAdress = element.ShopAdress, OpeningDate = element.OpeningDate, - ShopPastries = element.ShopPastries + ShopPastries = element.ShopPastries, + PastryCapacity = element.PastryCapacity }); return true; } diff --git a/Confectionery/ConfectioneryContracts/BindingModels/ShopBindingModel.cs b/Confectionery/ConfectioneryContracts/BindingModels/ShopBindingModel.cs index fcaec17..c21554a 100644 --- a/Confectionery/ConfectioneryContracts/BindingModels/ShopBindingModel.cs +++ b/Confectionery/ConfectioneryContracts/BindingModels/ShopBindingModel.cs @@ -12,6 +12,7 @@ namespace ConfectioneryContracts.BindingModels public int Id { get; set; } public string ShopName { get; set; } = string.Empty; public string ShopAdress { get; set; } = string.Empty; + public int PastryCapacity { get; set; } public DateTime OpeningDate { get; set; } public Dictionary ShopPastries { diff --git a/Confectionery/ConfectioneryContracts/StoragesContracts/IShopStorage.cs b/Confectionery/ConfectioneryContracts/StoragesContracts/IShopStorage.cs index 86d0e18..fe832ea 100644 --- a/Confectionery/ConfectioneryContracts/StoragesContracts/IShopStorage.cs +++ b/Confectionery/ConfectioneryContracts/StoragesContracts/IShopStorage.cs @@ -1,6 +1,7 @@ using ConfectioneryContracts.BindingModels; using ConfectioneryContracts.SearchModels; using ConfectioneryContracts.ViewModels; +using ConfectioneryDataModels.Models; using System; using System.Collections.Generic; using System.Linq; @@ -17,5 +18,7 @@ namespace ConfectioneryContracts.StoragesContracts ShopViewModel? Insert(ShopBindingModel model); ShopViewModel? Update(ShopBindingModel model); ShopViewModel? Delete(ShopBindingModel model); + bool Supply(int pastryId, int count); + bool Sell(int pastryId, int count); } } diff --git a/Confectionery/ConfectioneryContracts/ViewModels/ShopViewModel.cs b/Confectionery/ConfectioneryContracts/ViewModels/ShopViewModel.cs index d904197..7d5b1fe 100644 --- a/Confectionery/ConfectioneryContracts/ViewModels/ShopViewModel.cs +++ b/Confectionery/ConfectioneryContracts/ViewModels/ShopViewModel.cs @@ -17,6 +17,8 @@ namespace ConfectioneryContracts.ViewModels public string ShopAdress { get; set; } = String.Empty; [DisplayName("Дата открытия")] public DateTime OpeningDate { get; set; } + [DisplayName("Макс. вместимость")] + public int PastryCapacity { get; set; } public Dictionary ShopPastries { get; diff --git a/Confectionery/ConfectioneryDataModels/Models/IShopModel.cs b/Confectionery/ConfectioneryDataModels/Models/IShopModel.cs index 307a2eb..26c6a01 100644 --- a/Confectionery/ConfectioneryDataModels/Models/IShopModel.cs +++ b/Confectionery/ConfectioneryDataModels/Models/IShopModel.cs @@ -10,6 +10,7 @@ namespace ConfectioneryDataModels.Models { string ShopName { get; } string ShopAdress { get; } + int PastryCapacity { get; } DateTime OpeningDate { get; } Dictionary ShopPastries { get; } } diff --git a/Confectionery/ConfectioneryFileImplements/DataFileSingleton.cs b/Confectionery/ConfectioneryFileImplements/DataFileSingleton.cs index 53fc38f..91a7f6b 100644 --- a/Confectionery/ConfectioneryFileImplements/DataFileSingleton.cs +++ b/Confectionery/ConfectioneryFileImplements/DataFileSingleton.cs @@ -15,9 +15,11 @@ namespace ConfectioneryFileImplement private readonly string IngredientFileName = "Ingredient.xml"; private readonly string OrderFileName = "Order.xml"; private readonly string PastryFileName = "Pastry.xml"; + private readonly string ShopFileName = "Shop.xml"; public List Ingredients { get; private set; } public List Orders { get; private set; } public List Pastries { get; private set; } + public List Shops { get; private set; } public static DataFileSingleton GetInstance() { if (instance == null) @@ -29,11 +31,13 @@ namespace ConfectioneryFileImplement public void SaveIngredients() => SaveData(Ingredients, IngredientFileName, "Ingredients", x => x.GetXElement); public void SavePastries() => SaveData(Pastries, PastryFileName, "Pastries", x => x.GetXElement); public void SaveOrders() => SaveData(Orders, OrderFileName, "Orders", x => x.GetXElement); + public void SaveShops() => SaveData(Shops, ShopFileName, "Shops", x => x.GetXElement); private DataFileSingleton() { Ingredients = LoadData(IngredientFileName, "Ingredient", x => Ingredient.Create(x)!)!; Pastries = LoadData(PastryFileName, "Pastry", x => Pastry.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/Confectionery/ConfectioneryFileImplements/Implements/ShopStorage.cs b/Confectionery/ConfectioneryFileImplements/Implements/ShopStorage.cs new file mode 100644 index 0000000..89f46c2 --- /dev/null +++ b/Confectionery/ConfectioneryFileImplements/Implements/ShopStorage.cs @@ -0,0 +1,166 @@ +using ConfectioneryContracts.BindingModels; +using ConfectioneryContracts.SearchModels; +using ConfectioneryContracts.StoragesContracts; +using ConfectioneryContracts.ViewModels; +using ConfectioneryDataModels.Models; +using ConfectioneryFileImplement.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Text; +using System.Threading.Tasks; + +namespace ConfectioneryFileImplement.Implements +{ + 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 pastry = source.Shops.FirstOrDefault(x => x.Id == model.Id); + if (pastry == null) + { + return null; + } + pastry.Update(model); + source.SaveShops(); + return pastry.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 Supply(int pastryId, int count) + { + int freeSpace = source.Shops.Select(x => x.PastryCapacity - x.ShopPastries.Select(y => y.Value.Item2).Sum()).Sum(); + if (freeSpace < count) + { + return false; + } + foreach (Shop shop in source.Shops){ + int freeShopSpace = shop.PastryCapacity - shop.ShopPastries.Select(y => y.Value.Item2).Sum(); + if (freeShopSpace > 0) + { + if (freeShopSpace >= count) + { + if (shop.Pastries.ContainsKey(pastryId)) + { + shop.Pastries[pastryId] += count; + } + else + { + shop.Pastries.Add(pastryId, count); + } + shop.setShopPastriesNull(); + return true; + } + else + { + int dif = count - freeShopSpace; + count -= freeShopSpace; + if (shop.Pastries.TryGetValue(pastryId, out var pastryCount)) + { + shop.Pastries[pastryId] = pastryCount + count; + } + else + { + shop.Pastries.Add(pastryId, count); + } + shop.setShopPastriesNull(); + } + } + } + return false; + } + + public bool Sell(int pastryId, int count) + { + int pastryCount = source.Shops.Select(x => x.ShopPastries.Select(y => y.Value).Where(y => y.Item1.Id == pastryId).Sum(y => y.Item2)).Sum(); + if (pastryCount < count) + { + return false; + } + foreach (Shop shop in source.Shops) + { + int shopPastryCount = shop.ShopPastries.Select(x => x.Value).Where(x => x.Item1.Id == pastryId).Sum(x => x.Item2); + if (count - shopPastryCount >= 0) + { + count -= shopPastryCount; + shop.Pastries.Remove(pastryId); + shop.setShopPastriesNull(); + } + else + { + count = 0; + shop.Pastries[pastryId] -= count; + shop.setShopPastriesNull(); + } + if (count == 0) + { + source.SaveShops(); + return true; + } + } + return false; + } + } +} diff --git a/Confectionery/ConfectioneryFileImplements/Models/Pastry.cs b/Confectionery/ConfectioneryFileImplements/Models/Pastry.cs index 2bb7093..c9581d0 100644 --- a/Confectionery/ConfectioneryFileImplements/Models/Pastry.cs +++ b/Confectionery/ConfectioneryFileImplements/Models/Pastry.cs @@ -10,7 +10,7 @@ using System.Xml.Linq; namespace ConfectioneryFileImplement.Models { - public class Pastry + public class Pastry : IPastryModel { public int Id { get; private set; } public string PastryName { get; private set; } = string.Empty; diff --git a/Confectionery/ConfectioneryFileImplements/Models/Shop.cs b/Confectionery/ConfectioneryFileImplements/Models/Shop.cs new file mode 100644 index 0000000..b9be455 --- /dev/null +++ b/Confectionery/ConfectioneryFileImplements/Models/Shop.cs @@ -0,0 +1,104 @@ +using ConfectioneryContracts.BindingModels; +using ConfectioneryContracts.ViewModels; +using ConfectioneryDataModels.Models; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace ConfectioneryFileImplement.Models +{ + public class Shop : IShopModel + { + public int Id { get; private set; } + public string ShopName { get; private set; } = string.Empty; + public string ShopAdress { get; private set; } = string.Empty; + public int PastryCapacity { get; private set; } + public DateTime OpeningDate { get; private set; } + public Dictionary Pastries { get; private set; } = new(); + private Dictionary? _shopPastries = null; + public Dictionary ShopPastries + { + get + { + if (_shopPastries == null) + { + var source = DataFileSingleton.GetInstance(); + _shopPastries = Pastries.ToDictionary(x => x.Key, y => ((source.Pastries.FirstOrDefault(z => z.Id == y.Key) as IPastryModel)!, y.Value)); + } + return _shopPastries; + } + } + public static Shop? Create(ShopBindingModel? model) + { + if (model == null) + { + return null; + } + return new Shop() + { + Id = model.Id, + ShopName = model.ShopName, + ShopAdress = model.ShopAdress, + OpeningDate = model.OpeningDate, + Pastries = model.ShopPastries.ToDictionary(x => x.Key, x => x.Value.Item2), + PastryCapacity = model.PastryCapacity + }; + } + public static Shop? Create(XElement element) + { + if (element == null) + { + return null; + } + return new Shop() + { + Id = Convert.ToInt32(element.Attribute("Id")!.Value), + ShopName = element.Element("ShopName")!.Value, + ShopAdress = element.Element("ShopAdress")!.Value, + PastryCapacity = Convert.ToInt32(element.Element("PastryCapacity")!.Value), + OpeningDate = Convert.ToDateTime(element.Element("OpeningDate")!.Value), + Pastries = element.Element("ShopPastries")!.Elements("ShopPastry").ToDictionary(x => Convert.ToInt32(x.Element("Key")?.Value), x => Convert.ToInt32(x.Element("Value")?.Value)) + }; + } + public void Update(ShopBindingModel? model) + { + if (model == null) + { + return; + } + ShopName = model.ShopName; + ShopAdress = model.ShopAdress; + OpeningDate = model.OpeningDate; + Pastries = model.ShopPastries.ToDictionary(x => x.Key, x => x.Value.Item2); + _shopPastries = null; + PastryCapacity = model.PastryCapacity; + } + public ShopViewModel GetViewModel => new() + { + Id = Id, + ShopName = ShopName, + ShopAdress = ShopAdress, + ShopPastries = ShopPastries, + OpeningDate = OpeningDate, + PastryCapacity = PastryCapacity, + }; + internal void setShopPastriesNull() + { + _shopPastries = null; + } + public XElement GetXElement => new("Shop", + new XAttribute("Id", Id), + new XElement("ShopName", ShopName), + new XElement("ShopAdress", ShopAdress), + new XElement("PastryCapacity", PastryCapacity.ToString()), + new XElement("OpeningDate", OpeningDate.ToString()), + new XElement("ShopPastries", Pastries.Select(x => new XElement("ShopPastry", + new XElement("Key", x.Key), + new XElement("Value", x.Value))) + .ToArray())); + } +} diff --git a/Confectionery/ConfectioneryListImplement/Implements/ShopStorage.cs b/Confectionery/ConfectioneryListImplement/Implements/ShopStorage.cs index f95cb0a..6e89a0d 100644 --- a/Confectionery/ConfectioneryListImplement/Implements/ShopStorage.cs +++ b/Confectionery/ConfectioneryListImplement/Implements/ShopStorage.cs @@ -2,6 +2,7 @@ using ConfectioneryContracts.SearchModels; using ConfectioneryContracts.StoragesContracts; using ConfectioneryContracts.ViewModels; +using ConfectioneryDataModels.Models; using ConfectioneryListImplement.Models; using System; using System.Collections.Generic; @@ -107,5 +108,15 @@ namespace ConfectioneryListImplement.Implements } return null; } + + public bool Supply(int pastryId, int count) + { + throw new NotImplementedException(); + } + + public bool Sell(int pastryId, int count) + { + throw new NotImplementedException(); + } } } diff --git a/Confectionery/ConfectioneryListImplement/Models/Shop.cs b/Confectionery/ConfectioneryListImplement/Models/Shop.cs index c264be8..56a5728 100644 --- a/Confectionery/ConfectioneryListImplement/Models/Shop.cs +++ b/Confectionery/ConfectioneryListImplement/Models/Shop.cs @@ -15,6 +15,7 @@ namespace ConfectioneryListImplement.Models public int Id { get; private set; } public string ShopName { get; private set; } = string.Empty; public string ShopAdress { get; private set; } = string.Empty; + public int PastryCapacity { get; private set; } public DateTime OpeningDate { get; private set; } public Dictionary ShopPastries { get; private set; } = new Dictionary(); public static Shop? Create(ShopBindingModel? model) @@ -29,7 +30,8 @@ namespace ConfectioneryListImplement.Models ShopName = model.ShopName, ShopAdress = model.ShopAdress, OpeningDate = model.OpeningDate, - ShopPastries = model.ShopPastries + ShopPastries = model.ShopPastries, + PastryCapacity = model.PastryCapacity }; } public void Update(ShopBindingModel? model) @@ -42,6 +44,7 @@ namespace ConfectioneryListImplement.Models ShopAdress = model.ShopAdress; OpeningDate = model.OpeningDate; ShopPastries = model.ShopPastries; + PastryCapacity = model.PastryCapacity; } public ShopViewModel GetViewModel => new() { @@ -49,7 +52,8 @@ namespace ConfectioneryListImplement.Models ShopName = ShopName, ShopAdress = ShopAdress, ShopPastries = ShopPastries, - OpeningDate = OpeningDate + OpeningDate = OpeningDate, + PastryCapacity = PastryCapacity, }; } }