From e5d08bf31d0e7c1ea3606d549898fbfa0bad50b6 Mon Sep 17 00:00:00 2001
From: shanj <18996038927@163.com>
Date: Tue, 19 Sep 2023 18:57:41 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BA=A7=E5=93=81=E5=90=8C=E6=AD=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../Controllers/ProductSyncController.cs | 23 ++
.../Sync/ProductSyncBusiness.cs | 214 ++++++++++++++++++
BBWYB.Server.Business/TaskSchedulerManager.cs | 2 +
BBWYB.Server.Model/Db/Product/Product.cs | 54 +++++
BBWYB.Server.Model/Db/Product/ProductSku.cs | 59 +++++
.../QuanTan_Supplier_ProductListResponse.cs | 6 +
...QuanTan_Supplier_ProductSkuListResponse.cs | 6 +
.../Client/Impl/OP_QuanTanClient.cs | 9 +-
.../Response/Product/OP_ProductResponse.cs | 1 +
.../Response/Product/OP_ProductSkuResponse.cs | 3 +
10 files changed, 373 insertions(+), 4 deletions(-)
create mode 100644 BBWYB.Server.API/Controllers/ProductSyncController.cs
create mode 100644 BBWYB.Server.Business/Sync/ProductSyncBusiness.cs
create mode 100644 BBWYB.Server.Model/Db/Product/Product.cs
create mode 100644 BBWYB.Server.Model/Db/Product/ProductSku.cs
diff --git a/BBWYB.Server.API/Controllers/ProductSyncController.cs b/BBWYB.Server.API/Controllers/ProductSyncController.cs
new file mode 100644
index 0000000..b196c48
--- /dev/null
+++ b/BBWYB.Server.API/Controllers/ProductSyncController.cs
@@ -0,0 +1,23 @@
+using BBWYB.Server.Business.Sync;
+using Microsoft.AspNetCore.Mvc;
+
+namespace BBWYB.Server.API.Controllers
+{
+ public class ProductSyncController : BaseApiController
+ {
+ private ProductSyncBusiness productSyncBusiness;
+ public ProductSyncController(IHttpContextAccessor httpContextAccessor, ProductSyncBusiness productSyncBusiness) : base(httpContextAccessor)
+ {
+ this.productSyncBusiness = productSyncBusiness;
+ }
+
+ ///
+ /// 全店同步产品
+ ///
+ [HttpPost]
+ public void SyncAllShopAllProduct()
+ {
+ productSyncBusiness.SyncAllShopAllProduct();
+ }
+ }
+}
diff --git a/BBWYB.Server.Business/Sync/ProductSyncBusiness.cs b/BBWYB.Server.Business/Sync/ProductSyncBusiness.cs
new file mode 100644
index 0000000..4bcca99
--- /dev/null
+++ b/BBWYB.Server.Business/Sync/ProductSyncBusiness.cs
@@ -0,0 +1,214 @@
+using BBWYB.Common.Log;
+using BBWYB.Common.Models;
+using BBWYB.Server.Model.Db;
+using BBWYB.Server.Model.Dto;
+using FreeSql;
+using SDKAdapter.OperationPlatform.Models;
+using Yitter.IdGenerator;
+using System.Linq;
+using Newtonsoft.Json;
+using BBWYB.Server.Model;
+
+namespace BBWYB.Server.Business.Sync
+{
+ public class ProductSyncBusiness : BaseBusiness, IDenpendency
+ {
+ private ProductBusiness productBusiness;
+ private VenderBusiness venderBusiness;
+ private TaskSchedulerManager taskSchedulerManager;
+
+ public ProductSyncBusiness(IFreeSql fsql, NLogManager nLogManager, IIdGenerator idGenerator, ProductBusiness productBusiness, VenderBusiness venderBusiness, TaskSchedulerManager taskSchedulerManager) : base(fsql, nLogManager, idGenerator)
+ {
+ this.productBusiness = productBusiness;
+ this.venderBusiness = venderBusiness;
+ this.taskSchedulerManager = taskSchedulerManager;
+ }
+
+ ///
+ /// 同步所有店铺的全部产品
+ ///
+ public void SyncAllShopAllProduct()
+ {
+ //var shopList = venderBusiness.GetShopList(platform: Enums.Platform.拳探);
+ var shopList = venderBusiness.GetShopList(shopId: 9);
+ foreach (var shop in shopList)
+ {
+ Task.Factory.StartNew(() => SyncProduct(shop, true), CancellationToken.None, TaskCreationOptions.LongRunning, taskSchedulerManager.SyncProductTaskScheduler);
+ }
+ }
+
+
+ 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 OP_QueryProductRequest()
+ {
+ PageSize = 50,
+ PageIndex = 1,
+ AppKey = shop.AppKey,
+ AppSecret = shop.AppSecret,
+ AppToken = shop.AppToken,
+ Platform = SDKAdapter.AdapterEnums.PlatformType.拳探
+ };
+
+ var requestSku = new OP_QueryProductSkuRequest()
+ {
+ AppKey = shop.AppKey,
+ AppSecret = shop.AppSecret,
+ AppToken = shop.AppToken,
+ Platform = SDKAdapter.AdapterEnums.PlatformType.拳探,
+ //Spu = product.Id,
+ PageSize = 50,
+ PageIndex = 1
+ };
+
+ while (true)
+ {
+ var pListRes = productBusiness.GetProductList(request);
+ if (pListRes == null || pListRes.Items == null || pListRes.Items.Count == 0)
+ break;
+ productList.AddRange(pListRes.Items);
+
+ foreach (var product in pListRes.Items)
+ {
+ requestSku.Spu = product.Id;
+ var psListRes = productBusiness.GetProductSkuList(requestSku);
+ if (psListRes == null || psListRes.Items == null || psListRes.Items.Count == 0)
+ continue;
+ productSkuList.AddRange(psListRes.Items);
+ }
+
+ if (pListRes.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,
+ Logo = p.Logo,
+ ProductName = p.Title,
+ ShopId = int.Parse(shop.ShopId),
+ State = p.State,
+ SyncTime = DateTime.Now,
+ UpdateTime = DateTime.Now,
+ UpperTime = p.CreateTime
+ }));
+ }
+ #endregion
+
+ #region 找出变化的产品 (状态,标题)
+ var stateChangeProductList = productList.Where(p => dbProductList.Any(dp => dp.Id == p.Id && (dp.State != p.State || dp.ProductName != 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.ProductName, 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, 0).Where(p => goneProductIdList.Contains(p.Id));
+ updateProductList.Add(update);
+ }
+ #endregion
+
+ #region 找出新增的SKU
+ var newProductSkuList = productSkuList.Where(ps => !dbProductSkuList.Any(dps => dps.Id == ps.Id)).ToList();
+ if (newProductSkuList.Count() > 0)
+ {
+ insertProductSkuList.AddRange(newProductSkuList.Select(ps => new ProductSku()
+ {
+ Id = ps.Id,
+ Logo = ps.Logo,
+ Price = ps.Price,
+ ProductId = ps.ProductId,
+ ShopId = int.Parse(shop.ShopId),
+ SkuName = ps.Title,
+ State = ps.State,
+ SyncTime = DateTime.Now,
+ UpdateTime = DateTime.Now,
+ UpperTime = ps.CreateTime
+ }));
+ }
+ #endregion
+
+ #region 找出状态变化的SKU
+ var stateChangeProductSkuList = productSkuList.Where(ps => dbProductSkuList.Any(dps => dps.Id == ps.Id && (dps.State != ps.State || dps.SkuName != ps.Title))).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.SkuName, productSku.Title);
+ updateProductSkuList.Add(update);
+ }
+ }
+ #endregion
+
+ #region 找出接口查不出的SKU
+ var goneProductSkuList = dbProductSkuList.Where(dps => !productSkuList.Any(ps => ps.Id == dps.Id)).ToList();
+ if (goneProductSkuList.Count() > 0)
+ {
+ var goneProductSkuIdList = goneProductSkuList.Select(ps => ps.Id).ToList();
+ var update = fsql.Update().Set(ps => ps.State, 0).Where(ps => goneProductSkuIdList.Contains(ps.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();
+ }
+ });
+
+ Console.WriteLine($"{shop.ShopName}同步完毕,新增spu{insertProductList.Count()}个,新增sku{insertProductSkuList.Count()}个,更新spu{updateProductList.Count()}个,更新sku{updateProductSkuList.Count()}个");
+ }
+ catch (Exception ex)
+ {
+ nLogManager.Default().Error(ex, $"SyncProduct ShopId:{shop.ShopName}");
+ }
+ }
+ }
+}
diff --git a/BBWYB.Server.Business/TaskSchedulerManager.cs b/BBWYB.Server.Business/TaskSchedulerManager.cs
index fa971c1..6bab173 100644
--- a/BBWYB.Server.Business/TaskSchedulerManager.cs
+++ b/BBWYB.Server.Business/TaskSchedulerManager.cs
@@ -4,6 +4,7 @@ namespace BBWYB.Server.Business
{
public class TaskSchedulerManager
{
+ public LimitedConcurrencyLevelTaskScheduler SyncProductTaskScheduler { get; private set; }
public LimitedConcurrencyLevelTaskScheduler SyncOrderTaskScheduler { get; private set; }
public LimitedConcurrencyLevelTaskScheduler PurchaseOrderCallbackTaskScheduler { get; private set; }
@@ -13,6 +14,7 @@ namespace BBWYB.Server.Business
{
SyncOrderTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(10);
PurchaseOrderCallbackTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(10);
+ SyncProductTaskScheduler = new LimitedConcurrencyLevelTaskScheduler(10);
}
}
}
diff --git a/BBWYB.Server.Model/Db/Product/Product.cs b/BBWYB.Server.Model/Db/Product/Product.cs
new file mode 100644
index 0000000..ee4f128
--- /dev/null
+++ b/BBWYB.Server.Model/Db/Product/Product.cs
@@ -0,0 +1,54 @@
+using FreeSql.DataAnnotations;
+
+namespace BBWYB.Server.Model.Db
+{
+
+ ///
+ /// 商品表(SPU)
+ ///
+ [Table(Name = "product", DisableSyncStructure = true)]
+ public partial class Product
+ {
+
+ [Column(StringLength = 50, IsPrimary = true, IsNullable = false)]
+ public string Id { get; set; }
+
+
+ public string Logo { get; set; }
+
+ ///
+ /// 商品名称
+ ///
+ [Column(StringLength = 200)]
+ public string ProductName { get; set; }
+
+ [Column(DbType = "bigint")]
+ public long? ShopId { get; set; }
+
+ ///
+ /// 状态(0下架 1上架)
+ ///
+ [Column(DbType = "int")]
+ public int? State { get; set; }
+
+ ///
+ /// 同步时间
+ ///
+ [Column(DbType = "datetime")]
+ public DateTime? SyncTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [Column(DbType = "datetime")]
+ public DateTime? UpdateTime { get; set; }
+
+ ///
+ /// 最近上架时间
+ ///
+ [Column(DbType = "datetime")]
+ public DateTime? UpperTime { get; set; }
+
+ }
+
+}
diff --git a/BBWYB.Server.Model/Db/Product/ProductSku.cs b/BBWYB.Server.Model/Db/Product/ProductSku.cs
new file mode 100644
index 0000000..0a385ba
--- /dev/null
+++ b/BBWYB.Server.Model/Db/Product/ProductSku.cs
@@ -0,0 +1,59 @@
+using FreeSql.DataAnnotations;
+
+namespace BBWYB.Server.Model.Db
+{
+
+ ///
+ /// 商品Sku表
+ ///
+ [ Table(Name = "productsku", DisableSyncStructure = true)]
+ public partial class ProductSku {
+
+ ///
+ /// SkuId
+ ///
+ [Column(StringLength = 50, IsPrimary = true, IsNullable = false)]
+ public string Id { get; set; }
+
+
+ public string Logo { get; set; }
+
+ [Column(DbType = "decimal(18,2)")]
+ public decimal? Price { get; set; } = 0.00M;
+
+ [Column(StringLength = 50)]
+ public string ProductId { get; set; }
+
+ [Column(DbType = "bigint")]
+ public long? ShopId { get; set; }
+
+ [Column(StringLength = 200)]
+ public string SkuName { get; set; }
+
+ ///
+ /// 0下架 1上架
+ ///
+ [Column(DbType = "int")]
+ public int? State { get; set; }
+
+ ///
+ /// 同步时间
+ ///
+ [Column(DbType = "datetime")]
+ public DateTime? SyncTime { get; set; }
+
+ ///
+ /// 更新时间
+ ///
+ [Column(DbType = "datetime")]
+ public DateTime? UpdateTime { get; set; }
+
+ ///
+ /// 最近上架时间
+ ///
+ [Column(DbType = "datetime")]
+ public DateTime? UpperTime { get; set; }
+
+ }
+
+}
diff --git a/QuanTan.SDK/Models/Supplier/Response/Product/QuanTan_Supplier_ProductListResponse.cs b/QuanTan.SDK/Models/Supplier/Response/Product/QuanTan_Supplier_ProductListResponse.cs
index c56f556..49f68d0 100644
--- a/QuanTan.SDK/Models/Supplier/Response/Product/QuanTan_Supplier_ProductListResponse.cs
+++ b/QuanTan.SDK/Models/Supplier/Response/Product/QuanTan_Supplier_ProductListResponse.cs
@@ -9,6 +9,12 @@
public string Image { get; set; }
public string StoreId { get; set; }
+
+ public int? IsShow { get; set; }
+
+ public int? Status { get; set; }
+
+ public DateTime? UpperTime { get; set; }
}
public class QuanTan_Supplier_ProductListResponse : QuanTanListResponse
diff --git a/QuanTan.SDK/Models/Supplier/Response/Product/QuanTan_Supplier_ProductSkuListResponse.cs b/QuanTan.SDK/Models/Supplier/Response/Product/QuanTan_Supplier_ProductSkuListResponse.cs
index 51d8c36..ec89b75 100644
--- a/QuanTan.SDK/Models/Supplier/Response/Product/QuanTan_Supplier_ProductSkuListResponse.cs
+++ b/QuanTan.SDK/Models/Supplier/Response/Product/QuanTan_Supplier_ProductSkuListResponse.cs
@@ -17,6 +17,12 @@
public string CategoryId { get; set; }
public string StoreId { get; set; }
+
+ public int? IsShow { get; set; }
+
+ public int? Status { get; set; }
+
+ public DateTime? UpperTime { get; set; }
}
public class QuanTan_Supplier_ProductSkuListResponse : QuanTanListResponse
diff --git a/SDKAdapter/OperationPlatform/Client/Impl/OP_QuanTanClient.cs b/SDKAdapter/OperationPlatform/Client/Impl/OP_QuanTanClient.cs
index 6cd3169..e0cfb85 100644
--- a/SDKAdapter/OperationPlatform/Client/Impl/OP_QuanTanClient.cs
+++ b/SDKAdapter/OperationPlatform/Client/Impl/OP_QuanTanClient.cs
@@ -3,6 +3,7 @@ using BBWYB.Common.Models;
using QuanTan.SDK.Client.Supplier;
using QuanTan.SDK.Models.Supplier;
using SDKAdapter.OperationPlatform.Models;
+using static System.Net.WebRequestMethods;
namespace SDKAdapter.OperationPlatform.Client
{
@@ -41,10 +42,10 @@ namespace SDKAdapter.OperationPlatform.Client
{
Id = qtp.ProductId,
BrandName = string.Empty,
- CreateTime = null,
+ CreateTime = qtp.UpperTime,
Logo = qtp.Image,
ProductItemNum = string.Empty,
- State = 0,
+ State = qtp.IsShow == 1 && qtp.Status == 1 ? 1 : 0,
Title = qtp.ProductName
}).ToList()
};
@@ -69,12 +70,12 @@ namespace SDKAdapter.OperationPlatform.Client
Count = qtResponse.Data.Count,
Items = qtResponse.Data.List.Select(qtps => new OP_ProductSkuResponse()
{
- CreateTime = null,
+ CreateTime = qtps.UpperTime,
Id = qtps.ProductSku,
Logo = qtps.SkuImage,
Price = qtps.SkuPrice,
ProductId = qtps.ProductId,
- State = 0,
+ State = qtps.IsShow == 1 && qtps.Status == 1 ? 1 : 0,
Title = qtps.SkuName
}).ToList()
};
diff --git a/SDKAdapter/OperationPlatform/Models/Response/Product/OP_ProductResponse.cs b/SDKAdapter/OperationPlatform/Models/Response/Product/OP_ProductResponse.cs
index 85a0a2c..4f6b3b9 100644
--- a/SDKAdapter/OperationPlatform/Models/Response/Product/OP_ProductResponse.cs
+++ b/SDKAdapter/OperationPlatform/Models/Response/Product/OP_ProductResponse.cs
@@ -20,6 +20,7 @@
///
/// 商品状态
/// 京东【-1:删除 1:从未上架 2:自主下架 4:系统下架 8:上架 513:从未上架待审 514:自主下架待审 516:系统下架待审 520:上架待审核 1028:系统下架审核失败】
+ /// 拳探【0下架 1上架】
///
public int State { get; set; }
diff --git a/SDKAdapter/OperationPlatform/Models/Response/Product/OP_ProductSkuResponse.cs b/SDKAdapter/OperationPlatform/Models/Response/Product/OP_ProductSkuResponse.cs
index ce130e8..3d39a54 100644
--- a/SDKAdapter/OperationPlatform/Models/Response/Product/OP_ProductSkuResponse.cs
+++ b/SDKAdapter/OperationPlatform/Models/Response/Product/OP_ProductSkuResponse.cs
@@ -20,6 +20,9 @@
///
/// 京东【1:上架 2:下架 4:删除】
///
+ ///
+ /// 拳探【0下架 1上架】
+ ///
///
public int State { get; set; }