diff --git a/SewingDresses/SewingDressesBusinessLogic/BusinessLogic/OrderLogic.cs b/SewingDresses/SewingDressesBusinessLogic/BusinessLogic/OrderLogic.cs index a99f4f3..d8a2e54 100644 --- a/SewingDresses/SewingDressesBusinessLogic/BusinessLogic/OrderLogic.cs +++ b/SewingDresses/SewingDressesBusinessLogic/BusinessLogic/OrderLogic.cs @@ -5,6 +5,8 @@ using SewingDressesContracts.SearchModels; using SewingDressesContracts.StoragesContracts; using SewingDressesContracts.ViewModels; using SewingDressesDataModels.Enums; +using SewingDressesDataModels.Models; +using System.Collections.Specialized; namespace SewingDressesBusinessLogic.BusinessLogic { @@ -12,11 +14,16 @@ namespace SewingDressesBusinessLogic.BusinessLogic { private readonly ILogger _logger; private readonly IOrderStorage _orderStorage; - - public OrderLogic(ILogger logger, IOrderStorage orderStorage) + private readonly IShopStorage _shopStorage; + private readonly IShopLogic _shopLogic; + private readonly IDressStorage _dressStorage; + public OrderLogic(ILogger logger, IOrderStorage orderStorage, IShopStorage shopStorage, IShopLogic shopLogic, IDressStorage dressStorage) { _logger = logger; _orderStorage = orderStorage; + _shopStorage = shopStorage; + _shopLogic = shopLogic; + _dressStorage = dressStorage; } public List? ReadList(OrderSearchModel? model) @@ -99,5 +106,65 @@ namespace SewingDressesBusinessLogic.BusinessLogic { return ChangeStatus(model, OrderStatus.Выдан); } + + public bool CheckSupply(IDressModel dress, int count) + { + if (count <= 0) + { + _logger.LogWarning("Check supply operation error. Dress count < 0"); + return false; + } + int sumCapacity = _shopStorage.GetFullList().Select(x => x.MaxCount).Sum(); + int sumCount = _shopStorage.GetFullList().Select(x => x.ShopDresses.Select(y => y.Value.Item2).Sum()).Sum(); + int free = sumCapacity - sumCount; + + if (free < count) + { + _logger.LogWarning("Check supply error. No place for new Dresses"); + return false; + } + foreach (var shop in _shopStorage.GetFullList()) + { + free = shop.MaxCount; + foreach (var doc in shop.ShopDresses) + { + free -= doc.Value.Item2; + } + if (free == 0) + { + continue; + } + if (free >= count) + { + if (_shopLogic.MakeSupply(new() + { + Id = shop.Id + }, dress, count)) + { + count = 0; + } + else + { + _logger.LogWarning("Supply error"); + return false; + } + } + else + { + if (_shopLogic.MakeSupply(new() { Id = shop.Id}, dress, free)) + count -= free; + else + { + _logger.LogWarning("Supply error"); + return false; + } + } + if (count <= 0) + { + return true; + } + } + return false; + } } } diff --git a/SewingDresses/SewingDressesBusinessLogic/BusinessLogic/ShopLogic.cs b/SewingDresses/SewingDressesBusinessLogic/BusinessLogic/ShopLogic.cs index c2b15b0..0bae47f 100644 --- a/SewingDresses/SewingDressesBusinessLogic/BusinessLogic/ShopLogic.cs +++ b/SewingDresses/SewingDressesBusinessLogic/BusinessLogic/ShopLogic.cs @@ -119,6 +119,11 @@ namespace SewingDressesBusinessLogic.BusinessLogic throw new InvalidOperationException("Магазин с таким названием уже есть"); } } + + public bool MakeSell(IDressModel model, int count) + { + return _shopStorage.SellDresses(model, count); + } public bool MakeSupply(ShopSearchModel model, IDressModel dress, int count) { if (model == null) @@ -132,15 +137,23 @@ namespace SewingDressesBusinessLogic.BusinessLogic _logger.LogInformation("Make Supply. Id: {Id}. ShopName: {Name}",model.Id, model.Name); if (curModel == null) throw new ArgumentNullException(nameof(curModel)); + + var countItems = curModel.ShopDresses.Select(x => x.Value.Item2).Sum(); + if (curModel.MaxCount - countItems < count) + { + _logger.LogWarning("Shop is overflowed"); + return false; + } + if (curModel.ShopDresses.TryGetValue(dress.Id, out var pair)) { curModel.ShopDresses[dress.Id] = (pair.Item1, pair.Item2 + count); - _logger.LogInformation("Make Supply. Add Dress. DressName: {Name}. Count: {Count}", pair.Item1, count + pair.Item2); + _logger.LogInformation("Make Supply. Add Dress. ShopName: {ShopName}. DressName: {Name}. Count: {Count}", curModel.ShopName, pair.Item1, count + pair.Item2); } else { curModel.ShopDresses.Add(dress.Id, (dress, count)); - _logger.LogInformation("Make Supply. Add new Dress. DressName: {Name}. Count: {Count}", pair.Item1, count); + _logger.LogInformation("Make Supply. Add new Dress. ShopName: {ShopName}. DressName: {Name}. Count: {Count}", curModel.ShopName, pair.Item1, count); } return Update(new() diff --git a/SewingDresses/SewingDressesContracts/BindingModels/ShopBindingModel.cs b/SewingDresses/SewingDressesContracts/BindingModels/ShopBindingModel.cs index 6ae5676..e3b5ec6 100644 --- a/SewingDresses/SewingDressesContracts/BindingModels/ShopBindingModel.cs +++ b/SewingDresses/SewingDressesContracts/BindingModels/ShopBindingModel.cs @@ -13,6 +13,7 @@ namespace SewingDressesContracts.BindingModels public string ShopName { get; set; } public string Adress { get; set; } public DateTime DateOpen { get; set; } + public int MaxCount { get; set; } public Dictionary ShopDresses { get; set; } = new(); } } diff --git a/SewingDresses/SewingDressesContracts/BusinessLogicsContracts/IShopLogic.cs b/SewingDresses/SewingDressesContracts/BusinessLogicsContracts/IShopLogic.cs index 56f29cc..d716469 100644 --- a/SewingDresses/SewingDressesContracts/BusinessLogicsContracts/IShopLogic.cs +++ b/SewingDresses/SewingDressesContracts/BusinessLogicsContracts/IShopLogic.cs @@ -18,5 +18,6 @@ namespace SewingDressesContracts.BusinessLogicsContracts bool Update (ShopBindingModel? model); bool Delete (ShopBindingModel? model); bool MakeSupply(ShopSearchModel model, IDressModel dress, int count); + bool MakeSell(IDressModel model, int count); } } diff --git a/SewingDresses/SewingDressesContracts/StoragesContracts/IShopStorage.cs b/SewingDresses/SewingDressesContracts/StoragesContracts/IShopStorage.cs index b47e78c..3e7992e 100644 --- a/SewingDresses/SewingDressesContracts/StoragesContracts/IShopStorage.cs +++ b/SewingDresses/SewingDressesContracts/StoragesContracts/IShopStorage.cs @@ -18,5 +18,6 @@ namespace SewingDressesContracts.StoragesContracts ShopViewModel? Insert(ShopBindingModel model); ShopViewModel? Update(ShopBindingModel model); ShopViewModel? Delete(ShopBindingModel model); + bool SellDresses(IDressModel model, int count); } } diff --git a/SewingDresses/SewingDressesContracts/ViewModels/ShopViewModel.cs b/SewingDresses/SewingDressesContracts/ViewModels/ShopViewModel.cs index 9d7d47f..cb17fbd 100644 --- a/SewingDresses/SewingDressesContracts/ViewModels/ShopViewModel.cs +++ b/SewingDresses/SewingDressesContracts/ViewModels/ShopViewModel.cs @@ -17,6 +17,8 @@ namespace SewingDressesContracts.ViewModels public string Adress { get; set; } = string.Empty; [DisplayName("Дата открытия")] public DateTime DateOpen { get; set; } + [DisplayName("Вмещаемость")] + public int MaxCount { get; set; } public Dictionary ShopDresses { get; set; } = new(); } } diff --git a/SewingDresses/SewingDressesDataModels/Models/IShopModel.cs b/SewingDresses/SewingDressesDataModels/Models/IShopModel.cs index a423ef5..d39b30a 100644 --- a/SewingDresses/SewingDressesDataModels/Models/IShopModel.cs +++ b/SewingDresses/SewingDressesDataModels/Models/IShopModel.cs @@ -11,5 +11,6 @@ namespace SewingDressesDataModels.Models string ShopName { get; } string Adress { get; } DateTime DateOpen { get; } + int MaxCount { get; } } } diff --git a/SewingDresses/SewingDressesFileImplement/DataFileSingleton.cs b/SewingDresses/SewingDressesFileImplement/DataFileSingleton.cs index 27d6d67..e192233 100644 --- a/SewingDresses/SewingDressesFileImplement/DataFileSingleton.cs +++ b/SewingDresses/SewingDressesFileImplement/DataFileSingleton.cs @@ -9,9 +9,11 @@ namespace SewingDressesFileImplement private readonly string ComponentFileName = "Component.xml"; private readonly string OrderFileName = "Order.xml"; private readonly string DressFileName = "Dress.xml"; + private readonly string ShopFileName = "Shop.xml"; public List Components { get; private set; } public List Orders { get; private set; } public List Dresses { get; private set;} + public List Shops { get; private set; } public static DataFileSingleton GetInstance() { if (instance == null) @@ -39,11 +41,13 @@ namespace SewingDressesFileImplement public void SaveComponents() => SaveData(Components, ComponentFileName, "Components", x => x.GetXElement); public void SaveDresses() => SaveData(Dresses, DressFileName, "Dresses", 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() { Components = LoadData(ComponentFileName, "Component", x => Component.Create(x)!)!; Dresses = LoadData(DressFileName, "Dress", x => Dress.Create(x)!)!; Orders = LoadData(OrderFileName, "Order", x => Order.Create(x)!)!; + Shops = LoadData(ShopFileName, "Shop", x => Shop.Create(x)!)!; } } } diff --git a/SewingDresses/SewingDressesFileImplement/Implements/ShopStorage.cs b/SewingDresses/SewingDressesFileImplement/Implements/ShopStorage.cs new file mode 100644 index 0000000..2da86f4 --- /dev/null +++ b/SewingDresses/SewingDressesFileImplement/Implements/ShopStorage.cs @@ -0,0 +1,121 @@ +using SewingDressesContracts.BindingModels; +using SewingDressesContracts.SearchModels; +using SewingDressesContracts.StoragesContracts; +using SewingDressesContracts.ViewModels; +using SewingDressesDataModels.Models; +using SewingDressesFileImplement.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SewingDressesFileImplement.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.Name)) + { + return new(); + } + return _source.Shops.Where(x => x.ShopName.Contains(model.Name)).Select(x => x.GetViewModel).ToList(); + + } + public ShopViewModel? GetElement(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.Name) && !model.Id.HasValue) + { + return null; + } + return _source.Shops.FirstOrDefault(x => (!string.IsNullOrEmpty(model.Name) && x.ShopName == model.Name) || (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 component = _source.Shops.FirstOrDefault(x => x.Id == model.Id); + if (component == null) + { + return null; + } + component.Update(model); + _source.SaveShops(); + return component.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 CheckAvailability(int dressId, int count) + { + int store = _source.Shops.Select(x => x.ShopDresses.Select(y => (y.Value.Item1.Id == dressId ? y.Value.Item2 : 0)).Sum()).Sum(); + return store >= count; + } + public bool SellDresses(IDressModel model, int count) + { + var dres = _source.Dresses.FirstOrDefault(x => x.Id == model.Id); + + if (dres == null || CheckAvailability(model.Id, count)) + { + return false; + } + + for (int i = 0; i < _source.Shops.Count; i++) + { + var shop = _source.Shops[i]; + var dresses = shop.ShopDresses; + foreach (var dress in dresses.Where(x => x.Value.Item1.Id == dres.Id)) + { + var selling = Math.Min(dress.Value.Item2, count); + dresses[dress.Value.Item1.Id] = (dress.Value.Item1, dress.Value.Item2 - selling); + + count -= selling; + + if (count <= 0) + { + break; + } + } + shop.Update(new ShopBindingModel + { + Id = model.Id, + ShopName = shop.ShopName, + Adress = shop.Adress, + MaxCount = shop.MaxCount, + DateOpen = shop.DateOpen, + ShopDresses = dresses + }); + } + _source.SaveShops(); + return true; + } + } +} diff --git a/SewingDresses/SewingDressesFileImplement/Models/Shop.cs b/SewingDresses/SewingDressesFileImplement/Models/Shop.cs new file mode 100644 index 0000000..f520ed1 --- /dev/null +++ b/SewingDresses/SewingDressesFileImplement/Models/Shop.cs @@ -0,0 +1,101 @@ +using SewingDressesContracts.BindingModels; +using SewingDressesContracts.ViewModels; +using SewingDressesDataModels.Models; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; + +namespace SewingDressesFileImplement.Models +{ + public class Shop : IShopModel + { + public int Id { get; private set; } + public string ShopName { get; private set; } + public string Adress { get; private set; } + public DateTime DateOpen { get; private set; } + public int MaxCount { get; private set; } + public Dictionary Dresses { get; private set; } = new(); + private Dictionary? _shopDresses = null; + public Dictionary ShopDresses + { + get + { + if (_shopDresses == null) + { + var source = DataFileSingleton.GetInstance(); + _shopDresses = Dresses.ToDictionary(x => x.Key, y => ((source.Dresses.FirstOrDefault(z => z.Id == y.Key) as IDressModel)!, y.Value)); + } + return _shopDresses; + } + } + public static Shop? Create(ShopBindingModel model) + { + if (model == null) + { + return null; + } + return new Shop() + { + Id = model.Id, + ShopName = model.ShopName, + Adress = model.Adress, + DateOpen = model.DateOpen, + MaxCount = model.MaxCount, + Dresses = model.ShopDresses.ToDictionary(x => x.Key, x => x.Value.Item2) + }; + } + 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, + Adress = element.Element("Adress")!.Value, + MaxCount = Convert.ToInt32(element.Element("MaxCount")!.Value), + DateOpen = Convert.ToDateTime(element.Element("DateOpen")!.Value), + Dresses = element.Element("ShopDresses")!.Elements("ShopDress").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; + Adress = model.Adress; + DateOpen = model.DateOpen; + MaxCount = model.MaxCount; + if (model.ShopDresses.Count > 0) + { + Dresses = model.ShopDresses.ToDictionary(x => x.Key, x => x.Value.Item2); + _shopDresses = null; + } + } + public ShopViewModel GetViewModel => new() + { + Id = Id, + ShopName = ShopName, + Adress = Adress, + DateOpen = DateOpen, + MaxCount = MaxCount, + ShopDresses = ShopDresses + }; + + public XElement GetXElement => new XElement("Shop", + new XAttribute("Id", Id), + new XElement("ShopName", ShopName), + new XElement("Adress", Adress), + new XElement("DateOpen", DateOpen), + new XElement("MaxCount", MaxCount), + new XElement("ShopDresses", Dresses.Select(x => new XElement("ShopDress", new XElement("Key", x.Key), new XElement("Value", x.Value))).ToArray())); + } +} diff --git a/SewingDresses/SewingDressesListImplement/Implements/ShopStorage.cs b/SewingDresses/SewingDressesListImplement/Implements/ShopStorage.cs index 8ad8513..1be6bfe 100644 --- a/SewingDresses/SewingDressesListImplement/Implements/ShopStorage.cs +++ b/SewingDresses/SewingDressesListImplement/Implements/ShopStorage.cs @@ -104,5 +104,48 @@ namespace SewingDressesListImplement.Implements } return null; } + + public bool CheckAvailability(int dressId, int count) + { + int store = _source.Shops.Select(x => x.ShopDresses.Select(y => (y.Value.Item1.Id == dressId ? y.Value.Item2 : 0)).Sum()).Sum(); + return store >= count; + } + public bool SellDresses(IDressModel model, int count) + { + var dres = _source.Dresses.FirstOrDefault(x => x.Id == model.Id); + + if (dres == null || CheckAvailability(model.Id, count)) + { + return false; + } + + for (int i = 0; i < _source.Shops.Count; i++) + { + var shop = _source.Shops[i]; + var dresses = shop.ShopDresses; + foreach( var dress in dresses.Where(x => x.Value.Item1.Id == dres.Id)) + { + var selling = Math.Min(dress.Value.Item2, count); + dresses[dress.Value.Item1.Id] = (dress.Value.Item1, dress.Value.Item2 - selling); + + count -= selling; + + if (count <= 0) + { + break; + } + } + shop.Update(new ShopBindingModel + { + Id = model.Id, + ShopName = shop.ShopName, + Adress = shop.Adress, + MaxCount = shop.MaxCount, + DateOpen = shop.DateOpen, + ShopDresses = dresses + }); + } + return true; + } } } diff --git a/SewingDresses/SewingDressesListImplement/Models/Shop.cs b/SewingDresses/SewingDressesListImplement/Models/Shop.cs index 3845ddf..02672cc 100644 --- a/SewingDresses/SewingDressesListImplement/Models/Shop.cs +++ b/SewingDresses/SewingDressesListImplement/Models/Shop.cs @@ -15,6 +15,7 @@ namespace SewingDressesListImplement.Models public string ShopName { get; private set; } public string Adress { get; private set; } public DateTime DateOpen { get; private set; } + public int MaxCount { get; private set; } public Dictionary ShopDresses { get; private set; } = new(); public static Shop? Create (ShopBindingModel model) { @@ -28,6 +29,7 @@ namespace SewingDressesListImplement.Models ShopName = model.ShopName, Adress = model.Adress, DateOpen = model.DateOpen, + MaxCount = model.MaxCount, ShopDresses = new() }; } @@ -40,6 +42,7 @@ namespace SewingDressesListImplement.Models ShopName = model.ShopName; Adress = model.Adress; DateOpen = model.DateOpen; + MaxCount = model.MaxCount; ShopDresses = model.ShopDresses; } public ShopViewModel GetViewModel => new() @@ -48,6 +51,7 @@ namespace SewingDressesListImplement.Models ShopName = ShopName, Adress = Adress, DateOpen = DateOpen, + MaxCount = MaxCount, ShopDresses = ShopDresses }; } diff --git a/SewingDresses/SewingDressesView/MainForm.cs b/SewingDresses/SewingDressesView/MainForm.cs index a4ee92c..70644d5 100644 --- a/SewingDresses/SewingDressesView/MainForm.cs +++ b/SewingDresses/SewingDressesView/MainForm.cs @@ -160,5 +160,11 @@ namespace SewingDressesView form.ShowDialog(); } } + + private void MainForm_Load(object sender, EventArgs e) + { + LoadData(); + } + } } diff --git a/SewingDresses/SewingDressesView/ShopForm.Designer.cs b/SewingDresses/SewingDressesView/ShopForm.Designer.cs index 8623746..d9f618b 100644 --- a/SewingDresses/SewingDressesView/ShopForm.Designer.cs +++ b/SewingDresses/SewingDressesView/ShopForm.Designer.cs @@ -41,7 +41,10 @@ label1 = new Label(); label2 = new Label(); label3 = new Label(); + numeric = new NumericUpDown(); + label4 = new Label(); ((System.ComponentModel.ISupportInitialize)dataGridView).BeginInit(); + ((System.ComponentModel.ISupportInitialize)numeric).BeginInit(); SuspendLayout(); // // dateTimePicker @@ -107,7 +110,7 @@ // // buttonSave // - buttonSave.Location = new Point(714, 219); + buttonSave.Location = new Point(714, 248); buttonSave.Name = "buttonSave"; buttonSave.Size = new Size(94, 29); buttonSave.TabIndex = 4; @@ -117,7 +120,7 @@ // // buttonCancel // - buttonCancel.Location = new Point(870, 219); + buttonCancel.Location = new Point(870, 248); buttonCancel.Name = "buttonCancel"; buttonCancel.Size = new Size(94, 29); buttonCancel.TabIndex = 5; @@ -152,11 +155,29 @@ label3.TabIndex = 8; label3.Text = "Адрес"; // + // numeric + // + numeric.Location = new Point(714, 196); + numeric.Name = "numeric"; + numeric.Size = new Size(150, 27); + numeric.TabIndex = 9; + // + // label4 + // + label4.AutoSize = true; + label4.Location = new Point(592, 198); + label4.Name = "label4"; + label4.Size = new Size(100, 20); + label4.TabIndex = 10; + label4.Text = "Вместимость"; + // // ShopForm // AutoScaleDimensions = new SizeF(8F, 20F); AutoScaleMode = AutoScaleMode.Font; ClientSize = new Size(976, 450); + Controls.Add(label4); + Controls.Add(numeric); Controls.Add(label3); Controls.Add(label2); Controls.Add(label1); @@ -170,6 +191,7 @@ Text = "Форма магазина"; Load += ShopForm_Load; ((System.ComponentModel.ISupportInitialize)dataGridView).EndInit(); + ((System.ComponentModel.ISupportInitialize)numeric).EndInit(); ResumeLayout(false); PerformLayout(); } @@ -189,5 +211,7 @@ private DataGridViewTextBoxColumn Title; private DataGridViewTextBoxColumn Cost; private DataGridViewTextBoxColumn Count; + private NumericUpDown numeric; + private Label label4; } } \ No newline at end of file diff --git a/SewingDresses/SewingDressesView/ShopForm.cs b/SewingDresses/SewingDressesView/ShopForm.cs index 3d3224a..4917cda 100644 --- a/SewingDresses/SewingDressesView/ShopForm.cs +++ b/SewingDresses/SewingDressesView/ShopForm.cs @@ -41,7 +41,8 @@ namespace SewingDressesView textBoxName.Text = shop.ShopName; textBoxAdress.Text = shop.Adress; dateTimePicker.Text = shop.DateOpen.ToString(); - _dresses = shop.ShopDresses; + numeric.Value = shop.MaxCount; + _dresses = shop.ShopDresses ?? new Dictionary(); } LoadData(); } @@ -95,7 +96,7 @@ namespace SewingDressesView ShopName = textBoxName.Text, Adress = textBoxAdress.Text, DateOpen = dateTimePicker.Value.Date, - ShopDresses = _dresses + MaxCount = Convert.ToInt32(numeric.Value) }; var operationResult = _id.HasValue ? _logic.Update(model) : _logic.Create(model); if (!operationResult)