< Summary

Class:SVETA.Api.Services.Implements.PriceWorker
Assembly:SVETA.Api
File(s):/opt/dev/sveta_api_build/SVETA.Api/Services/Implements/PriceWorker.cs
Covered lines:0
Uncovered lines:179
Coverable lines:179
Total lines:382
Line coverage:0% (0 of 179)
Covered branches:0
Total branches:52
Branch coverage:0% (0 of 52)

Metrics

MethodLine coverage Branch coverage
.ctor(...)0%100%
ChangePrice()0%100%
ExchangeLoadPrice()0%0%

File(s)

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

#LineLine coverage
 1using AutoMapper;
 2using Microsoft.Extensions.Logging;
 3using SVETA.Api.Data.DTO;
 4using SVETA.Api.Services.Interfaces;
 5using System;
 6using System.Collections.Concurrent;
 7using System.Collections.Generic;
 8using System.IO;
 9using System.Data;
 10using System.Linq;
 11using System.Threading.Tasks;
 12using WinSolutions.Sveta.Server.Data.DataModel.Entities;
 13using WinSolutions.Sveta.Server.Data.DataModel.Kinds;
 14using WinSolutions.Sveta.Server.Services.Interfaces;
 15using SVETA.Api.Data.DTO.Prices.PriceTrend;
 16using Newtonsoft.Json;
 17using System.Globalization;
 18using DocumentFormat.OpenXml.Office2010.ExcelAc;
 19using Microsoft.EntityFrameworkCore;
 20using SVETA.Api.Helpers.Authorize;
 21using WinSolutions.Sveta.Common.Extensions;
 22using WinSolutions.Sveta.Server.Data.DataModel.Extensions;
 23using WinSolutions.Sveta.Server.Data.DataModel.Contexts;
 24using WinSolutions.Sveta.Common;
 25using Clave.Expressionify;
 26
 27namespace SVETA.Api.Services.Implements
 28{
 29    public class PriceWorker : IPriceWorker
 30    {
 31        private readonly IPriceTrendService _priceTrendService;
 32        private readonly IDepartmentService _departmentService;
 33        private readonly ICategoryRatioService _departmentCategoryRatioService;
 34        private readonly IClusterService _clusterService;
 35        private readonly ISupplyContractService _suplContractService;
 36        private readonly IDirectoriesService _dirService;
 37        private readonly IGoodService _goodService;
 38        private readonly IExchangeTokenService _exchangeTokenService;
 39        private readonly IEventService _eventService;
 40        private readonly ILogger<PriceWorker> _logger;
 41        SvetaDbContext _db;
 42        IAuthenticationService _authenticationService;
 43
 44        RecordsState activeRecordState;
 45        Dictionary<string, PriceCurrent> currentPrices;
 46
 047        public PriceWorker(IPriceTrendService priceTrendService,
 048            IDepartmentService departmentService,
 049            ICategoryRatioService departmentCategoryRatioService,
 050            IClusterService clusterService,
 051            ISupplyContractService suplContractService,
 052            IGoodService goodService,
 053            IDirectoriesService dirService,
 054            IExchangeTokenService exchangeTokenService,
 055            IUserService userService,
 056            IEventService eventService,
 057            SvetaDbContext db,
 058            IAuthenticationService authenticationService,
 059            ILogger<PriceWorker> logger)
 060        {
 061            _priceTrendService = priceTrendService;
 062            _dirService = dirService;
 063            _departmentCategoryRatioService = departmentCategoryRatioService;
 064            _clusterService = clusterService;
 065            _suplContractService = suplContractService;
 066            _departmentService = departmentService;
 067            _exchangeTokenService = exchangeTokenService;
 068            _goodService = goodService;
 069            _logger = logger;
 070            _eventService = eventService;
 071            _db = db;
 072            _authenticationService = authenticationService;
 073        }
 74
 75        public async Task<PriceTrend> ChangePrice(PriceTrendRequestDTO priceIn)
 076        {
 77            /* Department dep = await _departmentService.GetDepartment(priceIn.DepartmentId);
 78             if (dep == null)
 79             {
 80                 throw new ArgumentException($"Подразделение #{priceIn.DepartmentId} не существует");
 81             }
 82             Good good = await _goodService.GetGood(priceIn.GoodId);
 83             if (good == null)
 84             {
 85                 throw new ArgumentException($"Товар #{priceIn.GoodId} не существует");
 86             }
 87
 88             return await ChangePriceInternal(null, dep, good, priceIn.PriceNew);*/
 089            return null;
 090        }
 91
 92        public async Task<List<Dictionary<string, string>>> ExchangeLoadPrice(Department department, ExchangePriceTrendR
 093        {
 094            var vendorCodes = new List<string>();
 095            var barCodes = new List<string>();
 096            requestDto.Prices.ForEach(x =>
 097            {
 098                x.VendorCode = x.VendorCode.NormalizeName();
 099                x.BarCode = x.BarCode.NormalizeName();
 0100
 0101                if(!string.IsNullOrEmpty(x.VendorCode))
 0102                {
 0103                    vendorCodes.Add(x.VendorCode.ToLower());
 0104                }
 0105                if (!string.IsNullOrEmpty(x.BarCode))
 0106                {
 0107                    barCodes.Add(x.BarCode.ToLower());
 0108                }
 0109            });
 110
 0111            _authenticationService.SwitchToServiceUser();
 0112            ConcurrentBag<Dictionary<string, string>> errors = new ConcurrentBag<Dictionary<string, string>>();
 0113            if (requestDto.BeginDate.ToUniversalTime() <= DateTime.UtcNow)
 0114            {
 0115                errors.Add(new Dictionary<string, string>()
 0116                {
 0117                    {"", "Дата начала действия цены меньше текущей даты"}
 0118                });
 0119                return errors.ToList();
 120            }
 121
 0122            var priceTrend = new PriceTrend
 0123            {
 0124                BeginDate = requestDto.BeginDate.Date,
 0125                SupplierDepartment = department
 0126            };
 127
 0128            await _priceTrendService.CreatePriceTrend(priceTrend);
 129
 130            try
 0131            {
 0132                Dictionary<string, long> goodsByVendorCode = _db.Goods
 0133                   .Include(x => x.DepartmentGoodSettings)
 0134                   .Expressionify()
 0135                   .Where(d => !d.IsDeleted && vendorCodes.Contains(d.GetActualVendorCode(department.Id).ToLower()))
 0136                   .AsNoTracking()
 0137                   .ToList()
 0138                   .Select(d => new KeyValuePair<string, long>(d.GetActualVendorCode(department.Id).ToString(), d.Id))
 0139                   .ToDictionary(pair => pair.Key.ToLower(), pair => pair.Value);
 140
 0141                Dictionary<string, long> goodsByBarCode = _db.Goods
 0142                  .Include(d => d.GoodBarcodes).ThenInclude(barcode => barcode.BarCode)
 0143                  .Include(d => d.DefaultBarCode)
 0144                  .Expressionify()
 0145                  .Where(d => !d.IsDeleted && barCodes.Contains(d.GetActualBarCode()))
 0146                  .AsNoTracking()
 0147                  .ToList().GroupBy(x => x.GetActualBarCode()).Select(x => x.FirstOrDefault()) //убираем дубли ШК, остав
 0148                  .Select(d => new KeyValuePair<string, long>(d.GetActualBarCode(), d.Id))
 0149                  .ToDictionary(pair => pair.Key.ToLower(), pair => pair.Value);
 150
 0151                ConcurrentBag<PriceTrendDetail> prices = new ConcurrentBag<PriceTrendDetail>();
 152
 0153                Parallel.ForEach(requestDto.Prices, trend =>
 0154                {
 0155                    var innerError = new List<string>();
 0156                    if (string.IsNullOrWhiteSpace(trend.VendorCode) || !goodsByVendorCode.TryGetValue(trend.VendorCode.T
 0157                    {
 0158                        if (string.IsNullOrWhiteSpace(trend.BarCode) || !goodsByBarCode.TryGetValue(trend.BarCode.ToLowe
 0159                        {
 0160                            errors.Add(new Dictionary<string, string>
 0161                            {
 0162                                {"VendorCode", trend.VendorCode}, {"BarCode", trend.BarCode}, {"Error", "Товар не найден
 0163                            });
 0164                            return;
 0165                        }
 0166                    }
 0167
 0168                    if (trend.CurrentPrice <= 0)
 0169                    {
 0170                        innerError.Add("Текущая цена товара не может быть меньше или равна 0");
 0171                    }
 0172                    if (trend.OldPrice < 0)
 0173                    {
 0174                        innerError.Add("Старая цена товара не может быть меньше 0");
 0175                    }
 0176
 0177                    if (innerError.Count > 0)
 0178                    {
 0179                        var dir = new Dictionary<string, string>()
 0180                        {
 0181                            {"VendorCode", trend.VendorCode}, {"BarCode", trend.BarCode}, {"Errors", string.Join(";", in
 0182                        };
 0183                        errors.Add(dir);
 0184                        return;
 0185                    }
 0186
 0187                    if (prices.Any(x => x.GoodId == good))
 0188                    {
 0189                        var dir = new Dictionary<string, string>()
 0190                        {
 0191                            {"VendorCode", trend.VendorCode}, {"BarCode", trend.BarCode}, {"Errors",  $"Товар с Id={good
 0192                        };
 0193                        errors.Add(dir);
 0194                        return;
 0195                    }
 0196                    var priceTrendDetail = new PriceTrendDetail
 0197                    {
 0198                        GoodId = good,
 0199                        PriceNew = trend.CurrentPrice,
 0200                        PriceOld = trend.OldPrice,
 0201                        PriceTrend = priceTrend
 0202                    };
 0203                    priceTrendDetail.Discount = priceTrendDetail.Discount();
 0204                    prices.Add(priceTrendDetail);
 0205
 0206                });
 0207                if (prices.Count > 0)
 0208                {
 0209                    _db.PriceTrendDetails.AddRange(prices);
 0210                    await _db.SaveChangesAsync(_authenticationService.UserId);
 0211                }
 0212                return errors.ToList();
 213            }
 0214            catch (Exception e)
 0215            {
 0216                _logger.LogError("Ошибка загрузки цен из 1С");
 0217                _logger.LogError(e.Message);
 0218                throw;
 219            }
 0220        }
 221
 222        public async Task<List<PriceTrendFromFileResultDTO>> Load(long priceTrendId, List<PriceTrendFromFileDTO> data)
 223        {
 224            var priceTrend = await _priceTrendService.GetPriceTrend(priceTrendId, null);
 225            if(priceTrend == null)
 226            {
 227                throw new ArgumentException($"PriceTrend {priceTrendId} not found");
 228            }
 229
 230            var goodUniqueCodes = new List<string>();
 231            var goodVendorCodes = new List<string>();
 232            var goodBarCodes = new List<string>();
 233            var goodNames = new List<string>();
 234
 235            data.ForEach(x =>
 0236            {
 0237                x.UniqueCode = x.UniqueCode.NormalizeName();
 0238                x.VendorCode = x.VendorCode.NormalizeName();
 0239                x.BarCode = x.BarCode.NormalizeName();
 0240                x.GoodName = x.GoodName.NormalizeName();
 241
 0242                if (!string.IsNullOrEmpty(x.UniqueCode))
 0243                {
 0244                    goodUniqueCodes.Add(x.UniqueCode.ToLower());
 0245                }
 0246                else if (!string.IsNullOrEmpty(x.VendorCode))
 0247                {
 0248                    goodVendorCodes.Add(x.VendorCode.ToLower());
 0249                }
 0250                else if (!string.IsNullOrEmpty(x.BarCode))
 0251                {
 0252                    goodBarCodes.Add(x.BarCode.ToLower());
 0253                }
 0254                else if (!string.IsNullOrEmpty(x.GoodName))
 0255                {
 0256                    goodNames.Add(x.GoodName.ToLower());
 0257                }
 258
 0259                x.Price = x.Price.NormalizeName();
 0260                x.OldPrice = x.OldPrice.NormalizeName();
 0261            });
 262            activeRecordState = await _dirService.GetRecordState((long)RecordState.Active);
 263
 264            var goodsByUniqueCodes = _goodService.FindGoodsByUniqueCodes(goodUniqueCodes).Result
 0265                .ToDictionary(x => x.UniqueCode.ToLower(), x => new List<Good> { x });
 266            var goodsByVendorCodes = _goodService.FindGoodsByVendorsCodes(goodVendorCodes, priceTrend.SupplierDepartment
 0267                .GroupBy(x => x.GetActualVendorCode(priceTrend.SupplierDepartmentId))
 0268                .ToDictionary(x => x.Key.ToLower(), x => x.ToList());
 269            var goodsByBarCodes = _goodService.FindGoodsByBarCodes(goodBarCodes).Result
 0270                .GroupBy(x => x.GetActualBarCode())
 0271                .ToDictionary(x => x.Key.ToLower(), x => x.ToList());
 272            var goodsByNames = _goodService.FindGoodsByNames(goodNames).Result
 0273                .GroupBy(x => x.Name)
 0274                .ToDictionary(x => x.Key.ToLower(), x => x.ToList());
 275
 276            var priceTrendsDic = new Dictionary<long, PriceTrend>();
 277            var goodsAdded = new List<long>();
 278
 279            var result = new List<PriceTrendFromFileResultDTO>();
 280            foreach (var row in data)
 281            {
 282                if (string.IsNullOrEmpty(row.UniqueCode)
 283                    && string.IsNullOrEmpty(row.VendorCode)
 284                    && string.IsNullOrEmpty(row.BarCode)
 285                    && string.IsNullOrEmpty(row.GoodName))
 286                {
 287                    result.Add(new PriceTrendFromFileResultDTO(row, "Не задан товар"));
 288                    continue;
 289                }
 290
 291                decimal priceDec;
 292                try
 293                {
 294                    priceDec = row.Price.ToDecimal();
 295                    if(priceDec <= 0)
 296                    {
 297                        result.Add(new PriceTrendFromFileResultDTO(row, "Цена должна быть больше нуля"));
 298                        continue;
 299                    }
 300                }
 301                catch
 302                {
 303                    result.Add(new PriceTrendFromFileResultDTO(row, "Некорректный формат цены"));
 304                    continue;
 305                }
 306
 307                decimal? priceOld = null;
 308                try
 309                {
 310                    if (!string.IsNullOrEmpty(row.OldPrice))
 311                    {
 312                        priceOld = row.OldPrice.ToDecimal();
 313                        if (priceOld <= 0)
 314                        {
 315                            result.Add(new PriceTrendFromFileResultDTO(row, "Старая цена должна быть больше нуля"));
 316                            continue;
 317                        }
 318                    }
 319                }
 320                catch
 321                {
 322                    result.Add(new PriceTrendFromFileResultDTO(row, "Некорректный формат старой цены"));
 323                    continue;
 324                }
 325
 326                List<Good> good = null;
 327                if (!String.IsNullOrEmpty(row.UniqueCode))
 328                {
 329                    goodsByUniqueCodes.TryGetValue(row.UniqueCode.ToLower(), out good);
 330                }
 331                else if (!String.IsNullOrEmpty(row.VendorCode))
 332                {
 333                    goodsByVendorCodes.TryGetValue(row.VendorCode.ToLower(), out good);
 334                }
 335                else if (!String.IsNullOrEmpty(row.BarCode))
 336                {
 337                    goodsByBarCodes.TryGetValue(row.BarCode.ToLower(), out good);
 338                }
 339                else if (!String.IsNullOrEmpty(row.GoodName))
 340                {
 341                    goodsByNames.TryGetValue(row.GoodName.ToLower(), out good);
 342                }
 343                else
 344                {
 345                    result.Add(new PriceTrendFromFileResultDTO(row, "Не заданы UniqueCode, VendorCode, BarCode, GoodName
 346                    continue;
 347                }
 348
 349                if (good == null || good.Count == 0)
 350                {
 351                    result.Add(new PriceTrendFromFileResultDTO(row, "Товар не найден"));
 352                    continue;
 353                }
 354                if (good.Count > 1)
 355                {
 356                    result.Add(new PriceTrendFromFileResultDTO(row, "Найден более чем один товар"));
 357                    continue;
 358                }
 0359                if (goodsAdded.Any(x => x == good.Single().Id))
 360                {
 361                    result.Add(new PriceTrendFromFileResultDTO(row, "Переоценка для данного товара уже добавлена"));
 362                    continue;
 363                }
 364
 365                // добавляем туда собственно переоценку
 366                var trendDetail = new PriceTrendDetail()
 367                {
 368                    PriceNew = priceDec,
 369                    PriceOld = priceOld,
 370                    PriceTrend = priceTrend,
 371                    GoodId = good.Single().Id
 372                };
 373                trendDetail.Discount = trendDetail.Discount();
 374                _db.PriceTrendDetails.Add(trendDetail);
 375                goodsAdded.Add(good.Single().Id);
 376            }
 377            await _db.SaveChangesAsync(_authenticationService.UserId);
 378
 379            return result;
 380        }
 381    }
 382}