< Summary

Class:WinSolutions.Sveta.Server.Services.Implements.WorkScheduleService
Assembly:WinSolutions.Sveta.Server
File(s):/opt/dev/sveta_api_build/WinSolutions.Sveta.Server/Services/Implements/WorkScheduleService.cs
Covered lines:76
Uncovered lines:12
Coverable lines:88
Total lines:204
Line coverage:86.3% (76 of 88)
Covered branches:24
Total branches:56
Branch coverage:42.8% (24 of 56)

Metrics

MethodLine coverage Branch coverage
.ctor(...)100%100%
GetSchedules()100%50%
GetNextWorkDay()100%100%
GetSchedules()100%100%
GetSchedule(...)100%100%
PrepareSchedules()100%100%
Create()87.5%50%
Create()85.71%50%
ScheduleExists()100%100%
Update()70%50%
Update()83.33%50%
Delete()85.71%50%
CalcPeriodFromSchedule()68.75%31.81%

File(s)

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

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using Microsoft.Extensions.Logging;
 3using System;
 4using System.Collections.Generic;
 5using System.Linq;
 6using System.Text.Json;
 7using System.Threading.Tasks;
 8using WinSolutions.Sveta.Server.Domain;
 9using WinSolutions.Sveta.Server.Data.DataModel.Contexts;
 10using WinSolutions.Sveta.Server.Data.DataModel.Entities;
 11using WinSolutions.Sveta.Server.Data.DataModel.Kinds;
 12using WinSolutions.Sveta.Server.Services.Interfaces;
 13using WinSolutions.Sveta.Common;
 14using SVETA.Api.Helpers;
 15
 16
 17namespace WinSolutions.Sveta.Server.Services.Implements
 18{
 19    public class WorkScheduleService : SvetaServiceBase, IWorkScheduleService
 20    {
 21        private readonly SvetaDbContext _db;
 22        private readonly ILogger<WorkScheduleService> _logger;
 23        public WorkScheduleService(SvetaDbContext db, ILogger<WorkScheduleService> logger, IAuthenticationService authen
 18524            : base(authenticationService)
 18525        {
 18526            _db = db;
 18527            _logger = logger;
 18528        }
 29
 30        /// <summary>
 31        /// получить записи с пагинацией
 32        /// </summary>
 33        /// <param name="page">номер страницы</param>
 34        /// <param name="limit">размер страницы</param>
 35        /// <param name="date">дата начала рабочего дня</param>
 36        /// <param name="workingDay">true, если только рабочие дни</param>
 37        /// <param name="sortByDateDesc">сортировать по дате начала дня</param>
 38        /// <param name="departmentId">id склада</param>
 39        /// <returns></returns>
 40        public async Task<PaginatedData<List<WorkSchedule>>> GetSchedules(int page, int limit, DateTime? date, bool work
 1041        {
 1042            var schedules = PrepareSchedules().AsNoTracking();
 1043            int total = await schedules?.CountAsync();
 1044            schedules = schedules.Where(x => !workingDay || x.IsWorkingDay == true)
 1045                .Where(x=> departmentId == 0 || x.WarehouseId == departmentId)
 1046                .Where(x => date.IsNullOrMinValue() || x.BeginTime.Date == date.Value.Date);
 1047            schedules = !sortByDateDesc ? schedules.OrderBy(x => x.BeginTime) : schedules.OrderByDescending(x => x.Begin
 1048            int filtered = await schedules?.CountAsync();
 1049            return new PaginatedData<List<WorkSchedule>>
 1050            {
 1051                Result = await schedules.Skip(page * limit).Take(limit).ToListAsync(),
 1052                TotalCount = total,
 1053                TotalFilteredCount = filtered
 1054            };
 1055        }
 56
 57        /// <summary>
 58        /// возвращает следующий после текущего рабочий день
 59        /// </summary>
 60        /// <param name="warehouseId">id склада</param>
 61        /// <returns></returns>
 2962        public async Task<WorkSchedule> GetNextWorkDay(long warehouseId) => await PrepareSchedules()
 2963            .Where(x => x.WarehouseId == warehouseId)
 2964            .OrderBy(x => x.BeginTime)
 2965            .FirstOrDefaultAsync(x => x.BeginTime > DateTime.UtcNow && x.IsWorkingDay);
 66
 67        /// <summary>
 68        /// получить все записи
 69        /// </summary>
 70        /// <returns></returns>
 18771        public async Task<List<WorkSchedule>> GetSchedules() => await PrepareSchedules().ToListAsync();
 72
 73        /// <summary>
 74        /// получить запись
 75        /// </summary>
 76        /// <param name="id">id записи</param>
 77        /// <returns></returns>
 178        public Task<WorkSchedule> GetSchedule(long id) => PrepareSchedules().FirstOrDefaultAsync(e => e.Id == id);
 79
 80        /// <summary>
 81        /// предварительная выборка записей
 82        /// </summary>
 83        /// <returns></returns>
 23084        private IQueryable<WorkSchedule> PrepareSchedules() => _db.WorkScheduler
 23085            .Include(x=>x.Warehouse).ThenInclude(x=>x.Contragent)
 23086           .Where(e => !e.IsDeleted)
 23087           .AsQueryable();
 88
 89        /// <summary>
 90        /// создает запись
 91        /// </summary>
 92        /// <param name="data">объект WorkSchedule</param>
 93        /// <returns></returns>
 94        public async Task Create(WorkSchedule data)
 195        {
 196            var existSchedule = PrepareSchedules().Any(x => x.BeginTime == data.BeginTime && x.EndTime == data.EndTime &
 197            if (existSchedule)
 098                throw new ArgumentException("Запись с указанной датой начала и окончания рабочего дня уже существует");
 199            _db.Entry(data.Warehouse).State = data.Warehouse.Id == 0 ? EntityState.Detached : EntityState.Unchanged;
 1100            await _db.WorkScheduler.AddAsync(data);
 1101            await _db.SaveChangesAsync(CurrentUserId);
 1102        }
 103
 104        /// <summary>
 105        /// создает список записей
 106        /// </summary>
 107        /// <param name="data">список записей WorkSchedule</param>
 108        /// <returns></returns>
 109        public async Task Create(List<WorkSchedule> data)
 187110        {
 187111            if (data.Count == 0)
 0112                return;
 187113            data.ForEach(x =>
 23811114            {
 23811115                _db.Entry(x.Warehouse).State = x.Warehouse.Id == 0 ? EntityState.Detached : EntityState.Unchanged;
 23811116            });
 187117            await _db.WorkScheduler.AddRangeAsync(data);
 187118            await _db.SaveChangesAsync(CurrentUserId);
 187119        }
 120
 121        /// <summary>
 122        /// проверяет существование записи
 123        /// </summary>
 124        /// <param name="id">id записи</param>
 125        /// <returns></returns>
 2126        public async Task<bool> ScheduleExists(long id) => await _db.WorkScheduler.AsNoTracking().Where(e => e.Id == id 
 127
 128        /// <summary>
 129        /// обновляет запись
 130        /// </summary>
 131        /// <param name="data">объект WorkSchedule</param>
 132        /// <returns></returns>
 133        public async Task Update(WorkSchedule data)
 1134        {
 1135            if (!(await ScheduleExists(data.Id)))
 0136            {
 0137                throw new ArgumentException($"Расписание с id={data.Id} не найдено");
 138            }
 1139            var existSchedule = PrepareSchedules().Any(x => x.BeginTime == data.BeginTime && x.EndTime == data.EndTime &
 1140            if (existSchedule)
 0141                throw new ArgumentException("Запись с указанной датой начала и окончания рабочего дня уже существует");
 1142            _db.WorkScheduler.Update(data);
 1143            await _db.SaveChangesAsync(CurrentUserId);
 1144        }
 145
 146        /// <summary>
 147        /// обновляет список записей
 148        /// </summary>
 149        /// <param name="data">список записей WorkSchedule</param>
 150        /// <returns></returns>
 151        public async Task Update(List<WorkSchedule> data)
 1152        {
 1153            if (data.Count == 0)
 0154                return;
 1155            _db.WorkScheduler.UpdateRange(data);
 1156            await _db.SaveChangesAsync(CurrentUserId);
 1157        }
 158
 159        /// <summary>
 160        /// удаляет запись
 161        /// </summary>
 162        /// <param name="id">id записи</param>
 163        /// <returns></returns>
 164        public async Task Delete(long id)
 1165        {
 1166            WorkSchedule rec = await _db.WorkScheduler.FindAsync(id);
 1167            if (rec == null)
 0168                throw new KeyNotFoundException($"Расписание с id={id} не найдено");
 1169            rec.IsDeleted = true;
 1170            await _db.SaveChangesAsync(CurrentUserId);
 1171        }
 172
 173        /// <summary>
 174        /// Подсчитывает рабочее время в минутах между двумя датами на основе расписания работы склада
 175        /// </summary>
 176        /// <remarks>author i.rebenok</remarks>
 177        /// <param name="dateFrom">Дата-время с</param>
 178        /// <param name="dateTo">Дата-время по</param>
 179        /// <param name="warehouseId">id склада</param>
 180        public async Task<double> CalcPeriodFromSchedule(DateTime dateFrom, DateTime dateTo, long warehouseId)
 1181        {
 182            //выбираем промежуток для расчетов. Увеличиваем диапазон на 1 день для начала и конца. Так как могут быть см
 183            //НАпример смена с 01.06 22:00 до 02.06 06:00. Мы передали даты расчета с 02.06 02:00 до 02.06 05:00. Чтобы 
 1184            var schedule = await PrepareSchedules().AsNoTracking().Where(x => x.IsWorkingDay && x.BeginTime.Date >= date
 1185            double result = 0;
 5186            foreach (var item in schedule)
 1187            {
 188                //или если datefrom < времени начала работы и dateto >= даты-времени окончания дня, то считаем весь день
 1189                if (dateFrom <= item.BeginTime && dateTo >= item.EndTime)
 0190                    result += item.EndTime.Subtract(item.BeginTime).TotalMinutes;
 191                //если внутри одного рабочего дня, считаем разницу между датами переданного периода
 1192                else if (dateFrom >= item.BeginTime && dateTo <= item.EndTime)
 1193                    result += dateTo.Subtract(dateFrom).TotalMinutes;
 194                //если datefrom <= времени начала работы и dateto находится в рабочем периоде этого дня, считаем разницу
 0195                else if (dateFrom <= item.BeginTime && dateTo <= item.EndTime && dateTo >= item.BeginTime)
 0196                    result += dateTo.Subtract(item.BeginTime).TotalMinutes;
 197                //если datefrom находится в рабочем периоде этого дня и dateto >= времени окончания дня, считаем разницу
 0198                else if (dateFrom >= item.BeginTime && dateFrom <= item.EndTime && dateTo >= item.EndTime)
 0199                    result += item.EndTime.Subtract(dateFrom).TotalMinutes;
 1200            }
 1201            return result;
 1202        }
 203    }
 204}