/// <summary> /// Удаляет дубликаты из фулкаталога по sku /// </summary> public static void DeleteDuplicateItems() { Program.Logger.Info("Delete duplicate for FullCatalog"); var fullCatalog = LoadFullCatalogFromFtp(); var itemsCount = fullCatalog.records.Count; var newFullCatalog = new FullCatalogRoot(); newFullCatalog.update_time = DateTime.Now; foreach (var record in fullCatalog.records) { var rec = newFullCatalog.records.Find(x => x.sku == record.sku); if (rec == null) { newFullCatalog.records.Add(record); } else { Program.Logger.Debug("Duplicate item. Sku: " + rec.sku); } } var countDeleteItems = itemsCount - newFullCatalog.records.Count; Program.Logger.Info("Items deleted: " + countDeleteItems); Program.Logger.Info("Delete duplicate completed. Items count: " + newFullCatalog.records.Count); if (countDeleteItems > 0) { SaveFullCatalogToFtp(newFullCatalog); } }
private void LoadAllItems(AllStockRoot allstock, FullCatalogRoot fullCatalog, VkGoodsRoot oldVkGoodsRoot) { var vkGoods = new VkGoodsRoot(); //var i = 0; //const int lim = 10; foreach (var artikul in allstock.sneakers) { try { var vkItem = PostItemToVk(fullCatalog, artikul, oldVkGoodsRoot); if (vkItem == null) { continue; } vkGoods.Records.Add(vkItem); //i++; //if (i != lim) continue; // //i = 0; vkGoods.UpdateTime = DateTime.Now; SaveVkGoodsRootToYd(vkGoods); } catch (Exception e) { _logger.Error(e, " Ошибка при добавлении товара ВК"); _logger.Error(e.Message); _logger.Error(e.StackTrace); } } }
private static AvitoAds createAds(RootParsingObject discont, FullCatalogRoot fullCatalog, DateTime startTime) { var Ads = new AvitoAds(); Ads.StartTime = startTime; var menWomenOnlyListings = discont.listings.FindAll(x => x.category != "kids"); //var listingsMoreThan2SizesAvailable = menWomenOnlyListings.FindAll(x => x.sizes.Count > 2); var listings = menWomenOnlyListings; listings = listings.OrderBy(x => x.sku).ToList(); var listingCount = listings.Count; for (int i = 0; i < listingCount; i++) { var sneaker = listings[i]; var fcSneaker = fullCatalog.records.Find(x => x.sku == sneaker.sku); AvitoAd Ad = GetAdFromSneaker(sneaker, fcSneaker, Ads.StartTime, Ads.AdList.Count + 1, listingCount); if (Ad != null) { Ads.AdList.Add(Ad); } } _logger.Info("Кол-во листингов: " + listingCount); _logger.Info("Кол-во объявлений: " + Ads.AdList.Count); return(Ads); }
public void Run() { var discontSamara = DiscontSamaraParser.LoadLocalFileJson(); fullCatalog = FullCatalog2.LoadLocalFile(); var shopifyRecords = CreateShopifyRecords(discontSamara); }
private static AvitoAds createAds(Model.AllStock.AllStockRoot allstock, FullCatalogRoot fullCatalog, DateTime startTime) { var Ads = new AvitoAds(); Ads.StartTime = startTime; for (int i = 0; i < allstock.sneakers.Count; i++) { var sneaker = allstock.sneakers[i]; var fcSneaker = fullCatalog.records.Find(x => x.sku == sneaker.sku); AvitoAd Ad = GetAdFromSneaker(sneaker, fcSneaker, Ads.StartTime, i + 1, allstock.sneakers.Count); //тут есть ошибка. У аллстока может быть больше позиций чем для авито, так как некоторые ад могут нул вернуть и не добавиться. По правильному нужно сначала сделать первый прогон, заполнить все объявления и только потом добавлять дату постинга (зная точно кол-во объявлений) if (Ad != null) { Ads.AdList.Add(Ad); } } return(Ads); }
private static BonanzaRoot CreateBonanzaRecords(AllStockRoot allstock, FullCatalogRoot fullCatalog) { ShopCatalogRoot shopCatalog = ShopCatalogController.LoadShopCatalogFromFtp(); BonanzaRoot bonanza = new BonanzaRoot(); foreach (var asSneaker in allstock.sneakers) { foreach (var asSize in asSneaker.sizes) { Model.BonanzaModel.BonanzaRecord bRecord = GetBonanzaRecord(asSize, asSneaker, fullCatalog, shopCatalog); if (bRecord != null) { bonanza.Records.Add(bRecord); } } } return(bonanza); }
private static HotOffersRoot GetHotOffers(AllStockRoot allStock) { /* Как определить лучшее предолжение? Горячий пирожок? Как найти самые большие скидки в нашей базе данных? * Я думаю что для нас выгодными будут предложения, которые с учетом доставки и ват будут на 30% или даже дешевле чем ритейл цена. * Что такое горячий пирожок? Это артикул, у которого есть несколько размеров, удовлетворяющих этому условию * Что мы заносим в пирожок? * - артикул, * - цену себестоимости, * - размеры которые попадают под это условия. * - на каждый размер: * - ссылка на магазин, где можно купить по этой цене данный размер * - ссылки на изображения с нашего сервака (несколько изображений) * - цена этого размера * - максимальную цену среди всех размеров (какие-то размеры дешевле, какие-то дороже * чтобы определить ритейл цену, берем среднюю цену без учета скидки всех размеров всех офферов */ double minMargin = MIN_NEED_MARGIN; //минимальная маржа в долларах с пирожка. То есть минимальная стоимость разницы между ритейл ценой и себест. с доставкой и вычетом ват double minSalePercent = 0.3; //минимальная скидка в процентах var myHotOffers = new HotOffersRoot(); FullCatalogRoot fullCatalog = FullCatalog2.LoadFullCatalogFromFtp(); foreach (var sneaker in allStock.sneakers) { var hOffer = GetHotOfferFromAllStockSneaker(sneaker, fullCatalog, minMargin, minSalePercent); if (hOffer != null) { myHotOffers.offers.Add(hOffer); } } if (myHotOffers.offers.Count > 0) { return(myHotOffers); } else { return(null); } }
public static void PostNewTodayItems(FullCatalogRoot fullCatalog = null) { if (fullCatalog == null) { fullCatalog = FullCatalog2.LoadFullCatalogFromFtp(); } var allstock = AllStockExporter2.LoadLocalFile(); var items = fullCatalog.records.FindAll(x => DateTime.Now - x.add_time < new TimeSpan(24, 0, 0)); var chatId = "-1001116441282"; //"@sneaker_icon_new_today" var message = "New items today: " + items.Count; _logger.Info(message); Helper.TelegramPost(message, chatId); System.Threading.Thread.Sleep(15000); var count = items.Count; for (int i = 0; i < count; i++) { var item = items[i]; var ret = "\n"; var m = "New model in our store:\n"; m += item.title + ret; m += "SKU: " + item.sku + ret; m += "Category: " + item.category + "\n"; m += "Add time: " + item.add_time + ret; //m += "Link: " + item.link + "\n\n"; foreach (var image in item.images) { m += image + "\n"; } _logger.Info("NewToday post sku:" + item.sku); Helper.TelegramPost(m, chatId); System.Threading.Thread.Sleep(15000); } }
public static void SaveFullCatalogToFtp(FullCatalogRoot fullCatalogJson) { Program.Logger.Info("Upload FullCatalog To Ftp..."); var appSettings = System.Configuration.ConfigurationManager.AppSettings; string ftpHost = appSettings["ftpHostSneakerIcon"]; string ftpUser = appSettings["ftpUserSneakerIcon"]; string ftpPass = appSettings["ftpPassSneakerIcon"]; //string path = appSettings["fullCatalogFtpPath"]; var folder = "FullCatalog"; var filename = "FullCatalog.json"; var localFileName = Config.GetConfig().DirectoryPathParsing + folder + @"\" + filename; var textJson = JsonConvert.SerializeObject(fullCatalogJson); System.IO.File.WriteAllText(localFileName, textJson); var ftpFileName = folder + "/" + filename; Helper.LoadFileToFtp(localFileName, ftpFileName, ftpHost, ftpUser, ftpPass); Program.Logger.Info("Uploaded FullCatalog Complete"); }
private static int CountItemsWithoutImages(FullCatalogRoot fullCatalog) { var itemsWithoutImage = fullCatalog.records.FindAll(x => x.images.Count == 0); return(itemsWithoutImage.Count); }
private static HotOffer GetHotOfferFromAllStockSneaker(AllStockSneaker sneaker, FullCatalogRoot fullCatalog, double minMargin, double minSalePercent) { //определяем среднюю ритейл цену этого кросса в долларах var averageSneakerRegularPrice = GetAverageRegularPrice(sneaker); //смотрим, есть ли офферы, которые удовлетворяютм минимальным требованиям var sizes = GetHotOfferSizes(sneaker, averageSneakerRegularPrice, minMargin, minSalePercent); //если офферов больше нуля (ну то есть такие офферы, которые удовлетворяют условиям), то добавляем этот горячий пирожок в список горячих пирожков if (sizes.Count > 0) { var hOffer = new HotOffer(); hOffer.sizes = sizes; hOffer.sku = sneaker.sku; hOffer.brand = sneaker.brand; hOffer.title = sneaker.title; hOffer.category = sneaker.category; var fcRecord = fullCatalog.records.Find(x => x.sku == sneaker.sku); if (fcRecord != null) { hOffer.images = fcRecord.images; } hOffer.our_price = hOffer.GetOurPrice(); hOffer.regular_price = averageSneakerRegularPrice; hOffer.add_time = DateTime.Now; return(hOffer); } else { return(null); } }
private static string GetBonanzaRecordDescription(AllStockSize asSize, AllStockSneaker asSneaker, FullCatalogRoot fullCatalog) { var boothUrl = System.Configuration.ConfigurationManager.AppSettings["bonanzaBoothUrl"]; var title = asSneaker.title; var sku = asSneaker.sku; var size = SizeChart.GetSizeStatic(new Size(asSneaker.brand, asSneaker.category, asSize.us, null, null, null, null)); if (size == null) { _logger.Warn("Ошибка в размере. sku: " + asSneaker.sku); return(null); } var sizeString = size.GetSizeStringUsEuUkCm(); string description = "<h3 style=\"text-align: center;\"><strong>" + title.ToUpper() + "</strong></h3>" + "<h3 style=\"text-align: center;\"><strong>" + "STYLE: " + sku + "</strong></h3>" + "<h3 style=\"text-align: center;\"><strong>" + "SIZE: " + sizeString + "</strong></h3>" + "<h3 style=\"text-align: center;\"><strong>" + "100% AUTHENTIC" + "</strong></h3>" + "<h3 style=\"text-align: center;\"><strong>" + "WORLDWIDE SHIPPING FOR 5-10 DAYS IN DOUBLE BOX WITH TRACKING NUMBER.<br>" + "</strong></h3>" + "<h3 style=\"text-align: center;\"><strong>" + "SHIP IN 2 BUSINESS DAY." + "</strong></h3>"; //description += "<h3 style=\"text-align: center;\"><strong>All sizes of this model available in stock</strong></h3>"; //if (sizeList != null) //{ // if (sizeList.Count > 0) // { // foreach (var size in sizeList) // { // //725076-301+6.5US // description += "<h4 style=\"text-align: center;\"><strong><a href=\"" + boothUrl + "?utf8=%E2%9C%93&item_sort_options%5Bfilter_string%5D=" + sku + "+" + size + "US&item_sort_options%5Bfilter_category_id%5D=&item_sort_options%5Bcustom_category_id%5D=&commit=Go\" rel=\"nofollow\" target=\"_blank\">Size " + size + " US</a></strong></h4>"; // } // } //} description += "<h3 style=\"text-align: center;\"><strong>" + "Other sizes of this model available in out stock: " + "<a href=\"" + boothUrl + "?utf8=%E2%9C%93&item_sort_options%5Bfilter_string%5D=" + sku + "&item_sort_options%5Bfilter_category_id%5D=&item_sort_options%5Bcustom_category_id%5D=&commit=Go\" rel=\"nofollow\" target=\"_blank\">Link</a>" + "</strong></h3>"; description += "<h3 style=\"text-align: center;\"><strong>" + "Please feel free to ask any questions and see <a href=\"" + boothUrl + "\" rel=\"nofollow\" target=\"_blank\">all our listings</a> for more great deals." + "</strong></h3>"; //throw new NotImplementedException(); return(description); }
public VkExporter() { Allstock = AllStockExporter2.LoadLocalFile(); FullCatalog = FullCatalog2.LoadLocalFile(); Posting = new VkPosting(); }
private static Model.BonanzaModel.BonanzaRecord GetBonanzaRecord(AllStockSize asSize, AllStockSneaker asSneaker, FullCatalogRoot fullCatalog, ShopCatalogRoot shopCatalog) { var fcSneaker = fullCatalog.records.Find(x => x.sku == asSneaker.sku); if (fcSneaker == null) { _logger.Warn("Артикул не найден в фулкаталоге. sku:" + asSneaker.sku); return(null); } var bRecord = new Model.BonanzaModel.BonanzaRecord(); //standart data bRecord.quantity = 5; bRecord.condition = "New with box"; bRecord.force_update = "true"; bRecord.brand = fcSneaker.brand; //shipping bRecord.shipping_price = 29; bRecord.shipping_type = "flat"; bRecord.shipping_carrier = "usps"; bRecord.shipping_service = "EconomyShipping"; bRecord.shipping_package = "normal"; //bRecord.worldwide_shipping_type = "flat"; //bRecord.worldwide_shipping_price = 29; bRecord.id = asSize.sku2; bRecord.description = GetBonanzaRecordDescription(asSize, asSneaker, fullCatalog); if (bRecord.description == null) { _logger.Warn("Пустое описание. sku2:" + bRecord.id); return(null); } bRecord.category = GetBonanzaCategory(asSneaker.category, fcSneaker.sex); bRecord.width = GetBonanzaWidth(asSneaker.category); bRecord.title = GetTitle(asSneaker.brand, asSize.us, asSneaker.sku, asSneaker.title); //price var offer = GetFirstActiveOffer(asSize, shopCatalog); //var offer = GetNonRussianOffer(asSize); //отфильтруем русские магазы if (offer == null) { return(null); } bRecord.price = GetPrice(offer); //double priceWithMargin = offer.price_usd_with_delivery_to_usa_and_minus_vat + MARGIN_USD; //double priceWithFeeMinusBonanzaDelivery = (priceWithMargin * 1.18) - 29; //priceWithFeeMinusBonanzaDelivery = Math.Round(priceWithFeeMinusBonanzaDelivery, 2); //bRecord.price = priceWithFeeMinusBonanzaDelivery.ToString("F", System.Globalization.CultureInfo.CreateSpecificCulture("en-US")); //images if (fcSneaker.images.Count == 0) { _logger.Warn("Нет изображений. sku2:" + bRecord.id); return(null); } bRecord.image1 = fcSneaker.images[0]; if (fcSneaker.images.Count > 1) { bRecord.image2 = fcSneaker.images[1]; } if (fcSneaker.images.Count > 2) { bRecord.image3 = fcSneaker.images[2]; } if (fcSneaker.images.Count > 3) { bRecord.image4 = fcSneaker.images[3]; } bRecord.size = asSize.us; bRecord.traits = "[[US Size:" + asSize.us + "]] "; bRecord.upc = asSize.upc; bRecord.MPN = fcSneaker.sku; //это вроде не работает bRecord.traits += "[[MPN:" + fcSneaker.sku + "]] "; return(bRecord); }
private static Model.BonanzaModel.BonanzaRecord GetBonanzaRecord_MultiListing(AllStockSneaker asSneaker, FullCatalogRoot fullCatalog) { //валидации //sizes if (asSneaker.sizes.Count == 0) { return(null); } //description var description = GetBonanzaRecordDescription_MultiListing(asSneaker, fullCatalog); if (description == null) { _logger.Warn("Пустое описание. sku:" + asSneaker.sku); return(null); } //инициализация var fcSneaker = fullCatalog.records.Find(x => x.sku == asSneaker.sku); var bRecord = new Model.BonanzaModel.BonanzaRecord(); //standart data bRecord.quantity = 5; //нужно доработать, кол-во равно 5*кол-во размеров bRecord.condition = "New with box"; bRecord.force_update = "true"; bRecord.brand = fcSneaker.brand; bRecord.MPN = fcSneaker.sku; //это вроде не работает bRecord.traits = "[[MPN:" + fcSneaker.sku + "]] "; //color (русские цвета добавляются, пока убрал) //if (!string.IsNullOrWhiteSpace(fcSneaker.color)) // bRecord.traits += "[[Color:" + fcSneaker.color + "]] "; //shipping bRecord.shipping_price = 29; bRecord.shipping_type = "flat"; bRecord.shipping_carrier = "usps"; bRecord.shipping_service = "EconomyShipping"; bRecord.shipping_package = "normal"; //bRecord.worldwide_shipping_type = "flat"; //bRecord.worldwide_shipping_price = 29; //main bRecord.id = fcSneaker.sku; bRecord.category = GetBonanzaCategory(asSneaker.category, fcSneaker.sex); bRecord.width = GetBonanzaWidth(asSneaker.category); bRecord.title = GetTitle_MultiListing(asSneaker.brand, asSneaker.sku, asSneaker.title); bRecord.description = description; //images bool hasImages = GetImages(fcSneaker, bRecord); if (!hasImages) { return(null); } //делаем вариации //все предложения из русских магазов уже удалены bRecord.price = String.Empty; foreach (var size in asSneaker.sizes) { if (size.offers.Count > 0) { var price = GetPrice(size.offers[0]); bRecord.traits += "[[US Size:" + size.us + "][quantity:" + 5 + "][price:" + price + "]]"; if (bRecord.price == String.Empty) { bRecord.price = price; } if (Double.Parse(bRecord.price.Replace(".", ",")) > Double.Parse(price.Replace(".", ","))) { bRecord.price = price; } } } if (bRecord.price == String.Empty) { _logger.Warn("Цена бонанза рекорд пустая. Sku: " + asSneaker.sku); var offer = asSneaker.sizes.Find(x => x.offers.Count > 0); return(null); } //price //var offer = GetNonRussianOffer_MultiListing(asSneaker); //отфильтруем русские магазы //if (offer == null) // return null; //bRecord.price = GetPrice(offer); //bRecord.size = asSize.us; //bRecord.traits = "[[US Size:" + asSize.us + "]] "; //bRecord.upc = asSize.upc; return(bRecord); }
private static BonanzaRoot CreateBonanzaRecords_MultiListing(AllStockRoot allstock, FullCatalogRoot fullCatalog) { BonanzaRoot bonanza = new BonanzaRoot(); foreach (var asSneaker in allstock.sneakers) { Model.BonanzaModel.BonanzaRecord bRecord = GetBonanzaRecord_MultiListing(asSneaker, fullCatalog); if (bRecord != null) { bonanza.Records.Add(bRecord); } } return(bonanza); }
private VkGoodsItem PostItemToVk(FullCatalogRoot fullCatalog, AllStockSneaker artikul, VkGoodsRoot oldVkGoodsRoot) { try { var task = new VkTask(); var fcSneaker = fullCatalog.records.Find(x => x.sku == artikul.sku); if (fcSneaker.images == null) { return(null); } if (fcSneaker.images.Count == 0) { return(null); } if (string.IsNullOrWhiteSpace(artikul.category)) { return(null); } if (artikul.sizes == null) { return(null); } if (artikul.sizes.Count == 0) { return(null); } task.Header = artikul.title.ToUpper() + " " + fcSneaker.sku; var sizeBlock = ""; foreach (var size in artikul.sizes) { var scSize = SizeChart.GetSizeStatic(new Size(artikul.brand, artikul.category, size.us, null, null, null, null)); var priceSize = size.offers[0].price_usd_with_delivery_to_usa_and_minus_vat; var priceSizeRub = (int)CurrencyRate.ConvertCurrency("USD", "RUB", priceSize) + Margin; if (scSize != null) { sizeBlock += scSize.GetAllSizeString() + ". Цена:" + priceSizeRub + Environment.NewLine; } } var start = fcSneaker.type.ToLower() + " " + artikul.title.ToUpper() + Environment.NewLine; task.Description = start.Substring(0, 1).ToUpper() + start.Remove(0, 1); task.Description += "Артикул: " + artikul.sku + Environment.NewLine; task.Description += "В оригинальной упаковке Nike." + Environment.NewLine; task.Description += "БЕСПЛАТНАЯ доставка по Москве" + Environment.NewLine; task.Description += "Доставка по России 3-5 дней компанией СДЭК." + Environment.NewLine; task.Description += "Стоимость доставки по РФ - 300 рублей." + Environment.NewLine; task.Description += "Доставка в регионы только по 100% предоплате, наложенным платежом не отправляем" + Environment.NewLine; task.Description += "Работаем с 2012 года, более 4000 моделей в ассортименте. Можете перейти в группу Вконтакте, чтобы убедиться в том, что мы продаем только оригинальную обувь. Никаких подделок и реплик!" + Environment.NewLine; task.Description += "В нашей группе Вконтакте более 70 реальных отзывов от клиентов!" + Environment.NewLine; task.Description += "Размеры в наличии:" + Environment.NewLine; task.Description += sizeBlock; task.Description += "Уточняйте наличие размеров." + Environment.NewLine; task.Description += "Если размера нет в наличии, можем его привезти под заказ. Срок поставки товара под заказ: 7-10 дней." + Environment.NewLine; task.Description += "Sneaker Icon - это большой выбор оригинальной брендовой обуви Nike и Jordan. Кроссовки, кеды, бутсы, футзалки, шиповки, сланцы, ботинки и другие типы обуви" + Environment.NewLine; var priceUsd = artikul.GetMinPrice(); var priceRub = (int)CurrencyRate.ConvertCurrency("USD", "RUB", priceUsd) + Margin; task.Price = priceRub; task.ImageList = fcSneaker.images; task.CollectionList = GetCollectionsName(fcSneaker.sku); //todo пока так. Нормально удаление сделаю, как попросят. task.IsDeleted = false; task.SKU = fcSneaker.sku; var oldItem = oldVkGoodsRoot.Records.Where(x => x.SKU != null).FirstOrDefault(x => x.SKU.Equals(fcSneaker.sku)); var result = Posting.AddOrEditVkGoods(task, oldItem); if (result != null) { //todo подумать над информативностью. Тут не только именно отправленные данные. _logger.Debug($"В товары ВК отправлен SKU {fcSneaker.sku} ID {result.VkId}"); } return(result); } catch (Exception e) { _logger.Error(e, "Ошибка при добавлении товара в ВК"); _logger.Error(e.StackTrace); return(null); } }
private static int CountItemsWithoutCategory(FullCatalogRoot fullCatalogJson) { var itemsWithoutCategory = fullCatalogJson.records.FindAll(x => string.IsNullOrWhiteSpace(x.category)); return(itemsWithoutCategory.Count); }