diff --git a/GarmentFactoryDatabaseImplement/Implements/ShopStorage.cs b/GarmentFactoryDatabaseImplement/Implements/ShopStorage.cs new file mode 100644 index 0000000..23d87c4 --- /dev/null +++ b/GarmentFactoryDatabaseImplement/Implements/ShopStorage.cs @@ -0,0 +1,243 @@ +using GarmentFactoryContracts.SearchModels; +using GarmentFactoryContracts.StoragesContracts; +using GarmentFactoryContracts.ViewModels; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using GarmentFactoryContracts.BindingModels; +using GarmentFactoryDatabaseImplement.Models; + +namespace GarmentFactoryDatabaseImplement.Implements +{ + public class ShopStorage : IShopStorage + { + public List GetFullList() + { + using var context = new GarmentFactoryDatabase(); + return context.Shops + .Include(x => x.Textiles) + .ThenInclude(x => x.Textile) + .ToList() + .Select(x => x.GetViewModel) + .ToList(); + } + + public List GetFilteredList(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName)) + { + return new(); + } + + using var context = new GarmentFactoryDatabase(); + + return context.Shops + .Include(x => x.Textiles) + .ThenInclude(x => x.Textile) + .Where(x => x.ShopName.Contains(model.ShopName)) + .ToList() + .Select(x => x.GetViewModel) + .ToList(); + } + + public ShopViewModel? GetElement(ShopSearchModel model) + { + if (string.IsNullOrEmpty(model.ShopName) && !model.Id.HasValue) + { + return new(); + } + + using var context = new GarmentFactoryDatabase(); + + return context.Shops + .Include(x => x.Textiles) + .ThenInclude(x => x.Textile) + .FirstOrDefault(x => (!string.IsNullOrEmpty(model.ShopName) && x.ShopName == model.ShopName) + || (model.Id.HasValue && x.Id == model.Id))?.GetViewModel; + } + + public ShopViewModel? Insert(ShopBindingModel model) + { + using var context = new GarmentFactoryDatabase(); + + var newShop = Shop.Create(context, model); + if (newShop == null) + { + return null; + } + + context.Shops.Add(newShop); + context.SaveChanges(); + + return newShop.GetViewModel; + } + + public ShopViewModel? Update(ShopBindingModel model) + { + using var context = new GarmentFactoryDatabase(); + + using var transaction = context.Database.BeginTransaction(); + try + { + var shop = context.Shops.FirstOrDefault(x => x.Id == model.Id); + + if (shop == null) + return null; + + shop.Update(model); + context.SaveChanges(); + shop.UpdateTextiles(context, model); + + transaction.Commit(); + return shop.GetViewModel; + } + catch + { + transaction.Rollback(); + throw; + } + } + + + public ShopViewModel? Delete(ShopBindingModel model) + { + using var context = new GarmentFactoryDatabase(); + var element = context.Shops + .Include(x => x.Textiles) + .FirstOrDefault(rec => rec.Id == model.Id); + if (element != null) + { + context.Shops.Remove(element); + context.SaveChanges(); + return element.GetViewModel; + } + return null; + } + + //продажа текстиля из магазинов + public bool Sell(SupplySearchModel model) + { + using var context = new GarmentFactoryDatabase(); + using var transaction = context.Database.BeginTransaction(); + + try + { + //поиск всех магаз-ов, в кот. есть нужный текстиль (сортировка: сначала те, где его больше) + var shopsWithThisTextile = context.Shops + .Include(x => x.Textiles) + .ThenInclude(x => x.Textile) + .ToList() + .Where(x => x.ShopTextiles.ContainsKey(model.TextileId.Value)) + .OrderByDescending(x => x.ShopTextiles[model.TextileId.Value].Item2) + .ToList(); + + foreach (var shop in shopsWithThisTextile) + { + //сколько надо будет этого текстиля, если продать все из текущего магазина + int thisTextileNeeded = model.Count.Value - shop.ShopTextiles[model.TextileId.Value].Item2; + + //если ещё надо будет + if (thisTextileNeeded > 0) + { + //полное удаление этого текстиля из этого магазина + shop.ShopTextiles.Remove(model.TextileId.Value); + shop.DictionaryTextilesUpdate(context); + context.SaveChanges(); + + model.Count = thisTextileNeeded; + } + else + { + //если в этом магазине ровно столько, сколько надо + if (thisTextileNeeded == 0) + { + shop.ShopTextiles.Remove(model.TextileId.Value); + } + //если в этом магазине больше, чем надо + else + { + //уменьшение в этом магазине этого текстиля на нужное кол-во + var textileAndCount = shop.ShopTextiles[model.TextileId.Value]; + textileAndCount.Item2 = -thisTextileNeeded; + shop.ShopTextiles[model.TextileId.Value] = textileAndCount; + } + shop.DictionaryTextilesUpdate(context); + transaction.Commit(); + + return true; + } + } + + transaction.Rollback(); + return false; + } + catch + { + transaction.Rollback(); + throw; + } + } + + //пополнение магазинов текстилем + public bool RestockShops(SupplyBindingModel model) + { + using var context = new GarmentFactoryDatabase(); + using var transaction = context.Database.BeginTransaction(); + + //все магазины, где ещё есть свободное место (занятое кол-во < максимально допустимого) + var shops = context.Shops + .Include(x => x.Textiles) + .ThenInclude(x => x.Textile) + .ToList() + .Where(x => x.ShopTextiles.Select(x => x.Value.Item2).Sum() < x.TextileMaxCount) + .ToList(); + + try + { + foreach (Shop shop in shops) + { + //свободное место в этом магазине + int freeSpace = shop.TextileMaxCount - shop.ShopTextiles.Select(x => x.Value.Item2).Sum(); + + //кол-во кот. надо для этого магазина (либо до макс. кол-ва, либо кол-во, кот. осталось в "поставке" (что меньше)) + int restock = Math.Min(freeSpace, model.Count); + model.Count -= restock; + + //если в этом магазине есть этот текстиль, то изменение его кол-ва + if (shop.ShopTextiles.ContainsKey(model.TextileId)) + { + var textileAndCount = shop.ShopTextiles[model.TextileId]; + textileAndCount.Item2 += restock; + shop.ShopTextiles[model.TextileId] = textileAndCount; + } + //если нет, то добавление в этом кол-ве + else + { + var textile = context.Textiles.First(x => x.Id == model.TextileId); + shop.ShopTextiles.Add(model.TextileId, (textile, restock)); + } + + shop.DictionaryTextilesUpdate(context); + + //если в "поставке" закончились товары, то всё ок + if (model.Count == 0) + { + transaction.Commit(); + return true; + } + } + + transaction.Rollback(); + return false; + } + catch + { + transaction.Rollback(); + throw; + } + } + } +} diff --git a/GarmentFactoryDatabaseImplement/Models/Shop.cs b/GarmentFactoryDatabaseImplement/Models/Shop.cs new file mode 100644 index 0000000..501a50f --- /dev/null +++ b/GarmentFactoryDatabaseImplement/Models/Shop.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.ComponentModel.DataAnnotations.Schema; +using System.ComponentModel.DataAnnotations; +using GarmentFactoryDataModels.Models; +using GarmentFactoryContracts.BindingModels; +using GarmentFactoryContracts.ViewModels; + +namespace GarmentFactoryDatabaseImplement.Models +{ + public class Shop : IShopModel + { + public int Id { get; set; } + + [Required] + public string ShopName { get; set; } = string.Empty; + + [Required] + public string Address { get; set; } = string.Empty; + + [Required] + public DateTime DateOpen { get; set; } + + [Required] + public int TextileMaxCount { get; set; } + + [ForeignKey("ShopId")] + public List Textiles { get; set; } = new(); + + private Dictionary? _shopTextiles = null; + + [NotMapped] + public Dictionary ShopTextiles + { + get + { + if (_shopTextiles == null) + { + if (_shopTextiles == null) + { + _shopTextiles = Textiles.ToDictionary(x => x.TextileId, y => (y.Textile as ITextileModel, y.Count)); + } + return _shopTextiles; + } + + return _shopTextiles; + } + } + + public static Shop Create(GarmentFactoryDatabase context, ShopBindingModel model) + { + return new Shop() + { + Id = model.Id, + ShopName = model.ShopName, + Address = model.Address, + DateOpen = model.DateOpen, + TextileMaxCount = model.TextileMaxCount, + Textiles = model.ShopTextiles.Select(x => new ShopTextile + { + Textile = context.Textiles.First(y => y.Id == x.Key), + Count = x.Value.Item2 + }).ToList(), + }; + } + + public void Update(ShopBindingModel model) + { + ShopName = model.ShopName; + Address = model.Address; + DateOpen = model.DateOpen; + TextileMaxCount = model.TextileMaxCount; + } + + public ShopViewModel GetViewModel => new() + { + Id = Id, + ShopName = ShopName, + Address = Address, + DateOpen = DateOpen, + ShopTextiles = ShopTextiles, + TextileMaxCount = TextileMaxCount + }; + + public void UpdateTextiles(GarmentFactoryDatabase context, ShopBindingModel model) + { + var ShopTextiles = context.ShopTextiles + .Where(rec => rec.ShopId == model.Id) + .ToList(); + + if (ShopTextiles != null && ShopTextiles.Count > 0) + { + context.ShopTextiles.RemoveRange(ShopTextiles.Where(rec => !model.ShopTextiles.ContainsKey(rec.TextileId))); + context.SaveChanges(); + + ShopTextiles = context.ShopTextiles.Where(rec => rec.ShopId == model.Id).ToList(); + + foreach (var textileToUpdate in ShopTextiles) + { + textileToUpdate.Count = model.ShopTextiles[textileToUpdate.TextileId].Item2; + model.ShopTextiles.Remove(textileToUpdate.TextileId); + } + + context.SaveChanges(); + } + + var Shop = context.Shops.First(x => x.Id == Id); + + foreach (var ShopTextile in model.ShopTextiles) + { + context.ShopTextiles.Add(new ShopTextile + { + Shop = Shop, + Textile = context.Textiles.First(x => x.Id == ShopTextile.Key), + Count = ShopTextile.Value.Item2 + }); + + context.SaveChanges(); + } + + _shopTextiles = null; + } + + public void DictionaryTextilesUpdate(GarmentFactoryDatabase context) + { + UpdateTextiles(context, new ShopBindingModel + { + Id = Id, + ShopTextiles = ShopTextiles + }); + } + } +} diff --git a/GarmentFactoryDatabaseImplement/Models/ShopTextile.cs b/GarmentFactoryDatabaseImplement/Models/ShopTextile.cs new file mode 100644 index 0000000..c4985b6 --- /dev/null +++ b/GarmentFactoryDatabaseImplement/Models/ShopTextile.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace GarmentFactoryDatabaseImplement.Models +{ + public class ShopTextile + { + public int Id { get; set; } + + [Required] + public int TextileId { get; set; } + + [Required] + public int ShopId { get; set; } + + [Required] + public int Count { get; set; } + + public virtual Shop Shop { get; set; } = new(); + + public virtual Textile Textile { get; set; } = new(); + } +}