| | | 1 | | using Microsoft.EntityFrameworkCore; |
| | | 2 | | using SVETA.Api.Helpers.Authorize; |
| | | 3 | | using SVETA.Api.Services.Interfaces; |
| | | 4 | | using System; |
| | | 5 | | using SVETA.Api.Helpers; |
| | | 6 | | using System.IO; |
| | | 7 | | using System.Linq; |
| | | 8 | | using System.Collections.Generic; |
| | | 9 | | using Microsoft.Extensions.Options; |
| | | 10 | | using SVETA.Api.Data.Domain; |
| | | 11 | | using WinSolutions.Sveta.Common; |
| | | 12 | | using System.Security.Claims; |
| | | 13 | | using MimeKit; |
| | | 14 | | using MailKit.Net.Smtp; |
| | | 15 | | using System.Threading.Tasks; |
| | | 16 | | using WinSolutions.Sveta.Server.Data.DataModel.Contexts; |
| | | 17 | | using WinSolutions.Sveta.Server.Data.DataModel.Entities; |
| | | 18 | | using WinSolutions.Sveta.Server.Services.Interfaces; |
| | | 19 | | using Microsoft.Extensions.Logging; |
| | | 20 | | using SVETA.Api.Data.DTO; |
| | | 21 | | using WinSolutions.Sveta.Server.Data.DataModel.Extensions; |
| | | 22 | | using SVETA.Api.Services.Implements.ImportingExporting.Importers; |
| | | 23 | | |
| | | 24 | | namespace SVETA.Api.Services.Implements |
| | | 25 | | { |
| | | 26 | | public class UploadWorker : IUploadWorker |
| | | 27 | | { |
| | | 28 | | private readonly ILogger<UploadWorker> _logger; |
| | | 29 | | private readonly IWorkScheduleService _workScheduleService; |
| | | 30 | | private readonly IDepartmentService _departService; |
| | | 31 | | private readonly IEventService _eventService; |
| | | 32 | | private readonly IRestService _restService; |
| | | 33 | | private readonly IDirectoriesService _dirService; |
| | | 34 | | private readonly IDiskStorageService _diskStorage; |
| | | 35 | | private readonly IGoodSettingService _serviceGoodSetting; |
| | | 36 | | |
| | 0 | 37 | | public UploadWorker(IWorkScheduleService workScheduleService, IDepartmentService departService, IRestService res |
| | 0 | 38 | | ILogger<UploadWorker> logger, IEventService eventService, IDirectoriesService dirService, IDiskStorageServic |
| | 0 | 39 | | { |
| | 0 | 40 | | _restService = restService; |
| | 0 | 41 | | _workScheduleService = workScheduleService; |
| | 0 | 42 | | _dirService = dirService; |
| | 0 | 43 | | _diskStorage = diskStorage; |
| | 0 | 44 | | _eventService = eventService; |
| | 0 | 45 | | _departService = departService; |
| | 0 | 46 | | _logger = logger; |
| | 0 | 47 | | _serviceGoodSetting = serviceGoodSetting; |
| | 0 | 48 | | } |
| | | 49 | | |
| | | 50 | | /// <summary> |
| | | 51 | | /// Загружает расписание для склада |
| | | 52 | | /// </summary> |
| | | 53 | | /// <param name="warehouseId">id департманта</param> |
| | | 54 | | /// <param name="data">расписание в виде списка WorkScheduleFromFileDTO</param> |
| | | 55 | | /// <returns>результат загрузки в виде списка WorkScheduleFromFileResultDTO</returns> |
| | | 56 | | public async Task<List<WorkScheduleFromFileResultDTO>> Load(long warehouseId, List<WorkScheduleFromFileDTO> data |
| | | 57 | | { |
| | | 58 | | var result = new List<WorkScheduleFromFileResultDTO>(); |
| | | 59 | | var newEntries = new List<WorkSchedule>(); |
| | | 60 | | var existEntries = new List<WorkSchedule>(); |
| | | 61 | | var schedules = await _workScheduleService.GetSchedules(); |
| | | 62 | | var warehouse = await _departService.GetDepartment(warehouseId) ?? throw new ArgumentException($"Не найден с |
| | | 63 | | foreach (var row in data) |
| | | 64 | | { |
| | | 65 | | var parseResult = DateTime.TryParse(row.BeginTime, out DateTime beginTime); |
| | | 66 | | if (!parseResult) |
| | | 67 | | { |
| | | 68 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Некорректно задана дата и время начала рабочего д |
| | | 69 | | continue; |
| | | 70 | | } |
| | | 71 | | |
| | | 72 | | parseResult = DateTime.TryParse(row.EndTime, out DateTime endTime); |
| | | 73 | | if (!parseResult) |
| | | 74 | | { |
| | | 75 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Некорректно задана дата и время окончания рабочег |
| | | 76 | | continue; |
| | | 77 | | } |
| | | 78 | | |
| | | 79 | | if (beginTime > endTime) |
| | | 80 | | { |
| | | 81 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Дата начала рабочего дня не может быть больше дат |
| | | 82 | | continue; |
| | | 83 | | } |
| | | 84 | | |
| | | 85 | | if (endTime.Subtract(beginTime).TotalHours > 24) |
| | | 86 | | { |
| | | 87 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Длительность рабочего дня не может превышать 24 ч |
| | | 88 | | continue; |
| | | 89 | | } |
| | | 90 | | |
| | | 91 | | if (endTime.Subtract(beginTime).TotalHours < 1) |
| | | 92 | | { |
| | | 93 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Длительность рабочего дня не может быть меньше 1 |
| | | 94 | | continue; |
| | | 95 | | } |
| | | 96 | | |
| | | 97 | | parseResult = int.TryParse(row.Offset, out int offset); |
| | | 98 | | if (!parseResult) |
| | | 99 | | { |
| | | 100 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Некорректный часовой пояс")); |
| | | 101 | | continue; |
| | | 102 | | } |
| | | 103 | | |
| | | 104 | | if (!(offset >= 2 && offset <= 12)) |
| | | 105 | | { |
| | | 106 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Часовой пояс должен иметь значение от 2 до 12")); |
| | | 107 | | continue; |
| | | 108 | | } |
| | | 109 | | |
| | | 110 | | parseResult = Boolean.TryParse(row.IsWorkingDay, out bool workDay); |
| | | 111 | | if (!parseResult) |
| | | 112 | | { |
| | | 113 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Некорректно указан признак рабочего дня")); |
| | | 114 | | continue; |
| | | 115 | | } |
| | | 116 | | |
| | | 117 | | beginTime = beginTime.AddHours(-offset); //приводим к UTC |
| | | 118 | | endTime = endTime.AddHours(-offset); |
| | | 119 | | |
| | 0 | 120 | | var schedule = schedules.FirstOrDefault(x => x.BeginTime == beginTime && x.EndTime == endTime && x.Wareh |
| | | 121 | | if (schedule != null) |
| | | 122 | | { |
| | | 123 | | schedule.BeginTime = beginTime; |
| | | 124 | | schedule.EndTime = endTime; |
| | | 125 | | schedule.IsWorkingDay = workDay; |
| | | 126 | | existEntries.Add(schedule); |
| | | 127 | | } |
| | 0 | 128 | | else if (!newEntries.Any(x => x.BeginTime == beginTime && x.EndTime == endTime && x.Warehouse.Id == ware |
| | | 129 | | newEntries.Add(new WorkSchedule() |
| | | 130 | | { |
| | | 131 | | BeginTime = beginTime, |
| | | 132 | | EndTime = endTime, |
| | | 133 | | IsWorkingDay = workDay, |
| | | 134 | | Warehouse = warehouse |
| | | 135 | | }); |
| | | 136 | | else |
| | | 137 | | { |
| | | 138 | | result.Add(new WorkScheduleFromFileResultDTO(row, "Запись с указанной датой начала и окончания уже с |
| | | 139 | | continue; |
| | | 140 | | } |
| | | 141 | | } |
| | | 142 | | await _workScheduleService.Update(existEntries); |
| | | 143 | | await _workScheduleService.Create(newEntries); |
| | | 144 | | return result; |
| | | 145 | | } |
| | | 146 | | |
| | | 147 | | /// <summary> |
| | | 148 | | /// Загружает журнал событий |
| | | 149 | | /// </summary> |
| | | 150 | | /// <param name="filter">фильтр по значимым полям: причине или логину</param> |
| | | 151 | | /// <param name="entity">фильтр по имени объекта изменения. Если пусто, выводится по всем</param> |
| | | 152 | | /// <param name="sort">сортировка (entity, entity|desc, user, user|desc, dtcreated, dtcreated|desc)</param> |
| | | 153 | | /// <param name="dateFrom">дата с</param> |
| | | 154 | | /// <param name="dateTo">дата по</param> |
| | | 155 | | /// <param name="eventKind">тип события, 0 если отдавать события всех типов</param> |
| | | 156 | | /// <returns>результат загрузки в виде csv строк</returns> |
| | | 157 | | public async Task<string> DownloadEventsToFile(string filter = null, string sort = "", DateTimeOffset dateFrom = |
| | 0 | 158 | | { |
| | 0 | 159 | | var kinds = await _dirService.GetEventKinds(); |
| | 0 | 160 | | var events = await _eventService.GetEvents(0, int.MaxValue, filter, sort, dateFrom.GetStartOfDate(), dateTo. |
| | 0 | 161 | | var rows = new List<string[]>(); |
| | 0 | 162 | | rows.Add(new string[] { "ID пользователя", "Дата", "Время", "Действие", "Объект", "Причина" }); |
| | 0 | 163 | | events.Result.ForEach(x => |
| | 0 | 164 | | { |
| | 0 | 165 | | rows.Add(new string[] |
| | 0 | 166 | | { |
| | 0 | 167 | | x.User.Login, |
| | 0 | 168 | | x.DtCreated.Date.ToShortDateString(), |
| | 0 | 169 | | x.DtCreated.ToShortTimeString(), |
| | 0 | 170 | | kinds.Single(k => k.Id == (int)x.EventsKind.Id).Name, |
| | 0 | 171 | | x.Entity, |
| | 0 | 172 | | x.ReasonJson |
| | 0 | 173 | | }); |
| | 0 | 174 | | }); |
| | 0 | 175 | | var result = CsvUtil.ToCsv(rows); |
| | 0 | 176 | | return result; |
| | 0 | 177 | | } |
| | | 178 | | |
| | | 179 | | /// <summary> |
| | | 180 | | /// Загружает настройки товаров (GoodSettings) |
| | | 181 | | /// </summary> |
| | | 182 | | /// <param name="departmentId">id склада, 0 для всех</param> |
| | | 183 | | /// <returns>результат загрузки в виде csv строк</returns> |
| | | 184 | | public async Task<MemoryStream> DownloadGoodSettingsToFile(long departmentId) |
| | 0 | 185 | | { |
| | 0 | 186 | | var items = await _serviceGoodSetting.GetDepartmentGoodSettings(departmentId); |
| | | 187 | | |
| | 0 | 188 | | var rows = new List<GoodSettingRecord>(); |
| | 0 | 189 | | items.ForEach(x => |
| | 0 | 190 | | { |
| | 0 | 191 | | rows.Add(new GoodSettingRecord() |
| | 0 | 192 | | { |
| | 0 | 193 | | UniqueCode = x.Good.UniqueCode, |
| | 0 | 194 | | VendorCode = x.GetActualVendorCode(), |
| | 0 | 195 | | BarCode = x.Good.GetActualBarCode(), |
| | 0 | 196 | | GoodName = x.Good.Name, |
| | 0 | 197 | | MinQuantity = x.MinQuantity.ToString(), |
| | 0 | 198 | | PickingQuantum = x.PickingQuantum.ToString(), |
| | 0 | 199 | | ShowcaseVisible = x.ShowcaseVisible.ToString() |
| | 0 | 200 | | }); |
| | 0 | 201 | | }); |
| | 0 | 202 | | return CsvUtil.ToExcelStream(ImportingExporting.TemplateHelper.GetTemplate(rows)); |
| | 0 | 203 | | } |
| | | 204 | | |
| | | 205 | | /// <summary> |
| | | 206 | | /// Загружает остатки |
| | | 207 | | /// </summary> |
| | | 208 | | /// <param name="departmentId">id склада, 0 для всех</param> |
| | | 209 | | /// <returns>результат загрузки в виде csv строк</returns> |
| | | 210 | | public async Task<MemoryStream> DownloadRestsToFile(long departmentId) |
| | 0 | 211 | | { |
| | 0 | 212 | | var items = await _restService.GetRests(0, int.MaxValue, 0, departmentId, null, null, -1); |
| | 0 | 213 | | var settings = await _serviceGoodSetting.GetDepartmentGoodSettings(departmentId); |
| | | 214 | | |
| | 0 | 215 | | var rows = new List<RestRecord>(); |
| | 0 | 216 | | items.Result.ForEach(x => |
| | 0 | 217 | | { |
| | 0 | 218 | | var setting = settings.FirstOrDefault(s => s.GoodId == x.GoodId); |
| | 0 | 219 | | rows.Add(new RestRecord |
| | 0 | 220 | | { |
| | 0 | 221 | | UniqueCode = x.Good.UniqueCode, |
| | 0 | 222 | | VendorCode = (setting?.GetActualVendorCode()) ?? x.Good.UniqueCode, |
| | 0 | 223 | | BarCode = x.Good.GetActualBarCode(), |
| | 0 | 224 | | GoodName = x.Good.Name, |
| | 0 | 225 | | Quantity = x.Quantity.ToString() |
| | 0 | 226 | | }); |
| | 0 | 227 | | }); |
| | | 228 | | |
| | 0 | 229 | | return CsvUtil.ToExcelStream(ImportingExporting.TemplateHelper.GetTemplate(rows)); |
| | 0 | 230 | | } |
| | | 231 | | } |
| | | 232 | | } |