< Summary

Class:WinSolutions.Sveta.Server.Services.Implements.GoodService
Assembly:WinSolutions.Sveta.Server
File(s):/opt/dev/sveta_api_build/WinSolutions.Sveta.Server/Services/Implements/GoodService.cs
Covered lines:96
Uncovered lines:308
Coverable lines:404
Total lines:535
Line coverage:23.7% (96 of 404)
Covered branches:27
Total branches:172
Branch coverage:15.6% (27 of 172)

Metrics

MethodLine coverage Branch coverage
.ctor(...)100%100%
GetGoods()0%0%
GetGoodsCount()0%100%
PrepareGetNotDeletedGoodsQuery(...)0%0%
ExpandCategoryTree(...)0%0%
GetGood()100%100%
GetGood()100%100%
GetGoods()0%100%
GetGoodsByCategory()0%100%
GetGoodsBySuplier()0%100%
GetActiveGoods()0%100%
GetActiveGoods()0%0%
GetGoodsByName(...)0%100%
SearchGoods()0%100%
GetGoodsByBarcode(...)0%100%
FindGoodsByBarCodes(...)0%100%
PrepeareGoods()100%100%
PrepareNotDeletedGoods()0%100%
CreateGood()66.66%50%
CreateGoodRange()79.54%61.11%
UpdateGood()0%0%
SetPhoto()0%100%
DeleteGood()0%0%
GoodExists()0%100%
ChangeGoodState()0%0%
GetShowcaseGoodsBaseQuery(...)0%0%
GetFilteredShowcaseGoodsQuery(...)0%0%
GetPagedShowcaseGoodsQuery(...)0%0%
GetShowcaseGood()0%100%
FindGoodsByNames()0%100%
FindGoodsByUniqueCodes()0%100%
FindGoodsByVendorsCodes()0%100%
FindGoodsByIds()0%100%
GetGoods()100%100%

File(s)

/opt/dev/sveta_api_build/WinSolutions.Sveta.Server/Services/Implements/GoodService.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using WinSolutions.Sveta.Server.Domain;
 3using WinSolutions.Sveta.Common;
 4using Microsoft.Extensions.Logging;
 5using System;
 6using System.Collections.Generic;
 7using System.Linq;
 8using System.Text;
 9using System.Threading.Tasks;
 10using WinSolutions.Sveta.Server.Data.DataModel.Contexts;
 11using WinSolutions.Sveta.Server.Data.DataModel.Entities;
 12using WinSolutions.Sveta.Server.Data.DataModel.Kinds;
 13using WinSolutions.Sveta.Server.Services.Interfaces;
 14using Clave.Expressionify;
 15using Microsoft.EntityFrameworkCore.Internal;
 16using WinSolutions.Sveta.Server.Data.DataModel.Extensions;
 17using WinSolutions.Sveta.Common.Extensions;
 18
 19namespace WinSolutions.Sveta.Server.Services.Implements
 20{
 21    public class GoodService : SvetaServiceBase, IGoodService
 22    {
 23        private readonly ILogger<GoodService> _logger;
 24        private readonly SvetaDbContext _db;
 25        public GoodService(SvetaDbContext db, ILogger<GoodService> logger, IAuthenticationService authenticationService)
 18426            : base(authenticationService)
 18427        {
 18428            _db = db;
 18429            _logger = logger;
 18430        }
 31
 32        /// <summary>
 33        /// Возвращает товары по фильтру и категории
 34        /// </summary>
 35        /// <param name="page">пейджинг: номер страницы</param>
 36        /// <param name="limit">пейджинг: размер страницы</param>
 37        /// <param name="filter">фильтр по значимым полям</param>
 38        /// <param name="sort">сортировка</param>
 39        /// <param name="categoryId">код категории, null если возвращать все товары из всех категорий</param>
 40        /// <param name="activeOnly">возвращать только активные товары, иначе активные + неактивные</param>
 41        /// <returns></returns>
 42        public async Task<List<Good>> GetGoods(int page, int limit, string filter, string sort, long? categoryId, bool a
 043        {
 044            var qry = PrepareGetNotDeletedGoodsQuery(filter, categoryId, activeOnly);
 045            switch((sort ?? "").ToLower())
 46            {
 047                case "name": qry = qry.OrderBy(x => x.Name); break;
 048                case "name|desc": qry = qry.OrderByDescending(x => x.Name); break;
 049                case "brandname": qry = qry.OrderBy(x => x.Brand.Name); break;
 050                case "brandname|desc": qry = qry.OrderByDescending(x => x.Brand.Name); break;
 051                case "id|desc": qry = qry.OrderByDescending(x => x.Id); break;
 052                default: qry = qry.OrderBy(x => x.Id); break;
 53            }
 054            qry = qry.Skip(page * limit).Take(limit);
 055            return await qry.ToListAsync();
 056        }
 57
 58        /// <summary>
 59        /// Возвращает количество товаров по фильтру и категории
 60        /// </summary>
 61        /// <param name="filter">фильтр по значимым полям</param>
 62        /// <param name="categoryId">код категории, null если возвращать все товары из всех категорий</param>
 63        /// <param name="activeOnly">возвращать только активные товары, иначе активные + неактивные</param>
 64        /// <returns></returns>
 65        public async Task<int> GetGoodsCount(string filter, long? categoryId, bool activeOnly)
 066        {
 067            var qry = PrepareGetNotDeletedGoodsQuery(filter, categoryId, activeOnly);
 068            return await qry.CountAsync();
 069        }
 70
 71        IQueryable<Good> PrepareGetNotDeletedGoodsQuery(string filter, long? categoryId, bool activeOnly)
 072        {
 073            var qry = PrepareNotDeletedGoods();
 74
 075            if (activeOnly)
 076            {
 077                qry = qry.Where(x => x.RecState.Id == (long)RecordState.Active);
 078            }
 79
 080            if (categoryId.HasValue)
 081            {
 082                var categories = ExpandCategoryTree(new List<long>() { categoryId.Value });
 083                categories.Add(categoryId.Value);
 084                qry = qry.Where(x => categories.Contains(x.Category.Id));
 085            }
 86
 087            if (!string.IsNullOrWhiteSpace(filter))
 088            {
 089                qry = qry.Where(x => x.Name.ToUpper().Contains(filter.ToUpper())
 090                    || x.DefaultBarCode.Code.ToUpper().Contains(filter.ToUpper())
 091                    || x.GoodBarcodes.Any(g => g.BarCode.Code.ToUpper().Contains(filter.ToUpper()))
 092                    || (x.Manufacturer != null && x.Manufacturer.ShortName != null && x.Manufacturer.ShortName.ToUpper()
 093                    || (x.Manufacturer != null && x.Manufacturer.FullName != null && x.Manufacturer.FullName.ToUpper().C
 094            }
 95
 096            return qry;
 097        }
 98
 99        public List<long> ExpandCategoryTree(List<long> categories)
 0100        {
 0101            var children = _db.Categories
 0102                .Include(x => x.Parent)
 0103                .Include(d => d.RecState)
 0104                .Where(x => !x.IsDeleted && x.Parent != null && categories.Contains(x.Parent.Id))
 0105                .Select(x => x.Id)
 0106                .ToList();
 0107            if (children.Count > 0)
 0108            {
 0109                children.AddRange(ExpandCategoryTree(children));
 0110            }
 111
 0112            return children;
 0113        }
 114
 115        //JOIN
 66116        public async Task<Good> GetGood(long id) => await PrepeareGoods().FirstOrDefaultAsync(d => d.Id == id);
 1117        public async Task<Good> GetGood(string mainBarcode) => await PrepeareGoods()
 1118            .FirstOrDefaultAsync(d => d.GoodBarcodes.Count(g => g.IsPrimary) > 0
 1119                ? d.GoodBarcodes.FirstOrDefault(g => g.IsPrimary).BarCode.Code.ToLower().Equals(mainBarcode.NormalizeNam
 1120                : d.DefaultBarCode.Code.ToLower().Equals(mainBarcode.NormalizeName().ToLower()));
 121        //JOIN
 0122        public async Task<List<Good>> GetGoods(int page, int limit) => await PrepareNotDeletedGoods()
 0123            .Skip(page * limit)
 0124            .Take(limit)
 0125            .ToListAsync();
 126
 0127        public async Task<List<Good>> GetGoodsByCategory(int page, int limit, long categoryId) => await PrepareNotDelete
 0128            .Where(d => d.Category != null && d.Category.Id == categoryId)
 0129            .Skip(page * limit)
 0130            .Take(limit)
 0131            .ToListAsync();
 0132        public async Task<List<Good>> GetGoodsBySuplier(int page, int limit, long suplierId) => await PrepareNotDeletedG
 0133            .Where(d => d.Supplier != null && d.Supplier.Id == suplierId)
 0134            .Skip(page * limit)
 0135            .Take(limit)
 0136            .ToListAsync();
 137
 0138        public async Task<List<Good>> GetActiveGoods(int page, int limit) => await PrepareNotDeletedGoods()
 0139            .Where(d => d.RecState.Id == (long)RecordState.Active)
 0140            .Skip(page * limit)
 0141            .Take(limit)
 0142            .ToListAsync();
 143
 144        public async Task<PaginatedData<List<Good>>> GetActiveGoods(int page, int limit, long departmentId, long categor
 0145        {
 0146            var goods = PrepareNotDeletedGoods();
 0147            int total = await goods?.CountAsync();
 0148            goods = goods.Where(d => d.RecState.Id == (long)RecordState.Active)
 0149           .Where(d => categoryId == 0 || d.Category.Id == categoryId)
 0150           .Where(d => string.IsNullOrWhiteSpace(filter) || d.GetActualVendorCode(departmentId).ToLower().Contains(filte
 0151            switch ((sort ?? "").ToLower())
 152            {
 0153                case "name": goods = goods.OrderBy(x => x.Name); break;
 0154                case "name|desc": goods = goods.OrderByDescending(x => x.Name); break;
 0155                case "code": goods = goods.OrderBy(x => x.GetActualVendorCode(departmentId)); break;
 0156                case "code|desc": goods = goods.OrderByDescending(x => x.GetActualVendorCode(departmentId)); break;
 0157                default: goods = goods.OrderBy(x => x.Name); break;
 158            }
 0159            int filtered = await goods?.CountAsync();
 0160            return new PaginatedData<List<Good>>
 0161            {
 0162                Result = await goods.Skip(page * limit).Take(limit).ToListAsync(),
 0163                TotalCount = total,
 0164                TotalFilteredCount = filtered
 0165            };
 0166        }
 167
 0168        public IQueryable<Good> GetGoodsByName(string name) => PrepareNotDeletedGoods()
 0169            .AsNoTracking()
 0170            .Where(d => d.Name.ToUpper().Equals(name.NormalizeName().ToUpper()));
 171
 0172        public async Task<List<Good>> SearchGoods(string name, int limit) => await _db.Goods
 0173            .AsNoTracking()
 0174            .Where(d => d.Name.ToUpper().StartsWith(name.NormalizeName().ToUpper()))
 0175            .Where(e => !e.IsDeleted)
 0176            .Take(limit)
 0177            .ToListAsync();
 178
 179        //JOIN
 0180        public IQueryable<Good> GetGoodsByBarcode(string barcode) => _db.Goods
 0181            .Include(d => d.GoodBarcodes)
 0182            .ThenInclude(b => b.BarCode)
 0183            .Where(d => !d.IsDeleted
 0184                        && d.GoodBarcodes
 0185                            .Any(b => b.BarCode.Code.ToUpper().Equals(barcode.NormalizeName().ToUpper())));
 186
 187        public Task<List<Good>> FindGoodsByBarCodes(List<string> codes)
 0188        {
 0189            return _db.Goods
 0190                .Include(d => d.GoodBarcodes).ThenInclude(b => b.BarCode)
 0191                .Include(d => d.DefaultBarCode)
 0192                .Expressionify()
 0193                .Where(d => !d.IsDeleted && codes.Contains(d.GetActualBarCode().ToLower()))
 0194                .AsNoTracking()
 0195                .ToListAsync();
 0196        }
 197
 198        //JOIN
 67199        private IQueryable<Good> PrepeareGoods() => _db.Goods
 67200            .Include(d => d.Category).ThenInclude(d => d.Parent)
 67201            .Include(d => d.GoodBarcodes)
 67202            .ThenInclude(b => b.BarCode)
 67203            .Include(d => d.DefaultBarCode)
 67204            .Include(d => d.Barcodes)
 67205            .Include(d => d.Manufacturer)
 67206            .Include(d => d.Supplier)
 67207            .Include(d => d.Brand)
 67208            .Include(d => d.SubBrand)
 67209            .Include(d => d.Photos)
 67210            .Include(d => d.RecState)
 67211            .Include(d => d.VatsKind)
 67212            .Include(d => d.UnitsKind)
 67213            .Include(d => d.Country)
 67214            .Include(x => x.DepartmentGoodSettings).ThenInclude(x => x.Department)
 67215            .Include(d => d.Category)
 67216            .ThenInclude(x => x.DepartmentCategoryRatios).ThenInclude(x => x.Department)
 67217            .Include(d => d.Category)
 67218            .ThenInclude(x => x.DepartmentCategoryRatios).ThenInclude(x => x.Department)
 67219            .Include(x => x.Prices).ThenInclude(price => price.PriceTrend).ThenInclude(x => x.SupplierDepartment)
 67220            .Where(e => !e.IsDeleted)
 67221            .Expressionify()
 67222            .AsQueryable();
 223
 0224        private IQueryable<Good> PrepareNotDeletedGoods() => PrepeareGoods()
 0225            .Where(d => !d.IsDeleted);
 226
 227        public async Task CreateGood(Good good)
 368228        {
 229            try
 368230            {
 368231                if (good.RecState != null)
 368232                    _db.Entry(good.RecState).State = good.RecState.Id == 0 ? EntityState.Detached : EntityState.Unchange
 368233                await _db.Goods.AddAsync(good);
 368234                await _db.SaveChangesAsync(CurrentUserId);
 235
 368236                good.UpdateUniqueCode();
 368237                await _db.SaveChangesAsync(CurrentUserId);
 368238            }
 0239            catch (Exception e)
 0240            {
 0241                _logger.LogError("ошибка при создании товара");
 0242                _logger.LogError(e, e.Message);
 0243                throw;
 244            }
 368245        }
 246
 247        public async Task CreateGoodRange(List<Good> goods)
 1248        {
 23249            foreach (var good in goods)
 10250            {
 10251                if (good.Category != null)
 10252                {
 10253                    _db.Entry(good.Category).State = good.Category.Id == 0 ? EntityState.Detached : EntityState.Unchange
 10254                }
 10255                if (good.Manufacturer != null)
 0256                {
 0257                    _db.Entry(good.Manufacturer).State = good.Manufacturer.Id == 0 ? EntityState.Detached : EntityState.
 0258                }
 10259                if (good.Supplier != null)
 0260                {
 0261                    _db.Entry(good.Supplier).State = good.Supplier.Id == 0 ? EntityState.Detached : EntityState.Unchange
 0262                }
 10263                if (good.Brand != null)
 10264                {
 10265                    _db.Entry(good.Brand).State = good.Brand.Id == 0 ? EntityState.Detached : EntityState.Unchanged;
 10266                }
 10267                if (good.SubBrand != null)
 0268                {
 0269                    _db.Entry(good.SubBrand).State = good.SubBrand.Id == 0 ? EntityState.Detached : EntityState.Unchange
 0270                }
 10271                if (good.UnitsKind != null)
 10272                {
 10273                    _db.Entry(good.UnitsKind).State = good.UnitsKind.Id == 0 ? EntityState.Detached : EntityState.Unchan
 10274                }
 10275                if (good.VatsKind != null)
 10276                {
 10277                    _db.Entry(good.VatsKind).State = good.VatsKind.Id == 0 ? EntityState.Detached : EntityState.Unchange
 10278                }
 10279                if (good.RecState != null)
 10280                {
 10281                    _db.Entry(good.RecState).State = good.RecState.Id == 0 ? EntityState.Detached : EntityState.Unchange
 10282                }
 10283            }
 1284            await _db.Goods.AddRangeAsync(goods);
 1285            await _db.SaveChangesAsync(CurrentUserId);
 286
 23287            foreach (var good in goods)
 10288            {
 10289                good.UpdateUniqueCode();
 10290            }
 1291            await _db.SaveChangesAsync(CurrentUserId);
 1292        }
 293        //JOIN
 294        public async Task UpdateGood(Good data)
 0295        {
 0296            if (!(await GoodExists(data.Id)))
 0297            {
 0298                throw new ArgumentException($"Record #{data.Id} not found");
 299            }
 0300            _db.Goods.Update(data);
 0301            await _db.SaveChangesAsync(CurrentUserId);
 0302        }
 303        public async Task SetPhoto(Good good, List<Photo> photo)
 0304        {
 0305            good.Photos = photo;
 0306            await _db.SaveChangesAsync(CurrentUserId);
 0307        }
 308        public async Task DeleteGood(long goodId)
 0309        {
 0310            Good goodIn = _db.Goods.Where(e => !e.IsDeleted).FirstOrDefault(g => g.Id == goodId);
 0311            if (goodIn == null)
 0312            {
 0313                throw new KeyNotFoundException($"Record #{goodId} not found");
 314            }
 315
 0316            if (goodIn.RecState?.Id == (long)RecordState.Empty)
 0317            {
 0318                _db.Entry(goodIn).State = EntityState.Deleted;
 0319            }
 320            else
 0321            {
 0322                goodIn.IsDeleted = true;
 0323            }
 0324            await _db.SaveChangesAsync(CurrentUserId);
 0325        }
 0326        public async Task<bool> GoodExists(long id) => await _db.Goods
 0327            .AsNoTracking()
 0328            .Where(g => g.Id == id)
 0329            .Where(e => !e.IsDeleted)
 0330            .AnyAsync();
 331        public async Task ChangeGoodState(long id, RecordState state)
 0332        {
 0333            Good goodIn = await _db.Goods.Where(e => !e.IsDeleted).FirstAsync(g => g.Id == id);
 0334            if (goodIn == null)
 0335                throw new KeyNotFoundException($"Record good #{id} not found");
 0336            goodIn.RecState = _db.refRecordsState.Where(x=>!x.IsDeleted && x.Id == (long)state).FirstOrDefault();
 0337            await _db.SaveChangesAsync(CurrentUserId);
 0338        }
 339
 340        public IQueryable<Good> GetShowcaseGoodsBaseQuery(long? categoryId, Cluster cluster, bool showNA)
 0341        {
 0342            var pricesIds = _db.PriceTrendDetails
 0343                .Include(x => x.PriceTrend)
 0344                .Where(x => !x.IsDeleted && x.PriceTrend.SupplierDepartmentId == cluster.WarehouseId && x.PriceTrend.Beg
 0345                .Select(x => x.Id)
 0346                .ToList();
 347            // для данного склада коды видимых товаров
 0348            var settings = _db.DepartmentGoodSetting
 0349                .Where(x => !x.IsDeleted && x.DepartmentId == cluster.WarehouseId && x.ShowcaseVisible)
 0350                .Select(x => x.GoodId)
 0351                .ToList();
 0352            var qry = _db.Goods
 0353                .Include(d => d.Category).ThenInclude(x => x.DepartmentCategoryRatios).ThenInclude(x => x.Department)
 0354                .Include(d => d.GoodBarcodes)
 0355                .ThenInclude(barcode =>  barcode.BarCode)
 0356                .Include(d => d.DefaultBarCode)
 0357                .Include(d => d.Barcodes)
 0358                .Include(d => d.Manufacturer)
 0359                .Include(d => d.Supplier)
 0360                .Include(d => d.Brand)
 0361                .Include(d => d.SubBrand)
 0362                .Include(d => d.Photos)
 0363                .Include(d => d.RecState)
 0364                .Include(d => d.VatsKind)
 0365                .Include(d => d.UnitsKind)
 0366                .Include(d => d.Country)
 0367                .Include(d => d.Prices).ThenInclude(x => x.PriceTrend)
 0368                .Include(d => d.Rests)
 0369                .Include(x => x.DepartmentGoodSettings).ThenInclude(x => x.GoodSettingsLabels).ThenInclude(x => x.GoodLa
 0370                .Include(d => d.Rests)
 0371                .Include(d => d.Prices).ThenInclude(x => x.PriceTrend)
 0372                .Expressionify()
 0373                .Where(e => !e.IsDeleted && e.RecState.Id == (int)RecordState.Active && !e.Category.IsDeleted
 0374                    // только отображаемые товары для данного склада
 0375                    && settings.Contains(e.Id)
 0376                    // у товара должны быть действующие переоценки
 0377                    && e.Prices.Any(x => pricesIds.Contains(x.Id)));
 378
 379            // либо показываем все, либо должны быть остатки
 0380            if (!showNA)
 0381            {
 0382                var restsIds = _db.Rests
 0383                    .Where(x => !x.IsDeleted && x.DepartmentId == cluster.WarehouseId && x.Quantity > 0)
 0384                    .Select(x => x.GoodId)
 0385                    .ToList();
 0386                qry = qry.Where(x => restsIds.Contains(x.Id));
 0387            }
 388
 0389            if (categoryId.HasValue)
 0390            {
 0391                var cats = ExpandCategoryTree(new List<long> { categoryId.Value });
 0392                cats.Add(categoryId.Value);
 0393                qry = qry.Where(e => cats.Contains(e.Category.Id));
 0394            }
 395
 0396            return qry;
 0397        }
 398
 399        public IQueryable<Good> GetFilteredShowcaseGoodsQuery(IQueryable<Good> goodsQuery, Cluster cluster, decimal cont
 400            string filter, List<long> brands, List<long> countries, List<decimal> minQuantities, decimal? priceFrom, dec
 0401        {
 0402            if (!string.IsNullOrWhiteSpace(filter))
 0403            {
 0404                goodsQuery = goodsQuery.Where(x => x.Name.ToUpper().Contains(filter.ToUpper())
 0405                    || x.DefaultBarCode.Code.ToUpper().Contains(filter.ToUpper())
 0406                    || x.GoodBarcodes.Any(g => g.BarCode.Code.ToUpper().Contains(filter.ToUpper())));
 0407            }
 408
 0409            if (!string.IsNullOrWhiteSpace(labelName))
 0410            {
 0411                goodsQuery = goodsQuery.Where(x => x.DepartmentGoodSettings
 0412                    .Any(d => d.DepartmentId == cluster.WarehouseId
 0413                              && d.GoodSettingsLabels.Any(l =>
 0414                                  !l.GoodLabel.IsDeleted
 0415                                  && l.GoodLabel.Name.ToUpper().Equals(labelName.ToUpper()))));
 0416            }
 417
 0418            if (brands != null && brands.Any())
 0419            {
 0420                goodsQuery = goodsQuery.Where(x => brands.Contains(x.Brand.Id));
 0421            }
 422
 0423            if (countries != null && countries.Any())
 0424            {
 0425                goodsQuery = goodsQuery.Where(x => countries.Contains(x.Country.Id));
 0426            }
 427
 0428            if (minQuantities != null && minQuantities.Any())
 0429            {
 0430                goodsQuery = goodsQuery.Where(x => minQuantities.Contains(x.DepartmentGoodSettings.ActualMinQuantity(clu
 0431            }
 432
 0433            if(priceFrom.HasValue)
 0434            {
 0435                goodsQuery = goodsQuery.Where(x => x.CurrentPrice(cluster, contractRatio) >= priceFrom.Value);
 0436            }
 437
 0438            if (priceTo.HasValue)
 0439            {
 0440                goodsQuery = goodsQuery.Where(x => x.CurrentPrice(cluster, contractRatio) <= priceTo.Value);
 0441            }
 442
 0443            return goodsQuery;
 0444        }
 445
 446        public IQueryable<Good> GetPagedShowcaseGoodsQuery(IQueryable<Good> goodsQuery, Cluster cluster, int page, int l
 0447        {
 0448            switch ((sort ?? "").ToLower())
 449            {
 0450                case "name": goodsQuery = goodsQuery.OrderBy(x => x.Name); break;
 0451                case "name|desc": goodsQuery = goodsQuery.OrderByDescending(x => x.Name); break;
 0452                case "brandname": goodsQuery = goodsQuery.OrderBy(x => x.Brand.Name); break;
 0453                case "brandname|desc": goodsQuery = goodsQuery.OrderByDescending(x => x.Brand.Name); break;
 0454                case "price": goodsQuery = goodsQuery.OrderBy(x => x.Prices.Actual(cluster.WarehouseId).PriceNew); break
 0455                case "price|desc": goodsQuery = goodsQuery.OrderByDescending(x => x.Prices.Actual(cluster.WarehouseId).P
 0456                case "discount": goodsQuery = goodsQuery.OrderBy(x => x.Prices.Actual(cluster.WarehouseId).Discount); br
 0457                case "discount|desc": goodsQuery = goodsQuery.OrderByDescending(x => x.Prices.Actual(cluster.WarehouseId
 0458                case "countlabel|desc": goodsQuery = goodsQuery.OrderByDescending(x => x.DepartmentGoodSettings.LabelsCo
 0459                case "countlabel": goodsQuery = goodsQuery.OrderBy(x => x.DepartmentGoodSettings.LabelsCount(cluster.War
 0460                default: goodsQuery = goodsQuery.OrderBy(x => x.Id); break;
 461            }
 0462            return goodsQuery.Skip(page * limit).Take(limit);
 0463        }
 464
 465        public async Task<Good> GetShowcaseGood(long goodId, Cluster cluster)
 0466        {
 0467            return await GetShowcaseGoodsBaseQuery(null, cluster, true).FirstOrDefaultAsync(x => x.Id == goodId);
 0468        }
 469
 470        public async Task<List<Good>> FindGoodsByNames(List<string> names)
 0471        {
 0472            return await _db.Goods
 0473                .Include(x => x.Category)
 0474                .Include(x => x.Country)
 0475                .Include(x => x.Brand)
 0476                .Include(x => x.SubBrand)
 0477                .Include(x => x.Photos)
 0478                .Where(x => !x.IsDeleted && x.Category != null && names.Contains(x.Name.ToLower()))
 0479                .ToListAsync();
 0480        }
 481
 482        public async Task<List<Good>> FindGoodsByUniqueCodes(List<string> codes)
 0483        {
 0484            return await _db.Goods
 0485                .Include(x => x.Category)
 0486                .Include(x => x.Country)
 0487                .Include(x => x.Brand)
 0488                .Include(x => x.SubBrand)
 0489                .Include(x => x.Photos)
 0490                .Where(x => !x.IsDeleted && x.Category != null && codes.Contains(x.UniqueCode.ToLower()))
 0491                .ToListAsync();
 0492        }
 493
 494        public async Task<List<Good>> FindGoodsByVendorsCodes(List<string> codes, long departmentId)
 0495        {
 0496            return await _db.Goods
 0497                .Include(x => x.Category)
 0498                .Include(x => x.DepartmentGoodSettings)
 0499                .Expressionify()
 0500                .Where(x => !x.IsDeleted && x.Category != null && codes.Contains(x.GetActualVendorCode(departmentId).ToL
 0501                .ToListAsync();
 0502        }
 503
 504        public async Task<List<Good>> FindGoodsByIds(List<long> ids)
 0505        {
 0506            return await _db.Goods
 0507                .Include(x => x.Category)
 0508                .Where(x => !x.IsDeleted && x.Category != null && ids.Contains(x.Id))
 0509                .ToListAsync();
 0510        }
 511
 512        /// <summary>
 513        /// Возвращает список товаров для работы в заявках\отгрузках
 514        /// </summary>
 515        /// <param name="goodsId">список идентификаторов</param>
 516        /// <returns></returns>
 146517        public async Task<List<Good>> GetGoods(List<long> goodsId) => await _db.Goods
 146518            .Include(d => d.Rests)
 146519            .Include(x => x.Prices)
 146520            .ThenInclude(x => x.PriceTrend)
 146521            .ThenInclude(x => x.SupplierDepartment)
 146522            .Include(Good => Good.VatsKind)
 146523            .Include(Good => Good.DefaultBarCode)
 146524            .Include(Good => Good.GoodBarcodes)
 146525            .ThenInclude(barcode => barcode.BarCode)
 146526            .Include(good => good.Category)
 146527            .ThenInclude(category => category.DepartmentCategoryRatios)
 146528            .Include(Good => Good.Photos)
 146529            .Include(Good => Good.DepartmentGoodSettings)
 146530            .ThenInclude(DepartmentGoodSetting => DepartmentGoodSetting.Department)
 146531            .Where(d => !d.IsDeleted)
 146532            .Where(d => goodsId.Contains(d.Id))
 146533            .ToListAsync();
 534    }
 535}