< Summary

Class:SVETA.Api.Services.Implements.FeedsWorker
Assembly:SVETA.Api
File(s):/opt/dev/sveta_api_build/SVETA.Api/Services/Implements/FeedsWorker.cs
Covered lines:0
Uncovered lines:170
Coverable lines:170
Total lines:240
Line coverage:0% (0 of 170)
Covered branches:0
Total branches:76
Branch coverage:0% (0 of 76)

Metrics

MethodLine coverage Branch coverage
.ctor(...)0%100%
CreateFeedForYandex()0%0%
CreateFeedForGoogle()0%0%
NormalizeStringValues(...)0%100%
NormalizeExpireValues(...)0%100%

File(s)

/opt/dev/sveta_api_build/SVETA.Api/Services/Implements/FeedsWorker.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore;
 2using System.IO;
 3using System.Threading;
 4using System.Globalization;
 5using System.IO.Compression;
 6using SVETA.Api.Helpers.Authorize;
 7using SVETA.Api.Services.Interfaces;
 8using System;
 9using System.Linq;
 10using CrmVtbc;
 11using System.Collections.Generic;
 12using Microsoft.Extensions.Options;
 13using SVETA.Api.Data.Domain;
 14using WinSolutions.Sveta.Common;
 15using System.Security.Claims;
 16using System.Threading.Tasks;
 17using WinSolutions.Sveta.Server.Data.DataModel.Contexts;
 18using WinSolutions.Sveta.Server.Data.DataModel.Entities;
 19using WinSolutions.Sveta.Server.Services.Interfaces;
 20using Microsoft.Extensions.Logging;
 21using System.Xml.Linq;
 22using System.Security.Policy;
 23using Microsoft.AspNetCore.Mvc.Routing;
 24using System.Net.Http;
 25
 26namespace SVETA.Api.Services.Implements
 27{
 28    public class FeedsWorker : IFeedsWorker
 29    {
 30        private readonly SvetaDbContext _db;
 31        private readonly ILogger<FeedsWorker> _logger;
 32        private readonly UploadDownloadSettings _uploadSettings;
 33        private readonly ImagesSettings _imagesSettings;
 34        private readonly IDirectoriesService _dirService;
 35        private readonly ICategoryService _catService;
 36        private readonly IShowcaseWorker _showCaseWorker;
 37        private readonly CommonSettings _commonSettings;
 38
 039        public FeedsWorker(SvetaDbContext db,
 040            ILogger<FeedsWorker> logger,
 041            IOptions<UploadDownloadSettings> uploadSettings,
 042            IOptions<CommonSettings> commonSettings,
 043            IOptions<ImagesSettings> imagesSettings,
 044            IDirectoriesService dirService,
 045            ICategoryService catService,
 046            IShowcaseWorker showCaseWorker)
 047        {
 048            _db = db;
 049            _commonSettings = commonSettings.Value;
 050            _imagesSettings = imagesSettings.Value;
 051            _showCaseWorker = showCaseWorker;
 052            _catService = catService;
 053            _uploadSettings = uploadSettings.Value;
 054            _dirService = dirService;
 055            _logger = logger;
 056        }
 57
 58        /// <summary>
 59        /// Генерирует фид для яндекса
 60        /// </summary>
 61        /// <param name="filename">название выходного файла</param>
 62        /// <returns>возвращает ссылку на файл</returns>
 63        public async Task<string> CreateFeedForYandex(string filename)
 064        {
 065            XDocument xdoc = new XDocument();
 066            XElement root = new XElement("yml_catalog");
 067            root.Add(new XAttribute("date", DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm")));
 068            XElement shop = new XElement("shop");
 069            shop.Add(new XElement("name", "ЗАПОКУПКИ.РФ"));
 070            shop.Add(new XElement("company", "ООО ВТБ БИЗНЕС КОННЕКТ"));
 071            shop.Add(new XElement("url", "http://запокупки.рф"));
 072            shop.Add(new XElement("platform", "na"));
 073            shop.Add(new XElement("version", "1.0"));
 074            XElement currencies = new XElement("currencies");
 075            foreach (var item in await _dirService.GetCurrencies())
 076            {
 077                XElement currency = new XElement("currency", "");
 078                currency.Add(new XAttribute("rate", item.Rate));
 079                currency.Add(new XAttribute("id", item.STRCODE));
 080                currencies.Add(currency);
 081            }
 082            shop.Add(currencies);
 083            XElement categories = new XElement("categories");
 084            foreach (var item in await _catService.GetCategories(0, int.MaxValue, null))
 085            {
 086                if (item.ExcludeFromYandexFeed)
 087                    continue;
 088                XElement category = new XElement("category", NormalizeStringValues(item.Name));
 089                category.Add(new XAttribute("id", item.Id));
 090                if (item.Parent != null) category.Add(new XAttribute("parentId", item.Parent.Id));
 091                categories.Add(category);
 092            }
 093            shop.Add(categories);
 094            shop.Add(new XElement("enable_auto_discounts", "true"));
 095            XElement delivery = new XElement("delivery-options");
 096            XElement option = new XElement("option");
 097            option.Add(new XAttribute("days", 1));
 098            option.Add(new XAttribute("cost", 0));
 099            delivery.Add(option);
 0100            shop.Add(delivery);
 0101            XElement offers = new XElement("offers");
 0102            foreach (var item in _showCaseWorker.GetShowcaseGoods(null, -1, true, 0, int.MaxValue, null, "name", null, o
 0103            {
 0104                if (item.Category.ExcludeFromYandexFeed)
 0105                    continue;
 0106                XElement offer = new XElement("offer");
 0107                offer.Add(new XAttribute("id", item.Id));
 0108                offer.Add(new XElement("name", NormalizeStringValues(item.Name)));
 0109                offer.Add(new XElement("description", NormalizeStringValues(item.Name)));
 0110                if (item.Brand?.Name != null)
 0111                    offer.Add(new XElement("vendor", NormalizeStringValues(item.Brand.Name)));
 0112                if (item.VendorCode != null)
 0113                    offer.Add(new XElement("vendorCode", NormalizeStringValues(item.VendorCode)));
 0114                offer.Add(new XElement("url", $"{_commonSettings.BaseFrontUrl}/showcase/catalog?product={item.Id}&depart
 0115                offer.Add(new XElement("price", item.Price));
 0116                if (item.OldPrice != null)
 0117                    offer.Add(new XElement("oldprice", item.OldPrice));
 0118                offer.Add(new XElement("currencyId", currencies.Elements().FirstOrDefault().Attribute("id").Value));
 0119                offer.Add(new XElement("categoryId", item.Category.Id));
 0120                foreach (var photo in item.Photos)
 0121                    offer.Add(new XElement("picture", photo.FullSizeUrl));
 0122                offer.Add(new XElement("sales_notes", "Необходима предоплата."));
 0123                if (item.Country?.Name != null)
 0124                    offer.Add(new XElement("country_of_origin", NormalizeStringValues(item.Country.Name)));
 0125                if (item.MainBarcode?.Code != null)
 0126                    offer.Add(new XElement("barcode", item.MainBarcode?.Code));
 0127                foreach (var barcode in item.Barcodes)
 0128                    offer.Add(new XElement("barcode", barcode.Code));
 0129                if (item.GroupPackNesting != 0)
 0130                {
 0131                    XElement param = new XElement("param", item.GroupPackNesting);
 0132                    param.Add(new XAttribute("name", "Вложенность в групповую упаковку"));
 0133                    offer.Add(param);
 0134                }
 0135                if (item.GroupPackWidth != 0)
 0136                {
 0137                    XElement param = new XElement("param", item.GroupPackWidth);
 0138                    param.Add(new XAttribute("name", "Ширина групповой упаковки"));
 0139                    param.Add(new XAttribute("unit", "см"));
 0140                    offer.Add(param);
 0141                }
 0142                if (item.GroupPackHeight != 0)
 0143                {
 0144                    XElement param = new XElement("param", item.GroupPackHeight);
 0145                    param.Add(new XAttribute("name", "Высота групповой упаковки"));
 0146                    param.Add(new XAttribute("unit", "см"));
 0147                    offer.Add(param);
 0148                }
 0149                if (item.GroupPackThickness != 0)
 0150                {
 0151                    XElement param = new XElement("param", item.GroupPackThickness);
 0152                    param.Add(new XAttribute("name", "Толщина групповой упаковки"));
 0153                    param.Add(new XAttribute("unit", "см"));
 0154                    offer.Add(param);
 0155                }
 0156                if (item.PalletNesting != 0)
 0157                {
 0158                    XElement param = new XElement("param", item.PalletNesting);
 0159                    param.Add(new XAttribute("name", "Вложенность в поддон"));
 0160                    offer.Add(param);
 0161                }
 0162                if (item.ExpirationDays != 0)
 0163                    offer.Add(new XElement("expiry", NormalizeExpireValues(item.ExpirationDays)));
 0164                if (item.Weight != 0)
 0165                    offer.Add(new XElement("weight", item.Weight));
 0166                if (item.Thickness != 0 && item.Width != 0 && item.Height != 0)
 0167                    offer.Add(new XElement("dimensions", item.Thickness + "/" + item.Width + "/" + item.Height));
 0168                offers.Add(offer);
 0169            }
 0170            shop.Add(offers);
 0171            root.Add(shop);
 0172            xdoc.Add(root);
 0173            xdoc.Save(Path.Combine(_uploadSettings.DownloadsSavePath, filename));
 0174            return _uploadSettings.DownloadUrl + filename;
 0175        }
 176
 177        /// <summary>
 178        /// Генерирует фид для гугла
 179        /// </summary>
 180        /// <param name="filename">название выходного файла</param>
 181        /// <returns>возвращает массив байт, представляющего файл</returns>
 182        public async Task<byte[]> CreateFeedForGoogle(string filename)
 0183        {
 0184            var rows = new List<string>();
 0185            Dictionary<int, string> categoriesPath = new Dictionary<int, string>();
 0186            var currency = (await _dirService.GetCurrencies()).FirstOrDefault();
 0187            rows.Add("id\ttitle\tgtin\tdescription\tgoogle_product_category\tproduct_type\tlink\timage_link\tbrand\tMPN\
 0188            foreach (var item in _showCaseWorker.GetShowcaseGoods(null, -1, true, 0, int.MaxValue, null, "name", null, o
 0189            {
 0190                if (item.Category.ExcludeFromGoogleFeed)
 0191                    continue;
 0192                if (!categoriesPath.ContainsKey((int)item.Category.Id))
 0193                    categoriesPath.Add((int)item.Category.Id, await _catService.GetPathToCategoryForFeed(item.Category.I
 0194                rows.Add($"{item.Id}\t\"{item.Name}\"\t{item.MainBarcode?.Code}\t\"{item.Name}\"\t{item.Category.GoogleP
 0195                    $"{item.Brand.Name}\t{item.VendorCode}\tin_stock\tnew\t{item.Price.ToString(CultureInfo.GetCultureIn
 0196            }
 0197            byte[] dataAsBytes = rows.SelectMany(s =>
 0198                System.Text.Encoding.UTF8.GetBytes(s + Environment.NewLine)).ToArray();
 199
 0200            using (Stream stream = new MemoryStream(dataAsBytes))
 0201            {
 0202                using FileStream compressedFileStream = File.Create(Path.Combine(_uploadSettings.DownloadsSavePath, file
 0203                using GZipStream compressionStream = new GZipStream(compressedFileStream, CompressionMode.Compress);
 0204                await stream.CopyToAsync(compressionStream);
 0205            }
 0206           return await File.ReadAllBytesAsync(Path.Combine(_uploadSettings.DownloadsSavePath, filename) + ".gz");
 0207        }
 208
 209        /// <summary>
 210        /// нормализует значение согласно правилам яндекса
 211        /// </summary>
 212        /// <param name="value">значение</param>
 213        /// <returns>нормализованное значение</returns>
 214        private string NormalizeStringValues(string value)
 0215        {
 0216            value = value.Replace("\"", "&quot;")
 0217                .Replace("&", "&amp;")
 0218                .Replace(">", "&gt;")
 0219                .Replace("<", "&lt;")
 0220                .Replace("'", "&apos;");
 0221            return value;
 0222        }
 223
 224        /// <summary>
 225        /// нормализует срок годности (кол-во дней) согласно правилам яндекса
 226        /// </summary>
 227        /// <param name="value">кол-во дней</param>
 228        /// <returns>нормализованное значение в формате iso8601</returns>
 229        private string NormalizeExpireValues(int value)
 0230        {
 231            //срок годности должен быть  формате iso8601. Например, P1Y2M10DT2H30M - 1год 2 мес 10 дней 2 часа 30 мин
 0232            string expire = "P";
 0233            var years = (int)(value / 365.2425);
 0234            var months = (int)((value - years * 365.2425) / 30);
 0235            var days = (int)(value - years * 365.2425 - months * 30);
 0236            expire += years + "Y" + months + "M" + days + "DT0H00M";
 0237            return expire;
 0238        }
 239    }
 240}