< Summary

Class:WinSolutions.Sveta.Server.Services.Implements.PriceTrendService
Assembly:WinSolutions.Sveta.Server
File(s):/opt/dev/sveta_api_build/WinSolutions.Sveta.Server/Services/Implements/PriceTrendService.cs
Covered lines:36
Uncovered lines:110
Coverable lines:146
Total lines:304
Line coverage:24.6% (36 of 146)
Covered branches:5
Total branches:70
Branch coverage:7.1% (5 of 70)

Metrics

MethodLine coverage Branch coverage
.ctor(...)100%100%
CreatePriceTrend()100%50%
PreparePriceTrends()100%100%
PreparePriceTrendsDetail()0%100%
DeletePriceTrend()0%0%
DeletePriceTrendDetail()0%0%
GetCurrentPriceFromDetail()0%100%
GetPriceTrend()0%100%
GetPriceTrendWithDetails()0%100%
GetPriceTrendDetails()0%0%
GetPriceTrendDetail()0%100%
GetPriceTrends()0%0%
PriceTrendExists()100%100%
UpdatePriceTrend()71.42%50%
CreatePriceTrendDetail()66.66%50%
PriceTrendDetailExists()0%100%
UpdatePriceTrendDetail()0%0%
Sort(...)0%0%

File(s)

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

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using Microsoft.Extensions.Logging;
 3using System;
 4using System.Collections.Generic;
 5using System.Linq;
 6using System.Text;
 7using System.Threading.Tasks;
 8using WinSolutions.Sveta.Server.Data.DataModel.Contexts;
 9using WinSolutions.Sveta.Server.Data.DataModel.Entities;
 10using WinSolutions.Sveta.Server.Services.Interfaces;
 11using WinSolutions.Sveta.Common;
 12using WinSolutions.Sveta.Server.Domain;
 13using SVETA.Api.Helpers;
 14using Microsoft.EntityFrameworkCore.Internal;
 15using Clave.Expressionify;
 16
 17namespace WinSolutions.Sveta.Server.Services.Implements
 18{
 19    public class PriceTrendService : SvetaServiceBase, IPriceTrendService
 20    {
 21        private readonly SvetaDbContext _db;
 22        private readonly ILogger<PriceTrendService> _logger;
 23        private readonly IAuthenticationService _authenticationService;
 24        private readonly IDepartmentService _departService;
 25
 26        public PriceTrendService(SvetaDbContext db, ILogger<PriceTrendService> logger, IAuthenticationService authentica
 18427            : base(authenticationService)
 18428        {
 18429            _db = db;
 18430            _departService = departService;
 18431            _logger = logger;
 18432            _authenticationService = authenticationService;
 18433        }
 34
 35        /// <summary>
 36        /// создает запись в PriceTrend
 37        /// </summary>
 38        /// <param name="data">объект PriceTrend</param>
 39        /// <returns></returns>
 40        public async Task CreatePriceTrend(PriceTrend data)
 18441        {
 18442            _db.Entry(data.SupplierDepartment).State = EntityState.Unchanged;
 18443            await _db.PricesTrend.AddAsync(data);
 18444            await _db.SaveChangesAsync(CurrentUserId);
 18445            data.DocNumber = "PT" + data.Id.ToString("D8");
 18446            await UpdatePriceTrend(data);
 18447        }
 48
 49        /// <summary>
 50        /// предварительная выборка объектов PriceTrend
 51        /// </summary>
 52        /// <returns></returns>
 18453        private IQueryable<PriceTrend> PreparePriceTrends() => _db.PricesTrend
 18454            .Include(e => e.SupplierDepartment).ThenInclude(SupplierDepartment => SupplierDepartment.Contragent)
 18455            .Where(e => !e.IsDeleted)
 18456            .AsQueryable();
 57
 58        /// <summary>
 59        /// предварительная выборка объектов PriceTrendDetail
 60        /// </summary>
 61        /// <returns></returns>
 062        private IQueryable<PriceTrendDetail> PreparePriceTrendsDetail() => _db.PriceTrendDetails
 063            .Include(e => e.Good).ThenInclude(x => x.Category)
 064            .Include(e => e.Good).ThenInclude(x => x.GoodBarcodes).ThenInclude(d => d.BarCode)
 065            .Include(e => e.Good).ThenInclude(x => x.DefaultBarCode)
 066            .Include(e => e.Good).ThenInclude(x => x.Photos)
 067            .Include(d => d.Good)
 068            .ThenInclude(Good => Good.DepartmentGoodSettings)
 069            .Include(e => e.PriceTrend).ThenInclude(PriceTrend => PriceTrend.SupplierDepartment).ThenInclude(SupplierDep
 070            .Where(e => !e.IsDeleted && !e.Good.IsDeleted)
 071            .AsQueryable();
 72
 73        /// <summary>
 74        /// удаляет запись из PriceTrend
 75        /// </summary>
 76        /// <param name="id">id записи</param>
 77        /// <returns></returns>
 78        public async Task DeletePriceTrend(long id)
 079        {
 080            var data = await PreparePriceTrends()
 081                .FirstAsync(p => p.Id == id);
 082            if (data == null)
 083            {
 084                throw new KeyNotFoundException($"Переоценка с id={id} не найдена");
 85            }
 086            var details = _db.PriceTrendDetails.Where(x => x.PriceTrendId == id);
 087            foreach (var item in details)
 088                item.IsDeleted = true;
 089            data.IsDeleted = true;
 090            await _db.SaveChangesAsync(CurrentUserId);
 091        }
 92
 93        /// <summary>
 94        /// удаляет запись из PriceTrendDetail
 95        /// </summary>
 96        /// <param name="id">id записи</param>
 97        /// <returns></returns>
 98        public async Task DeletePriceTrendDetail(long id)
 099        {
 0100            var data = await _db.PriceTrendDetails
 0101                .FirstAsync(p => p.Id == id);
 0102            if (data == null)
 0103            {
 0104                throw new KeyNotFoundException($"Переоценка товара с id={id} не найдена");
 105            }
 0106            data.IsDeleted = true;
 0107            await _db.SaveChangesAsync(CurrentUserId);
 0108        }
 109
 110        /// <summary>
 111        /// Возвращает последнюю цену переоценки, которая уже действует (она есть текущая цена)
 112        /// </summary>
 113        /// <param name="goodId">id товара</param>
 114        /// <param name="departmentId">id склада</param>
 115        /// <returns></returns>
 0116        public async Task<PriceTrendDetail> GetCurrentPriceFromDetail(long goodId, long departmentId) => await PreparePr
 0117                .Where(x => x.PriceTrend.BeginDate <= DateTime.Now && x.GoodId == goodId && x.PriceTrend.SupplierDepartm
 0118                .OrderBy(x => x.PriceTrend.BeginDate)
 0119                .LastOrDefaultAsync();
 120
 121        /// <summary>
 122        /// получить запись из PriceTrend
 123        /// </summary>
 124        /// <param name="id">id записи</param>
 125        /// <param name="contragentId">id контрагента (необязательно)</param>
 126        /// <returns></returns>
 0127        public async Task<PriceTrend> GetPriceTrend(long id, long? contragentId) => await PreparePriceTrends()
 0128            .Where(x=> !contragentId.HasValue || x.SupplierDepartment.Contragent.Id == contragentId)
 0129            .FirstOrDefaultAsync(d => d.Id == id);
 130
 131        /// <summary>
 132        /// получить запись из PriceTrend с привязкой записей из PriceTrendDetail
 133        /// </summary>
 134        /// <param name="id">id записи</param>
 135        /// <param name="contragentId">id контрагента (необязательно)</param>
 136        /// <returns></returns>
 0137        public async Task<PriceTrend> GetPriceTrendWithDetails(long id, long? contragentId) => await PreparePriceTrends(
 0138            .Include(e => e.PriceTrendDetails)
 0139                .ThenInclude(PriceTrendDetails => PriceTrendDetails.Good)
 0140                    .ThenInclude(x => x.DefaultBarCode)
 0141            .Include(e => e.PriceTrendDetails)
 0142                .ThenInclude(PriceTrendDetails => PriceTrendDetails.Good)
 0143                    .ThenInclude(x => x.GoodBarcodes)
 0144                        .ThenInclude(x => x.BarCode)
 0145            .Expressionify()
 0146            .AsNoTracking()
 0147            .Where(x => !contragentId.HasValue || x.SupplierDepartment.Contragent.Id == contragentId)
 0148            .FirstOrDefaultAsync(d => d.Id == id);
 149
 150        /// <summary>
 151        /// получает записи из PriceTrendDetail с пагинацией и фильтрацией
 152        /// </summary>
 153        /// <param name="priceTrendId">id родительской записи</param>
 154        /// <param name="page">номер страницы</param>
 155        /// <param name="limit">размер страницы</param>
 156        /// <param name="filter">фильтр по названию товара</param>
 157        /// <returns></returns>
 158        public async Task<PaginatedData<List<PriceTrendDetail>>> GetPriceTrendDetails(long priceTrendId, int page, int l
 0159        {
 0160            var details = PreparePriceTrendsDetail().AsNoTracking().Where(x=>x.PriceTrendId == priceTrendId);
 0161            int total = await details?.CountAsync();
 0162            details = details.Where(x => string.IsNullOrWhiteSpace(filter) || x.Good.Name.ToUpper().Contains(filter.ToUp
 0163            int totalFiltered = await details?.CountAsync();
 0164            return new PaginatedData<List<PriceTrendDetail>>
 0165            {
 0166                Result = await details.Skip(page * limit).Take(limit).ToListAsync(),
 0167                TotalCount = total,
 0168                TotalFilteredCount = totalFiltered
 0169            };
 0170        }
 171
 172        /// <summary>
 173        /// получить запись из PriceTrendDetail
 174        /// </summary>
 175        /// <param name="id">id записи </param>
 176        /// <param name="contragentId">id контрагента (необязательно)</param>
 177        /// <returns></returns>
 0178        public async Task<PriceTrendDetail> GetPriceTrendDetail(long id, long? contragentId) => await PreparePriceTrends
 0179            .Where(d => !contragentId.HasValue || d.PriceTrend.SupplierDepartment.Contragent.Id == contragentId)
 0180            .FirstOrDefaultAsync(d => d.Id == id);
 181
 182        /// <summary>
 183        /// получить список записей из PriceTrend с пагинацией, сортировкой и фильтрацией
 184        /// </summary>
 185        /// <param name="page">номер страницы</param>
 186        /// <param name="limit">размер страницы</param>
 187        /// <param name="departmentId">id склада</param>
 188        /// <param name="beginDate">дата с</param>
 189        /// <param name="endDate">дата по</param>
 190        /// <param name="filter">фильтр по названию товара</param>
 191        /// <param name="sort">сортировка</param>
 192        /// <returns></returns>
 193        public async Task<PaginatedData<List<PriceTrend>>> GetPriceTrends(int page, int limit, long departmentId, DateTi
 0194        {
 0195            var prices = PreparePriceTrends().Include(e => e.PriceTrendDetails).ThenInclude(PriceTrendDetails => PriceTr
 196            // Тотал записей для смертных считаем после прмиенения ограничения роли
 0197            int total = await prices?.CountAsync(x => _authenticationService.IsUserPlatform() || x.SupplierDepartment.Co
 0198            prices = prices.Where(x => _authenticationService.IsUserPlatform() || x.SupplierDepartment.Contragent.Id == 
 0199                .Where(x=> departmentId ==0 || x.SupplierDepartment.Id == departmentId)
 0200                .Where(x=> beginDate.IsNullOrMinValue() || x.BeginDate.Date >= beginDate.Value.Date)
 0201                .Where(x => endDate.IsNullOrMinValue() || x.BeginDate.Date <= endDate.Value.Date) //сравниваем с beginda
 0202                .Where(x => string.IsNullOrWhiteSpace(filter) || x.PriceTrendDetails.Any(x=> x.Good.Name.ToUpper().Conta
 0203            prices = Sort(prices, sort?.ToLower());
 0204            int filtered = await prices?.CountAsync();
 0205            return new PaginatedData<List<PriceTrend>>
 0206            {
 0207                Result = await prices.Skip(page * limit).Take(limit).ToListAsync(),
 0208                TotalCount = total,
 0209                TotalFilteredCount = filtered
 0210            };
 0211        }
 212
 213        /// <summary>
 214        /// проверяет существование записи в PriceTrend
 215        /// </summary>
 216        /// <param name="id">id записи</param>
 217        /// <returns></returns>
 184218        public async Task<bool> PriceTrendExists(long id) => await PreparePriceTrends()
 184219            .Where(e => e.Id == id)
 184220            .AnyAsync();
 221
 222        /// <summary>
 223        /// обновляет запись в PriceTrend
 224        /// </summary>
 225        /// <param name="data">объект PriceTrend</param>
 226        /// <returns></returns>
 227        public async Task UpdatePriceTrend(PriceTrend data)
 184228        {
 184229            if (!(await PriceTrendExists(data.Id)))
 0230            {
 0231                throw new ArgumentException($"Переоценка с id={data.Id} не найдена");
 232            }
 184233            _db.PricesTrend.Update(data);
 184234            await _db.SaveChangesAsync(CurrentUserId);
 184235        }
 236
 237        /// <summary>
 238        /// создает запись в PriceTrendDetail
 239        /// </summary>
 240        /// <param name="data">объект PriceTrendDetail</param>
 241        /// <returns></returns>
 242        public async Task CreatePriceTrendDetail(PriceTrendDetail data)
 368243        {
 368244            var existing = await _db.PriceTrendDetails.FirstOrDefaultAsync(x => x.Good.Id == data.Good.Id && x.PriceTren
 368245            if (existing != null)
 0246            {
 0247                existing.PriceNew = data.PriceNew;
 0248                existing.PriceOld = data.PriceOld;
 0249                existing.IsDeleted = false;
 0250            }
 251            else
 368252            {
 368253                _db.Entry(data.Good).State = EntityState.Unchanged;
 368254                _db.Entry(data.PriceTrend).State = EntityState.Unchanged;
 368255                await _db.PriceTrendDetails.AddAsync(data);
 368256            }
 368257            await _db.SaveChangesAsync(CurrentUserId);
 368258        }
 259
 260        /// <summary>
 261        /// проверяет существование записи в PriceTrendDetails
 262        /// </summary>
 263        /// <param name="id">id записи</param>
 264        /// <returns></returns>
 0265        public async Task<bool> PriceTrendDetailExists(long id) => await _db.PriceTrendDetails
 0266            .Where(e => e.Id == id)
 0267            .AnyAsync();
 268
 269        /// <summary>
 270        /// обновляет запись в PriceTrendDetail
 271        /// </summary>
 272        /// <param name="data">объект PriceTrendDetail</param>
 273        /// <returns></returns>
 274        public async Task UpdatePriceTrendDetail(PriceTrendDetail data)
 0275        {
 0276            if (!(await PriceTrendDetailExists(data.Id)))
 0277            {
 0278                throw new ArgumentException($"Переоценка товара с id={data.Id} не найдена");
 279            }
 0280            _db.PriceTrendDetails.Update(data);
 0281            await _db.SaveChangesAsync(CurrentUserId);
 0282        }
 283
 284        /// <summary>
 285        /// сортировка
 286        /// </summary>
 287        /// <param name="items">выборка записей PriceTrend</param>
 288        /// <param name="sort">тип сортировки</param>
 289        /// <returns></returns>
 0290        private IQueryable<PriceTrend> Sort(IQueryable<PriceTrend> items, string sort = default) => (sort ?? "").ToLower
 0291        {
 0292            "goodscount" => items.OrderBy(d => d.PriceTrendDetails.Count()),
 0293            "goodscount|desc" => items.OrderByDescending(d => d.PriceTrendDetails.Count()),
 0294            "begindate" => items.OrderBy(d => d.BeginDate),
 0295            "begindate|desc" => items.OrderByDescending(d => d.BeginDate),
 0296            "creationdate" => items.OrderBy(d => d.CreationDateTime),
 0297            "creationdate|desc" => items.OrderByDescending(d => d.CreationDateTime),
 0298            "docnumber" => items.OrderBy(d => d.DocNumber),
 0299            _ => items.OrderByDescending(d => d.DocNumber)
 0300        };
 301
 302
 303    }
 304}