< Summary

Class:SVETA.Api.Services.Implements.GoodWorker
Assembly:SVETA.Api
File(s):/opt/dev/sveta_api_build/SVETA.Api/Services/Implements/GoodWorker.cs
Covered lines:35
Uncovered lines:106
Coverable lines:141
Total lines:357
Line coverage:24.8% (35 of 141)
Covered branches:3
Total branches:56
Branch coverage:5.3% (3 of 56)

Metrics

MethodLine coverage Branch coverage
.ctor(...)100%100%
ExchangeRests()0%0%
CreateGood()0%100%
PrepareGood()0%0%

File(s)

/opt/dev/sveta_api_build/SVETA.Api/Services/Implements/GoodWorker.cs

#LineLine coverage
 1using System;
 2using System.Collections.Concurrent;
 3using System.Collections.Generic;
 4using System.IO;
 5using System.Linq;
 6using System.Threading.Tasks;
 7using AutoMapper;
 8using AutoMapper.Mappers;
 9using Clave.Expressionify;
 10using Microsoft.EntityFrameworkCore;
 11using Microsoft.Extensions.Logging;
 12using Microsoft.Extensions.Options;
 13using SVETA.Api.Data.Domain;
 14using SVETA.Api.Data.DTO.Goods;
 15using SVETA.Api.Data.DTO.Rest;
 16using SVETA.Api.Services.Interfaces;
 17using WinSolutions.Sveta.Common.Extensions;
 18using WinSolutions.Sveta.Server.Data.DataModel.Contexts;
 19using WinSolutions.Sveta.Server.Data.DataModel.Entities;
 20using WinSolutions.Sveta.Server.Data.DataModel.Extensions;
 21using WinSolutions.Sveta.Server.Data.DataModel.Kinds;
 22using WinSolutions.Sveta.Server.Services.Interfaces;
 23
 24namespace SVETA.Api.Services.Implements
 25{
 26    public class GoodWorker: IGoodWorker
 27    {
 28        private readonly ILogger<GoodWorker> _logger;
 29        private readonly IGoodService _goodService;
 30        readonly IContragentService _contragentService;
 31        readonly ICategoryService _categoryService;
 32        readonly IBrandService _brandService;
 33        readonly IDirectoriesService _dirService;
 34        readonly ICountryService _countryService;
 35        private readonly IDepartmentService _departmentService;
 36        readonly ImagesSettings _imagesSettings;
 37        readonly IBarcodeService _barcodeService;
 38        private readonly SvetaDbContext _db;
 39        private readonly IRestService _restService;
 40
 141        public GoodWorker(IGoodService goodService,
 142            ICategoryService categoryService,
 143            IContragentService contragentService,
 144            IBrandService brandService,
 145            IDirectoriesService dirService,
 146            ICountryService countryService,
 147            IDepartmentService departmentService,
 148            IBarcodeService barcodeService,
 149            IOptions<ImagesSettings> imagesSettings,
 150            IRestService restService,
 151            SvetaDbContext db,
 152            ILogger<GoodWorker> logger)
 53
 154        {
 155            _db = db;
 156            _goodService = goodService;
 157            _logger = logger;
 158            _dirService = dirService;
 159            _contragentService = contragentService;
 160            _categoryService = categoryService;
 161            _brandService = brandService;
 162            _countryService = countryService;
 163            _barcodeService = barcodeService;
 164            _imagesSettings = imagesSettings.Value;
 165            _departmentService = departmentService;
 166            _restService = restService;
 167        }
 68
 69        public async Task<List<Dictionary<string, string>>> CreateGoods(List<GoodExchangeDto> goods, ExchangeToken token
 70        {
 71            List<Dictionary<string, string>> err = new List<Dictionary<string, string>>();
 72            List<Good> createdGoods = new List<Good>();
 73            IEnumerable<GoodInputDTO> inputGoods = new List<GoodInputDTO>();
 74
 75            Dictionary<string, Good> allGoodsByUniqCode = _db.Goods
 76                    .Where(d => !d.IsDeleted)
 77                    .Select(d => new KeyValuePair<string, Good>(d.GetActualVendorCode(token.DepartmentId).ToString(), d)
 578                    .ToDictionary(pair => pair.Key.ToLower(), pair => pair.Value);
 79
 80            Dictionary<string, Good> allGoodsByName = _db.Goods
 81                    .Where(d => !d.IsDeleted)
 82                    .Select(d => new KeyValuePair<string, Good>(d.Name, d))
 583                    .ToDictionary(pair => pair.Key.ToLower(), pair => pair.Value);
 84
 85            Dictionary<string, Brand> brands = _db.Brands
 86                .Where(d => !d.IsDeleted)
 87                .Select(d => new KeyValuePair<string, Brand>(d.Name, d))
 388                .ToDictionary(pair => pair.Key.ToLower(), pair => pair.Value);
 89            var catDic = _db.Categories.Where(x => !x.IsDeleted).ToList();
 90
 91            var unitDic = new Dictionary<string, UnitsKind>
 92            (
 93                _db.refUnitsKind.Select(x => new KeyValuePair<string, UnitsKind>(x.Name.ToLower(), x))
 94            );
 95            var vats = _db.refVatsKind.ToList();
 96            var countryDic = new Dictionary<string, Country>
 97            (
 98                _db.refCountries.Select(x => new KeyValuePair<string, Country>(x.Name.ToLower(), x))
 99            );
 100
 101            var mapper = new MapperConfiguration(cfg =>
 2102            {
 2103                cfg.CreateMap<GoodExchangeDto, Good>()
 3104                    .ForMember(d => d.Name, e => e.MapFrom(s => s.Name.NormalizeName()));
 2105            }).CreateMapper();
 106
 107            RecordsState inactiveState = await _dirService.GetRecordState((long) RecordState.Inactive);
 108            foreach (var good in goods)
 109            {
 110                List<string> innerError = new List<string>();
 111                try
 112                {
 113                    if (string.IsNullOrWhiteSpace(good.Name))
 114                        innerError.Add("Название товара обязательно для заполнения");
 115                    if (good.Name.Length > 255)
 116                        innerError.Add("Название товара не может быть длиннее 255 символов ");
 117                    if (!string.IsNullOrWhiteSpace(good.Name) && allGoodsByName.TryGetValue(good.Name.NormalizeName().To
 118                        innerError.Add($"Товар с названием '{good.Name}' уже существует");
 119                    outGood = default;
 120                    if (string.IsNullOrWhiteSpace(good.VendorCode))
 121                        innerError.Add("Уникальный код  обязателен для заполнения");
 122                    if ( allGoodsByUniqCode.TryGetValue(good.VendorCode.NormalizeName().ToLower(), out outGood))
 123                        innerError.Add($"Товар с названием '{good.VendorCode}' уже существует");
 20124                    var category = string.IsNullOrWhiteSpace(good.CategoryName) ? null : catDic.FirstOrDefault(d => d.Na
 125                    if (category == null)
 126                        innerError.Add($"Категория с именем {good.CategoryName} не найдена");
 127
 128                    Brand brand = default;
 129                    if (string.IsNullOrWhiteSpace(good.BrandName) || !brands.TryGetValue(good.BrandName.NormalizeName().
 130                    {
 131                        innerError.Add($"Бренд с именем {good.BrandName} не найден");
 132                    }
 133
 134                    Brand subBrand = default;
 135                    if (!string.IsNullOrWhiteSpace(good.SubBrandName))
 136                        brands.TryGetValue(good.SubBrandName.NormalizeName().ToLower(), out subBrand);
 137                    if (subBrand != null && brand.Id == subBrand.Id)
 138                    {
 139                        innerError.Add($"Бренд с именем {good.BrandName} и суббренд {good.SubBrandName} совпадают");
 140                    }
 141
 142                    Country country = default;
 143                    if (string.IsNullOrWhiteSpace(good.CountryName) || !countryDic.TryGetValue(good.CountryName.Normaliz
 144                    {
 145                        innerError.Add($"Страна с именем {good.CountryName} не найдена");
 146                    }
 147
 148                    UnitsKind unitKind = default;
 149                    if (string.IsNullOrWhiteSpace(good.UnitName) || !unitDic.TryGetValue(good.UnitName.NormalizeName().T
 150                    {
 151                        innerError.Add($"Еденица измерения с именем {good.UnitName} не найдена");
 152                    }
 153
 154                    var vatId = good.VatName switch
 155                    {
 156                        0 => (int) VatKind.Zero,
 157                        10 => (int) VatKind.Ten,
 158                        20 => (int) VatKind.Twenty,
 159                        _ => (int) VatKind.Twenty
 160                    };
 40161                    var vat = vats.FirstOrDefault(d => d.Code.Equals(vatId.ToString(), StringComparison.OrdinalIgnoreCas
 162                    if (vat == null)
 163                        innerError.Add($"Налоговая ставка {good.VatName} не найдена");
 164
 165                    if (innerError.Count > 0)
 166                    {
 167                        Dictionary<string, string> errors = new Dictionary<string, string>
 168                        {
 169                            {"VendorCode", good.VendorCode}, {"Error", string.Join(";", innerError)}
 170                        };
 171                        err.Add(errors);
 172                        continue;
 173                    }
 174
 175                    Good inputGood = mapper.Map<Good>(good);
 176                    inputGood.Category = category;
 177                    inputGood.Country = country;
 178                    inputGood.Brand = brand;
 179                    inputGood.SubBrand = subBrand;
 180                    inputGood.RecState = inactiveState;
 181                    inputGood.UnitsKind = unitKind;
 182                    inputGood.VatsKind = vat;
 183                    inputGood.GoodBarcodes = new List<GoodBarcode>() { new GoodBarcode { BarCode = new BarCode {Code = g
 184                    inputGood.DepartmentGoodSettings = new List<DepartmentGoodSetting>
 185                    {
 186                        new DepartmentGoodSetting
 187                        {
 188                            Department = token.Department,
 189                            MinQuantity = good.MinQuantity,
 190                            PickingQuantum = good.PickingQuantum,
 191                            ShowcaseVisible = good.ShowcaseVisible,
 192                            VendorCode = good.VendorCode
 193                        }
 194                    };
 195                    createdGoods.Add(inputGood);
 196                    allGoodsByUniqCode.Add(good.VendorCode.NormalizeName().ToLower(), inputGood);
 197                    allGoodsByName.Add(inputGood.Name.NormalizeName().ToLower(), inputGood);
 198                }
 199                catch (Exception e)
 200                {
 201                    _logger.LogError("Ошибка создания товара");
 202                    _logger.LogError($"{e.Message} {e.StackTrace}");
 203                    throw;
 204                }
 205            }
 206
 207            try
 208            {
 209                await _goodService.CreateGoodRange(createdGoods);
 210            }
 211            catch (Exception e)
 212            {
 213                Console.WriteLine(e);
 214                throw;
 215            }
 216
 217            return err;
 218        }
 219
 220        public async Task<List<Dictionary<string, string>>> ExchangeRests(Department department,
 221            List<ExchangeRestRequestDto> rests)
 0222        {
 0223            ConcurrentBag<Dictionary<string, string>> errors = new ConcurrentBag<Dictionary<string, string>>();
 0224            object lockable = new object();
 0225            ConcurrentBag<Rest> createdRest = new ConcurrentBag<Rest>();
 226            try
 0227            {
 228
 0229                Dictionary<string, long> goodsByVendorCode = _db.Goods
 0230                    .Include(x=>x.DepartmentGoodSettings)
 0231                    .Where(d => !d.IsDeleted)
 0232                    .Select(d => new KeyValuePair<string, long>(d.GetActualVendorCode(department.Id).ToString(), d.Id))
 0233                    .ToDictionary(pair => pair.Key.ToLower(), pair => pair.Value);
 234
 0235                Dictionary<string, long> goodsByBarCode = _db.Goods
 0236                   .Include(d => d.GoodBarcodes)
 0237                   .ThenInclude(barcode => barcode.BarCode)
 0238                   .Include(d => d.DefaultBarCode)
 0239                   .Where(d => !d.IsDeleted).ToList().GroupBy(x => x.GetActualBarCode()).Select(x => x.FirstOrDefault())
 0240                   .Select(d => new KeyValuePair<string, long>(d.GetActualBarCode(), d.Id))
 0241                   .ToDictionary(pair => pair.Key.ToLower(), pair => pair.Value);
 242
 0243                Parallel.ForEach(rests, rest =>
 0244                {
 0245                    if (string.IsNullOrWhiteSpace(rest.VendorCode) || !goodsByVendorCode.TryGetValue(rest.VendorCode.Nor
 0246                    {
 0247                        if (string.IsNullOrWhiteSpace(rest.BarCode) || !goodsByBarCode.TryGetValue(rest.BarCode.Normaliz
 0248                        {
 0249                            errors.Add(new Dictionary<string, string>
 0250                            {
 0251                                {"VendorCode", rest.VendorCode}, {"BarCode", rest.BarCode}, {"Error", "Товар не найден"}
 0252                            });
 0253                            return;
 0254                        }
 0255                    }
 0256
 0257                    var inputRest = new Rest
 0258                    {
 0259                        Department = department,
 0260                        GoodId = good,
 0261                        Quantity = rest.Rest
 0262                    };
 0263                    createdRest.Add(inputRest);
 0264                });
 0265                if (createdRest.Count > 0)
 0266                {
 0267                    await _restService.Create(createdRest.ToList());
 0268                }
 0269                return errors.ToList();
 270            }
 0271            catch (Exception e)
 0272            {
 0273                _logger.LogError("Ошибка загрузки остатков из 1С");
 0274                _logger.LogError(e.Message);
 0275                throw;
 276            }
 0277        }
 278
 279
 280        public async Task<Good> CreateGood(GoodInputDTO dto)
 0281        {
 0282            Good good = await PrepareGood(dto, new Good());
 0283            await _goodService.CreateGood(good);
 0284            return await Task.FromResult(good);
 0285        }
 286        public async Task<Good> PrepareGood(GoodInputDTO dto, Good good)
 0287        {
 0288            dto.Name = dto.Name.NormalizeName().Required(nameof(dto.Name));
 0289            dto.Barcode = dto.Barcode.NormalizeName().Required(nameof(dto.Barcode));
 290
 0291            if (_goodService.GetGoodsByName(dto.Name).Any(d => d.Id != good.Id))
 0292            {
 0293                throw new ArgumentException($"Товар с имененем '{dto.Name}' уже существует");
 294            }
 295
 0296            good.Country = await _countryService.GetCountry(dto.CountryId);
 0297            if (good.Country == null)
 0298            {
 0299                throw new ArgumentException($"Страна #{dto.CountryId} не найдена");
 300            }
 301
 0302            if (_goodService.GetGoodsByBarcode(dto.Barcode).Any(x => x.Id != good.Id))
 0303            {
 0304                throw new ArgumentException($"Good with barcode '{dto.Barcode}' already exists in db");
 305            }
 0306            good.DefaultBarCode = await _barcodeService.GetBarcode(dto.Barcode) ?? await _barcodeService.CreateBarcode(d
 307
 0308            if (!string.IsNullOrWhiteSpace(dto.AdditionalBarcode))
 0309            {
 0310                if (_goodService.GetGoodsByBarcode(dto.AdditionalBarcode).Any(x => x.Id != good.Id))
 0311                {
 0312                    throw new ArgumentException($"Good with barcode '{dto.AdditionalBarcode}' already exists in db");
 313                }
 0314                var addBarcode = await _barcodeService.GetBarcode(dto.AdditionalBarcode) ??
 0315                                 await _barcodeService.CreateBarcode(dto.AdditionalBarcode);
 316
 0317                good.Barcodes ??= new List<BarCode>();
 0318                good.Barcodes.Clear();
 0319                good.Barcodes.Add(addBarcode);
 0320            }
 321
 0322            good.Category = await _categoryService.FindCategory(dto.CategoryId);
 0323            if (good.Category == null)
 0324            {
 0325                throw new ArgumentException($"Category #{dto.CategoryId} not found");
 326            }
 327
 0328            if (dto.BrandId == dto.SubBrandId)
 0329            {
 0330                throw new ArgumentException($"Brand #{dto.BrandId} equals SubBrand #{dto.SubBrandId}");
 331            }
 332
 0333            good.Brand = dto.BrandId != 0 ? await _brandService.GetBrand(dto.BrandId) : null;
 334
 0335            good.SubBrand = dto.SubBrandId.HasValue ? await _brandService.GetBrand(dto.SubBrandId.Value) : null;
 336
 0337            good.UnitsKind = await _dirService.GetUnitKindByCode(dto.UnitKindId);
 0338            good.RecState = dto.IsActive ? await _dirService.GetRecordState((long)RecordState.Active) : await _dirServic
 0339            good.ConformityCertNumber = dto.ConformityCertNumber;
 0340            good.CustomDeclarationNumber = dto.CustomDeclarationNumber;
 341            //good.VendorCode = dto.VendorCode;
 0342            good.VatsKind = await _dirService.GetVatKindByCode(dto.Vat);
 0343            good.Weight = dto.Weight;
 0344            good.Width = dto.Width;
 0345            good.Height = dto.Height;
 0346            good.Thickness = dto.Thickness;
 0347            good.GroupPackNesting = dto.GroupPackNesting;
 0348            good.GroupPackWidth = dto.GroupPackWidth;
 0349            good.GroupPackHeight = dto.GroupPackHeight;
 0350            good.GroupPackThickness = dto.GroupPackThickness;
 0351            good.MinDeliveryLot = dto.MinDeliveryLot;
 0352            good.Name = dto.Name;
 353
 0354            return good;
 0355        }
 356    }
 357}