| | | 1 | | using System; |
| | | 2 | | using Microsoft.AspNetCore.Authorization; |
| | | 3 | | using System.IO; |
| | | 4 | | using System.Data; |
| | | 5 | | using System.Collections.Generic; |
| | | 6 | | using System.Linq; |
| | | 7 | | using System.Threading.Tasks; |
| | | 8 | | using AutoMapper; |
| | | 9 | | using Microsoft.AspNetCore.Mvc; |
| | | 10 | | using Microsoft.Extensions.Logging; |
| | | 11 | | using Newtonsoft.Json; |
| | | 12 | | using SVETA.Api.Data.DTO; |
| | | 13 | | using SVETA.Api.Data.DTO.DepartmentDTO; |
| | | 14 | | using SVETA.Api.Data.DTO.Prices.PriceTrend; |
| | | 15 | | using Swashbuckle.AspNetCore.Annotations; |
| | | 16 | | using WinSolutions.Sveta.Server.Data.DataModel.Entities; |
| | | 17 | | using WinSolutions.Sveta.Server.Services.Interfaces; |
| | | 18 | | using SVETA.Api.Services.Interfaces; |
| | | 19 | | using Microsoft.AspNetCore.Http; |
| | | 20 | | using ExcelDataReader; |
| | | 21 | | using SVETA.Api.Data.Domain; |
| | | 22 | | using Microsoft.Extensions.Options; |
| | | 23 | | using WinSolutions.Sveta.Common.Extensions; |
| | | 24 | | using SVETA.Api.Services.Implements; |
| | | 25 | | using WinSolutions.Sveta.Common; |
| | | 26 | | using WinSolutions.Sveta.Server.Data.DataModel.Extensions; |
| | | 27 | | using SVETA.Api.Helpers; |
| | | 28 | | using System.Text; |
| | | 29 | | |
| | | 30 | | namespace SVETA.Api.Controllers |
| | | 31 | | { |
| | | 32 | | [Authorize] |
| | | 33 | | [Route("api/v1/PriceTrends")] |
| | | 34 | | [ApiController] |
| | | 35 | | public class PriceTrendsController : SvetaController |
| | | 36 | | { |
| | | 37 | | const string _routeUrl = "api/v1/PriceTrends"; |
| | | 38 | | private readonly IPriceTrendService _service; |
| | | 39 | | private readonly IGoodService _goodService; |
| | | 40 | | private readonly IDepartmentService _departmentService; |
| | | 41 | | private readonly IPriceWorker _priceWorker; |
| | | 42 | | private readonly IAuthenticationService _authService; |
| | | 43 | | private readonly ILogger<PriceTrendsController> _logger; |
| | | 44 | | private readonly ImagesSettings _imageSettings; |
| | | 45 | | IDiskStorageService _diskStorage; |
| | | 46 | | |
| | | 47 | | public PriceTrendsController(IPriceTrendService service, |
| | | 48 | | IDepartmentService departmentService, |
| | | 49 | | IGoodService goodService, |
| | | 50 | | IAuthenticationService authService, |
| | | 51 | | IPriceWorker priceWorker, |
| | | 52 | | IDiskStorageService diskStorage, |
| | | 53 | | IOptions<ImagesSettings> option, |
| | 0 | 54 | | ILogger<PriceTrendsController> logger) : base(logger) |
| | 0 | 55 | | { |
| | 0 | 56 | | _goodService = goodService; |
| | 0 | 57 | | _priceWorker = priceWorker; |
| | 0 | 58 | | _authService = authService; |
| | 0 | 59 | | _service = service; |
| | 0 | 60 | | _departmentService = departmentService; |
| | 0 | 61 | | _logger = logger; |
| | 0 | 62 | | _imageSettings = option.Value; |
| | 0 | 63 | | _diskStorage = diskStorage; |
| | 0 | 64 | | } |
| | | 65 | | |
| | | 66 | | /// <summary> |
| | | 67 | | /// Возвращает шапки переоценок |
| | | 68 | | /// </summary> |
| | | 69 | | /// <remarks>author: i.rebenok</remarks> |
| | | 70 | | /// <param name="page">Любое значение ниже нуля изменится на 1, пагинация: номер страницы</param> |
| | | 71 | | /// <param name="limit">Любое значение ниже нуля изменится на 10, пагинация: размер страницы</param> |
| | | 72 | | /// <param name="filter">фильтр по товарам, входящим в переоценку</param> |
| | | 73 | | /// <param name="departmentId">id склада поставщика. Если 0, то все переоценки выводить, если >0,то только с эти |
| | | 74 | | /// <param name="sort">сортировка по одному из полей |
| | | 75 | | /// по docnumber|desc, creationdate,creationdate|desc, begindate,begindate|desc, goodscount,goodscount|desc. Сор |
| | | 76 | | /// <param name="beginDate">Дата начала дейсвтия. По умолчанию null = выводим все</param> |
| | | 77 | | /// <param name="endDate">Дата окончания дейсвтия. По умолчанию null = выводим все</param> |
| | | 78 | | [HttpGet("")] |
| | | 79 | | [SwaggerResponse(200, "Успешно", typeof(BaseResponseDTO<PriceTrendsResponseDTO>))] |
| | | 80 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 81 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(ErrorDTO))] |
| | | 82 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SystemOperator + "," + Role.SupplierOwner + "," + Role.Supplier |
| | | 83 | | public async Task<IActionResult> GetPriceTrends(int page = 1, int limit = 10, long departmentId = 0, DateTimeOff |
| | 0 | 84 | | { |
| | 0 | 85 | | filter = filter.NormalizeName(); |
| | 0 | 86 | | page = page < 1 ? 1 : page; |
| | 0 | 87 | | limit = limit < 1 ? 10 : limit; |
| | 0 | 88 | | var result = await _service.GetPriceTrends(page - 1, limit, departmentId, beginDate.GetDate(), endDate.GetDa |
| | 0 | 89 | | var param = $"sort={sort}&departmentId={departmentId}&beginDate={beginDate.ToISOString()}&endDate={endDate.T |
| | 0 | 90 | | var response = new BaseResponseDTO<PriceTrendsResponseDTO>(_routeUrl, page, (int)limit, result.TotalFiltered |
| | 0 | 91 | | { |
| | 0 | 92 | | Data = result.Result.Select(x => new PriceTrendsResponseDTO(x)).ToList(), |
| | 0 | 93 | | }; |
| | 0 | 94 | | return Ok(response); |
| | 0 | 95 | | } |
| | | 96 | | |
| | | 97 | | /// <summary> |
| | | 98 | | /// Возвращает изменение цены по id переоценки |
| | | 99 | | /// </summary> |
| | | 100 | | /// <remarks>author: i.rebenok</remarks> |
| | | 101 | | /// <param name="page">Любое значение ниже нуля изменится на 1, пагинация: номер страницы</param> |
| | | 102 | | /// <param name="limit">Любое значение ниже нуля изменится на 10, пагинация: размер страницы</param> |
| | | 103 | | /// <param name="id">Идентификатор записи</param> |
| | | 104 | | /// <param name="filter">фильтр по названиям товаров, входящих в переоценку</param> |
| | | 105 | | /// <returns></returns> |
| | | 106 | | [HttpGet("{id}")] |
| | | 107 | | [SwaggerResponse(200, "Успешно", typeof(PriceTrendResponseDTO))] |
| | | 108 | | [SwaggerResponse(404, "Нет записей", typeof(EmptyResult))] |
| | | 109 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 110 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(string))] |
| | | 111 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SystemOperator + "," + Role.SupplierOwner + "," + Role.Supplier |
| | | 112 | | public async Task<IActionResult> GetPriceTrend([SwaggerParameter(Required = true)] long id, int page = 1, int li |
| | 0 | 113 | | { |
| | 0 | 114 | | filter = filter.NormalizeName(); |
| | 0 | 115 | | page = page < 1 ? 1 : page; |
| | 0 | 116 | | limit = limit < 1 ? 10 : limit; |
| | 0 | 117 | | var ptrend = _authService.IsUserPlatform() ? await _service.GetPriceTrend(id, null) : await _service.GetPric |
| | 0 | 118 | | if (ptrend == null) |
| | 0 | 119 | | return NotFoundResult($"Переоценка с id={id} не найдена"); |
| | 0 | 120 | | var details = await _service.GetPriceTrendDetails(ptrend.Id, page - 1, limit, filter); |
| | 0 | 121 | | details.Result.ForEach(x => x.Good.Photos.SetPhotoUrl(_imageSettings)); |
| | 0 | 122 | | var param = $""; |
| | 0 | 123 | | var trendDTO = new PriceTrendResponseDTO(ptrend); |
| | 0 | 124 | | trendDTO.PriceTrendDetails = new BaseResponseDTO<PriceTrendGoodsDTO>(_routeUrl, page, (int)limit, details.To |
| | 0 | 125 | | { |
| | 0 | 126 | | Data = details.Result.Select(x => new PriceTrendGoodsDTO(x)).ToList(), |
| | 0 | 127 | | }; |
| | | 128 | | //цена ближайшей переоценки , которая уже начала действовать, по этом товару и департаменту для каждого това |
| | 0 | 129 | | foreach (var item in trendDTO.PriceTrendDetails.Data) |
| | 0 | 130 | | item.PriceCurrent = (await _service.GetCurrentPriceFromDetail(item.GoodId, trendDTO.SupplierDepartment.I |
| | 0 | 131 | | return Ok(trendDTO); |
| | | 132 | | |
| | 0 | 133 | | } |
| | | 134 | | |
| | | 135 | | /// <summary> |
| | | 136 | | /// Список-источник товаров для добавления в переоценку |
| | | 137 | | /// </summary> |
| | | 138 | | /// <remarks>author: i.rebenok</remarks> |
| | | 139 | | /// <param name="page">Любое значение ниже нуля изменится на 1, пагинация: номер страницы</param> |
| | | 140 | | /// <param name="limit">Любое значение ниже нуля изменится на 10, пагинация: размер страницы</param> |
| | | 141 | | /// <param name="id">Идентификатор переоценки</param> |
| | | 142 | | /// <param name="filter">фильтр по названиям или коду товара</param> |
| | | 143 | | /// <param name="categoryId">0 - все категории, иначе конкретная. 0 по умолчанию</param> |
| | | 144 | | /// <param name="sort">сортировка по одному из полей |
| | | 145 | | /// по code,code|desc, name,name|desc. Сортировка по умолчанию по name</param> |
| | | 146 | | /// <returns></returns> |
| | | 147 | | [HttpGet("{id}/SourceGoods")] |
| | | 148 | | [SwaggerResponse(200, "Успешно", typeof(BaseResponseDTO<PriceTrendsSourceGoodsResponseDTO>))] |
| | | 149 | | [SwaggerResponse(404, "Нет записей", typeof(EmptyResult))] |
| | | 150 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 151 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(string))] |
| | | 152 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SystemOperator + "," + Role.SupplierOwner + "," + Role.Supplier |
| | | 153 | | public async Task<IActionResult> GetSourceGoods(long id, int page = 1, int limit = 10, long categoryId = 0, stri |
| | 0 | 154 | | { |
| | 0 | 155 | | filter = filter.NormalizeName(); |
| | 0 | 156 | | var ptrend = _authService.IsUserPlatform() ? await _service.GetPriceTrendWithDetails(id, null) : await _serv |
| | 0 | 157 | | if (ptrend == null) |
| | 0 | 158 | | return NotFoundResult($"Переоценка с id={id} не найдена"); |
| | 0 | 159 | | var goods = await _goodService.GetActiveGoods(page-1, limit, ptrend.SupplierDepartmentId, categoryId, sort, |
| | 0 | 160 | | var param = $"id={id}&categoryId={categoryId}&sort={sort}"; |
| | 0 | 161 | | var response = new BaseResponseDTO<PriceTrendsSourceGoodsResponseDTO>(_routeUrl + "/" + id + "/SourceGoods", |
| | 0 | 162 | | { |
| | 0 | 163 | | Data = goods.Result.Select(x => new PriceTrendsSourceGoodsResponseDTO() |
| | 0 | 164 | | { |
| | 0 | 165 | | Id = x.Id, |
| | 0 | 166 | | VendorCode = x.GetActualVendorCode(ptrend.SupplierDepartmentId), |
| | 0 | 167 | | Name = x.Name, |
| | 0 | 168 | | UniqueCode = x.UniqueCode, |
| | 0 | 169 | | IsInTrend = (ptrend.PriceTrendDetails.Any(d => d.Good.Id == x.Id && !d.IsDeleted) ? true : false), |
| | 0 | 170 | | TrendDetailId = ptrend.PriceTrendDetails.FirstOrDefault(d => d.Good.Id == x.Id)?.Id |
| | 0 | 171 | | }).ToList(), |
| | 0 | 172 | | }; |
| | 0 | 173 | | return Ok(response); |
| | 0 | 174 | | } |
| | | 175 | | |
| | | 176 | | /// <summary> |
| | | 177 | | /// Создает шапку переоценки |
| | | 178 | | /// </summary> |
| | | 179 | | /// <remarks>author: i.rebenok</remarks> |
| | | 180 | | /// <param name="data">PriceTrendRequestDTO</param> |
| | | 181 | | [HttpPost] |
| | | 182 | | [SwaggerResponse(201, "Успешно", typeof(PriceTrendsResponseDTO))] |
| | | 183 | | [SwaggerResponse(400, "Ошибка в параметрах запроса", typeof(ErrorDTO))] |
| | | 184 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(ErrorDTO))] |
| | | 185 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 186 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SupplierOwner + "," + Role.SupplierOperator)] |
| | | 187 | | public async Task<IActionResult> CreatePriceTrend([FromBody] [SwaggerParameter(Required = true)] PriceTrendReque |
| | 0 | 188 | | { |
| | | 189 | | |
| | 0 | 190 | | if (!ModelState.IsValid) |
| | 0 | 191 | | { |
| | 0 | 192 | | return BadRequestResult("Некорректные входные данные"); |
| | | 193 | | } |
| | 0 | 194 | | var ptrend = new PriceTrend() |
| | 0 | 195 | | { |
| | 0 | 196 | | BeginDate = data.BeginDate.UtcDateTime.Date, |
| | 0 | 197 | | SupplierDepartment = _authService.IsUserPlatform() ? await _departmentService.GetDepartment(data.Departm |
| | 0 | 198 | | DocNumber = "0" |
| | 0 | 199 | | }; |
| | 0 | 200 | | if (ptrend.SupplierDepartment == null) |
| | 0 | 201 | | return BadRequestResult(new ErrorDTO() { error = $"Подразделение с id={data.DepartmentId} не найдено" }) |
| | 0 | 202 | | await _service.CreatePriceTrend(ptrend); |
| | 0 | 203 | | return StatusCode(201, new PriceTrendsResponseDTO(ptrend)); |
| | 0 | 204 | | } |
| | | 205 | | |
| | | 206 | | /// <summary> |
| | | 207 | | /// Обновляет шапку переоценки |
| | | 208 | | /// </summary> |
| | | 209 | | /// <remarks>author i.rebenok</remarks> |
| | | 210 | | /// <param name="id">id переоценки</param> |
| | | 211 | | /// <param name="data">PriceTrendRequestDTO</param> |
| | | 212 | | [HttpPut("{id}")] |
| | | 213 | | [SwaggerResponse(200, "Успешно обновлено", typeof(PriceTrendsResponseDTO))] |
| | | 214 | | [SwaggerResponse(400, "Некорректные входные данные", typeof(EmptyResult))] |
| | | 215 | | [SwaggerResponse(404, "Нет записей", typeof(EmptyResult))] |
| | | 216 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 217 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(string))] |
| | | 218 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SupplierOwner + "," + Role.SupplierOperator)] |
| | | 219 | | public async Task<IActionResult> UpdatePriceTrend([SwaggerParameter(Required = true)] long id, [FromBody] [Swagg |
| | 0 | 220 | | { |
| | 0 | 221 | | if (!ModelState.IsValid) |
| | 0 | 222 | | { |
| | 0 | 223 | | return BadRequestResult("Некорректные входные данные"); |
| | | 224 | | } |
| | 0 | 225 | | var ptrend = _authService.IsUserPlatform() ? await _service.GetPriceTrend(id, null) : await _service.GetPric |
| | 0 | 226 | | if (ptrend == null) |
| | 0 | 227 | | return NotFoundResult($"Переоценка с id={id} не найдена"); |
| | 0 | 228 | | ptrend.BeginDate = data.BeginDate.Date; |
| | 0 | 229 | | ptrend.SupplierDepartment = _authService.IsUserPlatform() ? await _departmentService.GetDepartment(data.Depa |
| | 0 | 230 | | if (ptrend.SupplierDepartment == null) |
| | 0 | 231 | | return BadRequest(new ErrorDTO() { error = $"Подразделение с id={data.DepartmentId} не найдено" }); |
| | 0 | 232 | | await _service.UpdatePriceTrend(ptrend); |
| | 0 | 233 | | return Ok(new PriceTrendsResponseDTO(ptrend)); |
| | 0 | 234 | | } |
| | | 235 | | |
| | | 236 | | /// <summary> |
| | | 237 | | /// Создает позицию в переоценке |
| | | 238 | | /// </summary> |
| | | 239 | | /// <remarks>author: i.rebenok</remarks> |
| | | 240 | | /// <param name="id">id переоценки</param> |
| | | 241 | | /// <param name="data">PriceTrendDetailRequestDTO</param> |
| | | 242 | | [HttpPost("{id}/Items")] |
| | | 243 | | [SwaggerResponse(201, "Успешно", typeof(EmptyResult))] |
| | | 244 | | [SwaggerResponse(400, "Ошибка в параметрах запроса", typeof(ErrorDTO))] |
| | | 245 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(ErrorDTO))] |
| | | 246 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 247 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SupplierOwner + "," + Role.SupplierOperator)] |
| | | 248 | | public async Task<IActionResult> CreatePriceTrendDetail([SwaggerParameter(Required = true)] long id, [FromBody] |
| | 0 | 249 | | { |
| | 0 | 250 | | if (!ModelState.IsValid) |
| | 0 | 251 | | { |
| | 0 | 252 | | return BadRequestResult("Некорректные входные данные"); |
| | | 253 | | } |
| | | 254 | | |
| | 0 | 255 | | var ptrend = _authService.IsUserPlatform() ? await _service.GetPriceTrend(id, null) : await _service.GetPric |
| | 0 | 256 | | if (ptrend == null) |
| | 0 | 257 | | return NotFoundResult($"Переоценка с id={id} не найдена"); |
| | 0 | 258 | | var ptrendDetail = new PriceTrendDetail() |
| | 0 | 259 | | { |
| | 0 | 260 | | PriceNew = 0, |
| | 0 | 261 | | PriceOld = 0, |
| | 0 | 262 | | PriceTrend = ptrend, |
| | 0 | 263 | | Good = await _goodService.GetGood(data.GoodId) |
| | 0 | 264 | | }; |
| | 0 | 265 | | ptrendDetail.Discount = ptrendDetail.Discount(); |
| | 0 | 266 | | if (ptrendDetail.Good == null) |
| | 0 | 267 | | return BadRequestResult($"Не найден товар с id={data.GoodId}"); |
| | 0 | 268 | | await _service.CreatePriceTrendDetail(ptrendDetail); |
| | 0 | 269 | | return StatusCode(201); |
| | 0 | 270 | | } |
| | | 271 | | |
| | | 272 | | /// <summary> |
| | | 273 | | /// Обновляет позицию в переоценке |
| | | 274 | | /// </summary> |
| | | 275 | | /// <remarks>author i.rebenok</remarks> |
| | | 276 | | /// <param name="id">id позиции в переоценке</param> |
| | | 277 | | /// <param name="data">PriceTrendDetailRequestDTO</param> |
| | | 278 | | [HttpPut("Items/{id}")] |
| | | 279 | | [SwaggerResponse(200, "Успешно обновлено", typeof(EmptyResult))] |
| | | 280 | | [SwaggerResponse(400, "Некорректные входные данные", typeof(EmptyResult))] |
| | | 281 | | [SwaggerResponse(404, "Нет записей", typeof(EmptyResult))] |
| | | 282 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 283 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(string))] |
| | | 284 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SupplierOwner + "," + Role.SupplierOperator)] |
| | | 285 | | public async Task<IActionResult> UpdatePriceTrendDetail([SwaggerParameter(Required = true)] long id, [FromBody] |
| | 0 | 286 | | { |
| | 0 | 287 | | if (!ModelState.IsValid) |
| | 0 | 288 | | { |
| | 0 | 289 | | return BadRequestResult(""); |
| | | 290 | | } |
| | | 291 | | /*if (data.PriceNew < 0) |
| | | 292 | | return BadRequestResult("Новая цена не может быть меньше 0"); |
| | | 293 | | if (data.PriceOld < 0) |
| | | 294 | | return BadRequestResult("Старая цена не может быть меньше 0");*/ |
| | | 295 | | |
| | 0 | 296 | | var ptrend = _authService.IsUserPlatform() ? await _service.GetPriceTrendDetail(id, null) : await _service.G |
| | 0 | 297 | | if (ptrend == null) |
| | 0 | 298 | | return NotFoundResult($"Переоценка с id={id} не найдена"); |
| | 0 | 299 | | ptrend.PriceNew = data.PriceNew; |
| | 0 | 300 | | ptrend.PriceOld = data.PriceOld; |
| | 0 | 301 | | ptrend.Good = await _goodService.GetGood(data.GoodId); |
| | 0 | 302 | | ptrend.Discount = ptrend.Discount(); |
| | 0 | 303 | | if (ptrend.Good == null) |
| | 0 | 304 | | return BadRequestResult($"Не найден товар с id={data.GoodId}"); |
| | 0 | 305 | | await _service.UpdatePriceTrendDetail(ptrend); |
| | 0 | 306 | | return Ok(); |
| | 0 | 307 | | } |
| | | 308 | | |
| | | 309 | | /// <summary> |
| | | 310 | | /// Удаляет переоценку |
| | | 311 | | /// </summary> |
| | | 312 | | /// <remarks>author i.rebenok</remarks> |
| | | 313 | | /// <param name="id">id переоценки</param> |
| | | 314 | | [HttpDelete("{id}")] |
| | | 315 | | [SwaggerResponse(200, "Успешно удалено", typeof(EmptyResult))] |
| | | 316 | | [SwaggerResponse(404, "Нет записей", typeof(EmptyResult))] |
| | | 317 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 318 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(string))] |
| | | 319 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SupplierOwner + "," + Role.SupplierOperator)] |
| | | 320 | | public async Task<IActionResult> DeletePriceTrend([SwaggerParameter(Required = true)] long id) |
| | 0 | 321 | | { |
| | 0 | 322 | | await _service.DeletePriceTrend(id); |
| | 0 | 323 | | return Ok(); |
| | 0 | 324 | | } |
| | | 325 | | |
| | | 326 | | /// <summary> |
| | | 327 | | /// Удаляет позицию в переоценке |
| | | 328 | | /// </summary> |
| | | 329 | | /// <remarks>author i.rebenok</remarks> |
| | | 330 | | /// <param name="id">id позиции в переоценке</param> |
| | | 331 | | [HttpDelete("Items/{id}")] |
| | | 332 | | [SwaggerResponse(200, "Успешно удалено", typeof(EmptyResult))] |
| | | 333 | | [SwaggerResponse(404, "Нет записей", typeof(EmptyResult))] |
| | | 334 | | [SwaggerResponse(403, "Не разрешено для этого пользователя")] |
| | | 335 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(string))] |
| | | 336 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SupplierOwner + "," + Role.SupplierOperator)] |
| | | 337 | | public async Task<IActionResult> DeletePriceTrendDetail([SwaggerParameter(Required = true)] long id) |
| | 0 | 338 | | { |
| | 0 | 339 | | await _service.DeletePriceTrendDetail(id); |
| | 0 | 340 | | return Ok(); |
| | 0 | 341 | | } |
| | | 342 | | |
| | | 343 | | /// <summary> |
| | | 344 | | /// Загружает изменение цен из файла. |
| | | 345 | | /// Файл должен содержать колонки DepartmentId, Department, Good, VendorCode, Price, OldPrice |
| | | 346 | | /// </summary> |
| | | 347 | | /// <param name="file"></param> |
| | | 348 | | /// <remarks>author: oboligatov</remarks> |
| | | 349 | | [Obsolete] |
| | | 350 | | [HttpPost("UploadFromFile")] |
| | | 351 | | [SwaggerResponse(200, "Успешно", typeof(PriceTrendUploadResultDTO))] |
| | | 352 | | [SwaggerResponse(400, "Некорректная структура файла", typeof(ErrorDTO))] |
| | | 353 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(ErrorDTO))] |
| | | 354 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SupplierOwner + "," + Role.SupplierOperator)] |
| | | 355 | | public async Task<IActionResult> UploadFromFile(IFormFile file) |
| | 0 | 356 | | { |
| | 0 | 357 | | throw new NotImplementedException(); |
| | | 358 | | } |
| | | 359 | | |
| | | 360 | | /// <summary> |
| | | 361 | | /// Загружает изменение цен из файла. |
| | | 362 | | /// Файл должен содержать колонки DepartmentId, Department, Good, VendorCode, Price, OldPrice |
| | | 363 | | /// </summary> |
| | | 364 | | /// <param name="file"></param> |
| | | 365 | | /// <remarks>author: oboligatov</remarks> |
| | | 366 | | [HttpGet("UploadFromFile/Template")] |
| | | 367 | | [SwaggerResponse(302, "Успешно", typeof(RedirectResult))] |
| | | 368 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(ErrorDTO))] |
| | | 369 | | [Obsolete] |
| | | 370 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SupplierOwner + "," + Role.SupplierOperator)] |
| | | 371 | | public IActionResult UploadFromFileTemplate() |
| | 0 | 372 | | { |
| | 0 | 373 | | throw new NotImplementedException(); |
| | | 374 | | } |
| | | 375 | | |
| | | 376 | | |
| | | 377 | | /// <summary> |
| | | 378 | | /// Экспортирует в файл детали переоценки |
| | | 379 | | /// </summary> |
| | | 380 | | /// <param name="id">id переоценки</param> |
| | | 381 | | /// <param name="fileType">формат выходного файла (excel, csv), по умолчанию excel</param> |
| | | 382 | | /// <returns></returns> |
| | | 383 | | [HttpGet("Export/{id}")] |
| | | 384 | | [SwaggerResponse(200, "Успешно", typeof(File))] |
| | | 385 | | [SwaggerResponse(500, "Ошибка на стороне сервера", typeof(ErrorDTO))] |
| | | 386 | | [SwaggerResponse(403, "Не разрешено для этого пользователя", typeof(ErrorDTO))] |
| | | 387 | | [Authorize(Roles = Role.SystemAdmin + "," + Role.SystemOperator + "," + Role.SupplierOwner + "," + Role.Supplier |
| | | 388 | | public async Task<IActionResult> Export([SwaggerParameter(Required = true)]long id, string fileType = "excel") |
| | | 389 | | { |
| | | 390 | | PriceTrend priceTrendDetails = await _service.GetPriceTrendWithDetails(id, null); |
| | | 391 | | if(priceTrendDetails == null) |
| | | 392 | | return NotFound($"Переоценка с id={id} не найдена"); |
| | | 393 | | |
| | | 394 | | var department = await _departmentService.GetDepartment(priceTrendDetails.SupplierDepartment.Id); |
| | | 395 | | |
| | | 396 | | //только повелитель или местный юзер могут смотреть переоценки |
| | 0 | 397 | | if(!_authService.IsUserPlatform() && !department.UsersDepartments.Any(x => x.UserId == _authService.UserId)) |
| | | 398 | | return Forbid("Доступ к переоценкам чужого департамента запрещён"); |
| | | 399 | | |
| | | 400 | | var rows = new List<string[]>(); |
| | | 401 | | rows.Add(new string[] { "Шаблон загрузки цен (* - поле обязательно для заполнения, ** - одно из полей обязат |
| | | 402 | | rows.Add(new string[] { "**Уникальный код товара", "**Артикул", "**Штрихкод", "**Название товара", "*Акционн |
| | | 403 | | rows.Add(new string[] { "UniqueCode", "VendorCode", "BarCode", "GoodName", "Price", "OldPrice" }); |
| | | 404 | | |
| | | 405 | | priceTrendDetails.PriceTrendDetails |
| | 0 | 406 | | .Where(x => !x.Good.IsDeleted) |
| | | 407 | | .ToList() |
| | | 408 | | .ForEach(x => |
| | 0 | 409 | | { |
| | 0 | 410 | | rows.Add(new string[] |
| | 0 | 411 | | { |
| | 0 | 412 | | x.Good.UniqueCode, |
| | 0 | 413 | | x.Good.GetActualVendorCode(priceTrendDetails.SupplierDepartmentId), |
| | 0 | 414 | | x.Good.GetActualBarCode(), |
| | 0 | 415 | | x.Good.Name, |
| | 0 | 416 | | x.PriceNew.ToString(), |
| | 0 | 417 | | x.PriceOld.ToString() |
| | 0 | 418 | | }); |
| | 0 | 419 | | }); |
| | | 420 | | |
| | | 421 | | var stream = new MemoryStream(); |
| | | 422 | | if (fileType == "csv") |
| | | 423 | | { |
| | | 424 | | var csv = CsvUtil.ToCsv(rows); |
| | | 425 | | using (var writer = new StreamWriter(stream, encoding: Encoding.UTF8, leaveOpen: true)) |
| | | 426 | | { |
| | | 427 | | writer.Write(csv); |
| | | 428 | | } |
| | | 429 | | stream.Position = 0; |
| | | 430 | | |
| | | 431 | | Response.Headers.Add("Content-Disposition", $"attachment;filename=price_trends_{priceTrendDetails.DocNum |
| | | 432 | | return File(stream, "text/csv"); |
| | | 433 | | } |
| | | 434 | | else |
| | | 435 | | { |
| | | 436 | | using (var book = CsvUtil.ToExcel(rows)) |
| | | 437 | | { |
| | | 438 | | book.SaveAs(stream); |
| | | 439 | | |
| | | 440 | | return File(stream.ToArray(), |
| | | 441 | | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| | | 442 | | $"price_trends_{priceTrendDetails.DocNumber}.xlsx"); |
| | | 443 | | } |
| | | 444 | | } |
| | | 445 | | } |
| | | 446 | | } |
| | | 447 | | } |