using System.Net.Http; using System; using System.Threading.Tasks; using Wicture.DbRESTFul.Infrastructure.Repository; using static JiaZhiQuan.Common.YCTech.YCTechModel; using JiaZhiQuan.Common.Config; using System.Linq; using JiaZhiQuan.Common.Utils; using Wicture.DbRESTFul; using System.Collections.Generic; using System.Data; using Wicture.DbRESTFul.Cache; namespace JiaZhiQuan.Common { /// /// 供应商 /// public static partial class RepositoryExtension { /// /// 同步供应商商品 /// /// /// /// /// /// /// /// /// /// public static async Task SupplierGoodsSync(this DbRESTFulRepository repository, IDbConnection conn, IHttpClientFactory httpClientFactory, ConfigFromDb config, bool isDev, string supplierName) { bool hasChange = false; var supplier = await repository.QuerySingleOrDefaultAsync("select supplierId,supplierName from n_supplier where supplierName=@supplierName and state=0", new { supplierName }); if (supplier == null) throw new LogicalException("未找到该供应商"); int supplierId = (int)supplier.supplierId; var now = DateTime.Now; string syncRst = "同步于初科技商品失败,调用商品接口失败"; //调用商品接口 var httpClient = httpClientFactory.CreateClient(); var request = new YCTechSyncProductRequest { Timestamp = DateTime.Now.ToString("yyyyMMddHHmmssfff") }; await request.ExeRequest(httpClient, config); if (request.Response != null && request.Response.Code != "-99" && request.Response.Data != null && request.Response.Data.Any()) { var supplierGoods = request.Response.Data.Select(g => new SupplierGoods() { productId = (int)g.Id, productName = g.ProductName, supplierId = supplierId, supplierName = supplierName, originalPrice = AmountUtils.ConvertYuanToCent((decimal)g.MianZhi), purchasePrice = AmountUtils.ConvertYuanToCent((decimal)g.ShouJia), pricingType = g.JiJiaLX, pricing = (int)(g.JiJia * 10000) }).ToList(); var goodsList = await repository.QueryAsync(@"select productId, productName, supplierId, originalPrice, purchasePrice , pricingType, pricing from n_supplier_goods where supplierId=@supplierId" , new { supplierId }); //日志数据 List logList = new List(); //需要删除的数据 List delIds = new List(); List addedItems = new List(); List updatedItems = new List(); if (goodsList != null && goodsList.Any()) { //转化成字典进行比较 var oldDict = goodsList.ToDictionary(item => item.productId); var newDict = supplierGoods.ToDictionary(item => item.productId); //新增的数据 addedItems = supplierGoods.Where(nItem => !oldDict.ContainsKey(nItem.productId)).ToList(); if (addedItems.Any()) { addedItems.ForEach(a => { logList.Add(new SupplierGoodsChangeLog { type = 0, syncId = 0, productId = a.productId, productName = a.productName, content = $"{supplierName},新增“{a.productId}”,{a.productName},原价{a.originalPrice}元," + $"优惠{a.pricingType}{a.pricing},采购价{a.purchasePrice}元", createAt = now }); }); } //删除的数据 var deletedItems = goodsList.Where(oItem => !newDict.ContainsKey(oItem.productId)).ToList(); if (deletedItems.Any()) { deletedItems.ForEach(a => { delIds.Add(a.productId); logList.Add(new SupplierGoodsChangeLog { type = 1, syncId = 0, productId = a.productId, productName = a.productName, content = $"{supplierName},减少“{a.productId}”,{a.productName},原价{a.originalPrice}元," + $"优惠{a.pricingType}{a.pricing},采购价{a.purchasePrice}元", createAt = now }); }); } //更新的商品 updatedItems = supplierGoods.Where(nItem => { if (oldDict.TryGetValue(nItem.productId, out var oItem)) { return !AreEqual(oItem, nItem); } return false; }).ToList(); if (updatedItems.Any()) { updatedItems.ForEach(a => { var oldGoods = goodsList.FirstOrDefault(g => g.productId == a.productId); if (oldGoods != null) { logList.Add(new SupplierGoodsChangeLog { type = 2, syncId = 0, productId = a.productId, productName = a.productName, content = $"{supplierName},“{a.productId},{oldGoods.productName}“从“原价{oldGoods.originalPrice}元," + $"优惠{oldGoods.pricingType}{oldGoods.pricing},采购价{oldGoods.purchasePrice}元“变更为" + $"“原价{a.originalPrice}元,优惠{a.pricingType}{a.pricing},采购价{a.purchasePrice}元”", createAt = now }); } }); } } else addedItems = supplierGoods; var trans = conn.BeginTransaction(); try { //新增的数据 if (addedItems.Any()) { await repository.QuerySingleOrDefaultAsync($@"INSERT INTO n_supplier_goods( productId, productName, supplierId, originalPrice, purchasePrice, pricingType, pricing, onsaleState, createAt)VALUES(@productId, @productName, @supplierId, @originalPrice, @purchasePrice, @pricingType, @pricing, {(int)MallGoodsOnsaleState.上架}, @createAt)", addedItems, conn, trans); } //更新的数据 if (updatedItems.Any()) { await repository.QuerySingleOrDefaultAsync($@"update n_supplier_goods set onsaleState={(int)MallGoodsOnsaleState.上架}, productName=@productName, supplierId=@supplierId, originalPrice=@originalPrice, purchasePrice=@purchasePrice, pricingType=@pricingType, pricing=@pricing, updateAt=@updateAt where productId=@productId", updatedItems, conn, trans); } //删除的数据 if (delIds.Any()) { await repository.QuerySingleOrDefaultAsync($"update n_supplier_goods set onsaleState={(int)MallGoodsOnsaleState.下架} where productId in @productId", new { productId = delIds }, conn, trans); } //改动日志数据 if (logList.Any()) { int syncId = await repository.QuerySingleOrDefaultAsync(@"insert into n_supplier_goods_sync(supplierId,state,syncRst,createAt) values (@supplierId,@state,@syncRst,@createAt);select LAST_INSERT_ID();", new { supplierId, state = 1, syncRst = "同步成功", createAt = now }, conn, trans); logList.ForEach(l => { l.syncId = syncId; }); await repository.QuerySingleOrDefaultAsync($@"INSERT INTO n_supplier_goods_change_records( syncId, type, productId, productName, content, createAt)VALUES( @syncId, @type, @productId, @productName, @content, @createAt)", logList, conn, trans); hasChange = true; } trans.Commit(); // 如果有变化发送邮件给运营 if (hasChange) { SendEmail(config, isDev); } return true; } catch (Exception ex) { trans.Rollback(); syncRst = "同步于初科技商品失败" + "\r\n" + ex.Message; LoggerManager.Logger.Error(ex, "同步于初科技商品失败" + "\r\n" + ex.Message); } } await repository.QuerySingleOrDefaultAsync(@"insert into n_supplier_goods_sync(supplierId,state,syncRst,createAt) values (@supplierId,@state,@syncRst,@createAt);", new { supplierId, state = 0, syncRst, createAt = now }); LoggerManager.Logger.Error("", syncRst); return false; } /// /// 同步供应商余额 /// /// /// /// /// /// public static async Task SyncYCTechSupplierBalance(this DbRESTFulRepository repository, IHttpClientFactory httpClientFactory, ConfigFromDb config, string supplierName = "于初科技", bool isSyncAt = true) { var supplier = await repository.QuerySingleOrDefaultAsync("select supplierId,supplierName from n_supplier where supplierName=@supplierName and state=0", new { supplierName }); if (supplier != null) { int supplierId = (int)supplier.supplierId; //查询余额 var httpClient = httpClientFactory.CreateClient(); var request = new YCTechYuERequest { Timestamp = DateTime.Now.ToString("yyyyMMddHHmmssfff") }; await request.ExeRequest(httpClient, config); if (request.Response != null && request.Response.Code != "-99") { int currentBalance = (int)(request.Response.Data.SurplusYuE * 100); string atSql = ""; if (isSyncAt) atSql = ",syncAt=now()"; await repository.QuerySingleOrDefaultAsync($"update n_supplier set balance=@balance {atSql} where supplierId=@supplierId", new { supplierId, balance = currentBalance }); return true; } } LoggerManager.Logger.Error("", "获取供应商余额失败"); return false; } /// /// 比较商品内容是否变化 /// /// /// /// private static bool AreEqual(SupplierGoods item1, SupplierGoods item2) { return item1.productName == item2.productName && item1.originalPrice == item2.originalPrice && item1.purchasePrice == item2.purchasePrice && item1.pricingType == item2.pricingType && item1.pricing == item2.pricing; } private static void SendEmail(ConfigFromDb config, bool isDev) { if (!string.IsNullOrEmpty(config.MPPostStatWarningMailTo)) { // 通过邮件提醒 var cont = "供应商商品有变化,请登录管理后台查看"; var mailToDic = new Dictionary(); config.MPPostStatWarningMailTo.Split(',', StringSplitOptions.RemoveEmptyEntries).ForEach(e => mailToDic[e] = e); var env = isDev ? "【测试环境】" : "【正式环境】"; _ = CommonUtils.SendEmail(new MailInfo { Account = config.MailAccount, MailFromAddr = config.MailAccount, AuthCode = config.MailAuthCode, MailFromName = "JiaZhiQuan.Processor", MailToDic = mailToDic, Subject = env + cont, Content = env + cont }); } } private class SupplierGoods { public int productId { get; set; } public string productName { get; set; } public int supplierId { get; set; } public string supplierName { get; set; } public int originalPrice { get; set; } public int purchasePrice { get; set; } public string pricingType { get; set; } public int pricing { get; set; } public DateTime createAt { get; set; } = DateTime.Now; public DateTime updateAt { get; set; } = DateTime.Now; } private class SupplierGoodsChangeLog { public int type { get; set; } public int syncId { get; set; } public int productId { get; set; } public string productName { get; set; } public string content { get; set; } public DateTime createAt { get; set; } = DateTime.Now; } } }