using BBWY.Common.Http; using BBWY.Common.Models; using BBWY.Server.Model; using BBWY.Server.Model.Dto; using Microsoft.Extensions.Options; using NLog; using System.Threading.Tasks; using Yitter.IdGenerator; using System.Linq; using BBWY.Server.Model.Db; using System; using System.Collections.Generic; using Newtonsoft.Json; using FreeSql; using System.Threading; using System.Collections.Concurrent; namespace BBWY.Server.Business.Sync { public class ProductSyncBusiness : BaseSyncBusiness, IDenpendency { private ProductBusiness productBusiness; private ConcurrentDictionary categoryCache; public ProductSyncBusiness(RestApiService restApiService, IOptions options, NLogManager nLogManager, IFreeSql fsql, IIdGenerator idGenerator, TaskSchedulerManager taskSchedulerManager, VenderBusiness venderBusiness, ProductBusiness productBusiness, YunDingBusiness yunDingBusiness) : base(restApiService, options, nLogManager, fsql, idGenerator, taskSchedulerManager, venderBusiness, yunDingBusiness) { this.productBusiness = productBusiness; this.categoryCache = new ConcurrentDictionary(); } private string GetMainSkuId(IList skuList) { var maxPrice = skuList.Max(s => s.Price); var sku = skuList.FirstOrDefault(s => s.Price == maxPrice && s.State == 1); return sku?.Id ?? string.Empty; } private bool CheckMainSkuState(IList skuList, string mainSkuId) { if (string.IsNullOrEmpty(mainSkuId)) return false; var mainSku = skuList.FirstOrDefault(s => s.Id == mainSkuId); if (mainSku == null || mainSku.State != 1) return false; return true; } private void SyncProduct(ShopResponse shop, ProductListResponse productList) { var currentProductId = ""; try { var shopId = long.Parse(shop.ShopId); List insertProductList = new List(); List> updateProductList = new List>(); List inserSkuList = new List(); List> updateProductSkuList = new List>(); var productIds = productList.Items.Select(p => p.Id); var dbProducts = fsql.Select().Where(p => p.ShopId == shopId && productIds.Contains(p.Id)).ToList(); var dbProductSkus = fsql.Select().Where(s => s.ShopId == shopId && productIds.Contains(s.ProductId)).ToList(); foreach (var product in productList.Items) { Thread.Sleep(200); currentProductId = product.Id; #region 检查sku var skuList = productBusiness.GetProductSkuList(new SearchProductSkuRequest() { AppKey = shop.AppKey, AppSecret = shop.AppSecret, AppToken = shop.AppToken, Platform = shop.PlatformId, Spu = product.Id, IsContainSource = true }); if (skuList == null || skuList.Count() == 0) continue; //排查已删除的sku var currentDbSkus = dbProductSkus.Where(dbsku => dbsku.ProductId == product.Id).ToList(); var deletedSkuList = currentDbSkus.Where(dbsku => skuList.Count(s => s.Id == dbsku.Id) == 0).ToList(); if (deletedSkuList.Count() > 0) { foreach (var deletedSku in deletedSkuList) { var update = fsql.Update(deletedSku.Id).Set(s => s.State, 4); updateProductSkuList.Add(update); } } foreach (var sku in skuList) { var categoryId = sku.Source.Value("categoryId"); var dbSku = dbProductSkus.FirstOrDefault(s => s.Id == sku.Id); if (dbSku == null) { inserSkuList.Add(new ProductSku() { Id = sku.Id, CreateTime = sku.CreateTime ?? DateTime.Now, Logo = sku.Logo, Platform = shop.PlatformId, Price = sku.Price, ProductId = sku.ProductId, ShopId = shopId, Title = sku.Title, State = sku.State, CategoryId = categoryId }); } else if (dbSku.State != sku.State || dbSku.Price != sku.Price || dbSku.CategoryId != categoryId) { var update = fsql.Update(dbSku.Id) .Set(s => s.State, sku.State) .Set(s => s.Price, sku.Price) .Set(s => s.CategoryId, categoryId); updateProductSkuList.Add(update); } } #endregion #region 检查产品 var dbProduct = dbProducts.FirstOrDefault(dbp => dbp.Id == product.Id); if (dbProduct == null) { insertProductList.Add(new Product() { Id = product.Id, CreateTime = product.CreateTime ?? DateTime.Now, Platform = shop.PlatformId, ProductItemNum = product.ProductItemNum, ShopId = shopId, Title = product.Title, State = product.State, MainSkuId = GetMainSkuId(skuList) }); } else if (dbProduct.State != product.State || !CheckMainSkuState(skuList, dbProduct.MainSkuId)) { string newMainSkuId = string.Empty; if (!CheckMainSkuState(skuList, dbProduct.MainSkuId)) newMainSkuId = GetMainSkuId(skuList); var update = fsql.Update(product.Id).SetIf(dbProduct.State != product.State, p => p.State, product.State) .SetIf(!string.IsNullOrEmpty(newMainSkuId), p => p.MainSkuId, newMainSkuId); updateProductList.Add(update); } #endregion } fsql.Transaction(() => { fsql.Insert(insertProductList).ExecuteAffrows(); fsql.Insert(inserSkuList).ExecuteAffrows(); if (updateProductList.Count > 0) foreach (var update in updateProductList) update.ExecuteAffrows(); if (updateProductSkuList.Count > 0) foreach (var update in updateProductSkuList) update.ExecuteAffrows(); }); } catch (Exception ex) { throw new Exception(currentProductId, ex); } } private void SyncProduct(ShopResponse shop, bool IsSyncAllProduct = false) { try { var shopId = long.Parse(shop.ShopId); var dbProductList = fsql.Select().Where(p => p.ShopId == shopId).ToList(); var dbProductSkuList = fsql.Select().Where(p => p.ShopId == shopId).ToList(); List productList = new List(); List productSkuList = new List(); List insertProductList = new List(); List insertProductSkuList = new List(); List> updateProductList = new List>(); List> updateProductSkuList = new List>(); var request = new SearchProductRequest() { PageSize = 50, PageIndex = 1, AppKey = shop.AppKey, AppSecret = shop.AppSecret, AppToken = shop.AppToken, Platform = shop.PlatformId }; while (true) { var currentProductList = productBusiness.GetProductList(request); if (currentProductList == null || currentProductList.Count == 0) break; productList.AddRange(currentProductList.Items); foreach (var product in currentProductList.Items) { var currentSkuList = productBusiness.GetProductSkuList(new SearchProductSkuRequest() { AppKey = shop.AppKey, AppSecret = shop.AppSecret, AppToken = shop.AppToken, Platform = shop.PlatformId, Spu = product.Id, IsContainSource = true }); if (currentSkuList == null || currentSkuList.Count() == 0) continue; productSkuList.AddRange(currentSkuList); } if (currentProductList.Items.Count < 50 || !IsSyncAllProduct) break; request.PageIndex++; Thread.Sleep(1000); } #region 找出新增的产品 var newProductList = productList.Where(p => !dbProductList.Any(dp => dp.Id == p.Id)).ToList(); if (newProductList.Count() > 0) { insertProductList.AddRange(newProductList.Select(p => new Product() { Id = p.Id, CreateTime = p.CreateTime, Title = p.Title, State = p.State, ShopId = shopId, Platform = shop.PlatformId, ProductItemNum = p.ProductItemNum, MainSkuId = productSkuList.FirstOrDefault(s => s.ProductId == p.Id)?.Id })); } #endregion #region 找出变化的产品 (状态,标题) var stateChangeProductList = productList.Where(p => dbProductList.Any(dp => dp.Id == p.Id && (dp.State != p.State || dp.Title != p.Title))).ToList(); if (stateChangeProductList.Count() > 0) { foreach (var product in stateChangeProductList) { var update = fsql.Update(product.Id).Set(p => p.State, product.State) .Set(p => p.Title, product.Title); updateProductList.Add(update); } } #endregion #region 找出接口查不出的产品 var goneProductList = dbProductList.Where(dp => !productList.Any(p => p.Id == dp.Id)).ToList(); if (goneProductList.Count() > 0) { var goneProductIdList = goneProductList.Select(p => p.Id).ToList(); var update = fsql.Update().Set(p => p.State, -1).Where(p => goneProductIdList.Contains(p.Id)); updateProductList.Add(update); } #endregion #region 找出新增的SKU var newProductSkuList = productSkuList.Where(p => !dbProductSkuList.Any(dp => dp.Id == p.Id)).ToList(); if (newProductSkuList.Count() > 0) { insertProductSkuList.AddRange(newProductSkuList.Select(p => new ProductSku() { Id = p.Id, CreateTime = p.CreateTime, Title = p.Title, State = p.State, ShopId = shopId, Platform = shop.PlatformId, Logo = p.Logo, ProductId = p.ProductId, Price = p.Price, CategoryId = p.Source.Value("categoryId"), CategoryName = GetCategoryName(shop, p.Source.Value("categoryId")) })); } #endregion #region 找出状态变化的SKU var stateChangeProductSkuList = productSkuList.Where(p => dbProductSkuList.Any(dp => dp.Id == p.Id && (dp.State != p.State || dp.Title != p.Title || dp.Price != p.Price || dp.Logo != p.Logo))).ToList(); if (stateChangeProductSkuList.Count() > 0) { foreach (var productSku in stateChangeProductSkuList) { var update = fsql.Update(productSku.Id).Set(p => p.State, productSku.State) .Set(p => p.Title, productSku.Title) .Set(p => p.Price, productSku.Price) .Set(p => p.Logo, productSku.Logo); updateProductSkuList.Add(update); } } #endregion #region 找出缺少类目的sku var noCategoryProductList = productSkuList.Where(p => dbProductSkuList.Any(dp => dp.Id == p.Id && string.IsNullOrEmpty(dp.CategoryName))).ToList(); if (noCategoryProductList.Count() > 0) { foreach (var productSku in noCategoryProductList) { var categoryName = GetCategoryName(shop, productSku.Source.Value("categoryId")); var update = fsql.Update(productSku.Id).Set(p => p.CategoryName, categoryName); updateProductSkuList.Add(update); } } #endregion #region 找出接口查不出的SKU var goneProductSkuList = dbProductSkuList.Where(dp => !productSkuList.Any(p => p.Id == dp.Id)).ToList(); if (goneProductSkuList.Count() > 0) { var goneProductSkuIdList = goneProductSkuList.Select(p => p.Id).ToList(); var update = fsql.Update().Set(p => p.State, 4).Where(p => goneProductSkuIdList.Contains(p.Id)); updateProductSkuList.Add(update); } #endregion fsql.Transaction(() => { if (insertProductList.Count() > 0) fsql.Insert(insertProductList).ExecuteAffrows(); if (insertProductSkuList.Count() > 0) fsql.Insert(insertProductSkuList).ExecuteAffrows(); if (updateProductList.Count() > 0) { foreach (var update in updateProductList) update.ExecuteAffrows(); } if (updateProductSkuList.Count() > 0) { foreach (var update in updateProductSkuList) update.ExecuteAffrows(); } }); } catch (Exception ex) { var shopData = JsonConvert.SerializeObject(shop); nLogManager.Default().Error(ex, $"SyncProduct ShopData:{shopData}"); } } /// /// 同步所有店铺的前50个产品 /// public void SyncAllShopProduct() { var shopList = venderBusiness.GetShopList(platform: Enums.Platform.京东); //SyncProduct(shopList.FirstOrDefault(s => s.ShopId == "12657364"), true); //布莱特玩具专营店 foreach (var shop in shopList) { Task.Factory.StartNew(() => SyncProduct(shop), System.Threading.CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.ProductSyncTaskScheduler); } } /// /// 同步所有店铺的全部产品 /// public void SyncAllShopAllProduct() { var shopList = venderBusiness.GetShopList(platform: Enums.Platform.京东); //SyncProduct(shopList.FirstOrDefault(s => s.ShopName == "披风熊玩具专营店"), true); foreach (var shop in shopList) { Task.Factory.StartNew(() => SyncProduct(shop, true), CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.ProductSyncTaskScheduler); } } private string GetCategoryName(ShopResponse shop, string categoryId) { if (categoryCache.TryGetValue(categoryId, out string name)) return name; try { var res = productBusiness.GetCategoyrInfo(new JDQueryCategoryRequest() { AppKey = shop.AppKey, CategoryId = categoryId, AppSecret = shop.AppSecret, AppToken = shop.AppToken, Platform = shop.PlatformId }); categoryCache.TryAdd(categoryId, res.Name); name = res.Name; } catch { } return name; } } }