| | |
| | | using AutoMapper; |
| | | using MailKit.Search; |
| | | using Newtonsoft.Json; |
| | | using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Net.Http; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEA_Common.StockEnum; |
| | |
| | | throw new Exception($"æªæ¾å°åºåºåä¿¡æ¯"); |
| | | } |
| | | |
| | | List<string> locationCodes = _basicRepository.LocationInfoRepository.GetCanOutLocationCodes(outboundOrder.WarehouseId); |
| | | List<string> locationCodes = _basicRepository.LocationInfoRepository.PPGetCanOutLocationCodes(outboundOrder.WarehouseId); |
| | | |
| | | return BaseDal.QueryTabs<Dt_StockInfo, Dt_StockInfoDetail, StockSelectViewDTO>((a, b) => a.Id == b.StockId, (a, b) => new StockSelectViewDTO |
| | | { |
| | |
| | | return null; |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// æ¥è¯¢è®¢åPPç«åºåºåè§å¾ |
| | | /// </summary> |
| | | /// <param name="orderId"></param> |
| | | /// <param name="materielCode"></param> |
| | | /// <returns></returns> |
| | | public List<PPStockSelectViewDTO> PPGetStockSelectViews(int orderId, string materielCode) |
| | | { |
| | | try |
| | | { |
| | | Dt_MesPPCutOutboundOrder mesPPCutOutboundOrder = _outboundRepository.MesPPCutOutboundOrderRepository.QueryFirst(x => x.Id == orderId); |
| | | if (mesPPCutOutboundOrder == null) |
| | | { |
| | | throw new Exception($"æªæ¾å°åºåºåä¿¡æ¯"); |
| | | } |
| | | List<string> locationCodes = _basicRepository.LocationInfoRepository.PPGetCanOutLocationCodes(mesPPCutOutboundOrder.WarehouseId); |
| | | |
| | | return BaseDal.QueryTabs<Dt_StockInfo, Dt_StockInfoDetail, PPStockSelectViewDTO>((a, b) => a.Id == b.StockId, (a, b) => new PPStockSelectViewDTO |
| | | { |
| | | LocationCode = a.LocationCode, |
| | | MaterielCode = b.MaterielCode, |
| | | MaterielName = b.MaterielName, |
| | | PalletCode = a.PalletCode, |
| | | Unit = b.Unit, |
| | | CutedWidth = b.CutedWidth, |
| | | UseableQuantity = b.StockQuantity - b.OutboundQuantity |
| | | }, a => locationCodes.Contains(a.LocationCode), b => b.StockQuantity > b.OutboundQuantity && b.MaterielCode == materielCode, x => true).GroupBy(x => x.PalletCode).Select(x => new PPStockSelectViewDTO |
| | | { |
| | | LocationCode = x.FirstOrDefault()?.LocationCode ?? "", |
| | | MaterielCode = x.FirstOrDefault()?.MaterielCode ?? "", |
| | | MaterielName = x.FirstOrDefault()?.MaterielName ?? "", |
| | | Unit = x.FirstOrDefault()?.Unit ?? "", |
| | | CutedWidth = x.Sum(x => x.CutedWidth), |
| | | PalletCode = x.Key, |
| | | UseableQuantity = x.Sum(x => x.UseableQuantity) |
| | | }).ToList(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¥è¯¢è®¢åPPå¹³åºåºåè§å¾ |
| | | /// </summary> |
| | | /// <param name="orderId"></param> |
| | | /// <param name="materielCode"></param> |
| | | /// <returns></returns> |
| | | public List<PPStockSelectViewDTO> PPGetPKStockSelectViews(int orderId, string materielCode) |
| | | { |
| | | try |
| | | { |
| | | Dt_MesPPCutOutboundOrder outboundOrder = _outboundRepository.MesPPCutOutboundOrderRepository.QueryFirst(x => x.Id == orderId); |
| | | if (outboundOrder == null) |
| | | { |
| | | throw new Exception($"æªæ¾å°åºåºåä¿¡æ¯"); |
| | | } |
| | | return BaseDal.QueryTabs<Dt_StockInfo, Dt_StockInfoDetail, PPStockSelectViewDTO>((a, b) => a.Id == b.StockId && a.WarehouseId == outboundOrder.WarehouseId, (a, b) => new PPStockSelectViewDTO |
| | | { |
| | | LocationCode = a.LocationCode, |
| | | MaterielCode = b.MaterielCode, |
| | | MaterielName = b.MaterielName, |
| | | PalletCode = a.PalletCode, |
| | | Unit = b.Unit, |
| | | CutedWidth = b.CutedWidth, |
| | | UseableQuantity = b.StockQuantity - b.OutboundQuantity |
| | | }, a => a.LocationCode.Contains("AGV_PP"), b => b.StockQuantity > b.OutboundQuantity && b.MaterielCode == materielCode, x => true).GroupBy(x => x.PalletCode).Select(x => new PPStockSelectViewDTO |
| | | { |
| | | LocationCode = x.FirstOrDefault()?.LocationCode ?? "", |
| | | MaterielCode = x.FirstOrDefault()?.MaterielCode ?? "", |
| | | MaterielName = x.FirstOrDefault()?.MaterielName ?? "", |
| | | Unit = x.FirstOrDefault()?.Unit ?? "", |
| | | CutedWidth = x.Sum(x => x.CutedWidth), |
| | | PalletCode = x.Key, |
| | | UseableQuantity = x.Sum(x => x.UseableQuantity) |
| | | }).ToList(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | public WebResponseContent StockQueryData(SaveModel saveModel) |
| | | { |
| | |
| | | while (needQuantity > 0) |
| | | { |
| | | Dt_StockInfo stockInfo = stockInfos[index]; |
| | | float useableStockQuantity = stockInfo.Details.Where(x => x.MaterielCode == materielCode).Sum(x => x.StockQuantity - x.OutboundQuantity); |
| | | if (useableStockQuantity < needQuantity) |
| | | // 计ç®å¯ç¨åºåæ¶è½¬æ¢ä¸ºdecimal |
| | | decimal useableStockQuantity = stockInfo.Details |
| | | .Where(x => x.MaterielCode == materielCode) |
| | | .Sum(x => (decimal)x.StockQuantity - (decimal)x.OutboundQuantity); |
| | | |
| | | // å°needQuantity转æ¢ä¸ºdecimalè¿è¡æ¯è¾ |
| | | if (useableStockQuantity < (decimal)needQuantity && useableStockQuantity > 0) |
| | | { |
| | | stockInfo.Details.ForEach(x => x.OutboundQuantity = x.StockQuantity); |
| | | needQuantity -= useableStockQuantity; |
| | | stockInfo.Details.ForEach(x => |
| | | x.OutboundQuantity = x.StockQuantity); |
| | | |
| | | // 使ç¨decimalè¿è¡è®¡ç®åå转åfloat |
| | | needQuantity = (float)((decimal)needQuantity - useableStockQuantity); |
| | | } |
| | | else |
| | | { |
| | |
| | | { |
| | | if (x.StockQuantity > x.OutboundQuantity && x.MaterielCode == materielCode) |
| | | { |
| | | if (x.StockQuantity - x.OutboundQuantity >= needQuantity) |
| | | // å°ç¸å
³å¼è½¬æ¢ä¸ºdecimalè¿è¡ç²¾ç¡®è®¡ç® |
| | | decimal currentStock = (decimal)x.StockQuantity; |
| | | decimal currentOutbound = (decimal)x.OutboundQuantity; |
| | | decimal currentNeed = (decimal)needQuantity; |
| | | decimal available = currentStock - currentOutbound; |
| | | |
| | | if (available >= currentNeed) |
| | | { |
| | | x.OutboundQuantity += needQuantity; |
| | | x.OutboundQuantity = (float)(currentOutbound + currentNeed); |
| | | needQuantity = 0; |
| | | } |
| | | else |
| | | { |
| | | needQuantity -= (x.StockQuantity - x.OutboundQuantity); |
| | | needQuantity = (float)(currentNeed - available); |
| | | x.OutboundQuantity = x.StockQuantity; |
| | | } |
| | | } |
| | |
| | | outStocks.Add(stockInfo); |
| | | index++; |
| | | } |
| | | |
| | | } |
| | | else |
| | | { |
| | | for (int i = 0; i < stockInfos.Count; i++) |
| | | { |
| | | Dt_StockInfo stockInfo = stockInfos[i]; |
| | | float useableStockQuantity = stockInfo.Details.Where(x => x.MaterielCode == materielCode).Sum(x => x.StockQuantity - x.OutboundQuantity); |
| | | if (useableStockQuantity < needQuantity) |
| | | { |
| | | stockInfo.Details.ForEach(x => x.OutboundQuantity = x.StockQuantity); |
| | | needQuantity -= useableStockQuantity; |
| | | } |
| | | else |
| | | { |
| | | stockInfo.Details.ForEach(x => |
| | | { |
| | | if (x.StockQuantity > x.OutboundQuantity && x.MaterielCode == materielCode) |
| | | { |
| | | if (x.StockQuantity - x.OutboundQuantity >= needQuantity) |
| | | { |
| | | x.OutboundQuantity += needQuantity; |
| | | needQuantity = 0; |
| | | } |
| | | else |
| | | { |
| | | needQuantity -= (x.StockQuantity - x.OutboundQuantity); |
| | | x.OutboundQuantity = x.StockQuantity; |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | outStocks.Add(stockInfo); |
| | | } |
| | | throw new Exception("åºåä¸è¶³"); |
| | | } |
| | | residueQuantity = needQuantity; |
| | | return outStocks; |
| | |
| | | |
| | | public List<Dt_StockInfo> GetUseableStocks(string materielCode, string batchNo, int warehoseId) |
| | | { |
| | | if ((materielCode.Equals("405000585")|| materielCode.Equals("405000831") || materielCode.Equals("405005565") || materielCode.Equals("405405097") || materielCode.Equals("405005461")) && warehoseId == 5) |
| | | { |
| | | warehoseId = 3; |
| | | } |
| | | List<string> locationCodes = _basicRepository.LocationInfoRepository.GetCanOutLocationCodes(warehoseId); |
| | | |
| | | return BaseDal.GetStockInfos(materielCode, batchNo, locationCodes); |
| | |
| | | return BaseDal.GetStockInfos(materielCode, batchNo, locationCodes); |
| | | } |
| | | |
| | | public WebResponseContent UpdateExpirationlabel() |
| | | { |
| | | try |
| | | { |
| | | var today = DateTime.Today; |
| | | int batchSize = 1000; |
| | | int totalUpdated = 0; |
| | | int skipCount = 0; |
| | | |
| | | // åªæ¥è¯¢éè¦çåæ®µï¼åå°æ°æ®ä¼ è¾åå
åå ç¨ |
| | | var query = BaseDal.Db.Queryable<Dt_StockInfoDetail>() |
| | | .InnerJoin<Dt_StockInfo>((detail, master) => detail.StockId == master.Id) |
| | | .Select((detail, master) => new |
| | | { |
| | | MasterId = master.Id, |
| | | master.WarehouseId, |
| | | detail.EffectiveDate, |
| | | CurrentExpirationlabel = master.Expirationlabel |
| | | }); |
| | | |
| | | while (true) |
| | | { |
| | | var batchData = query.Skip(skipCount).Take(batchSize).ToList(); |
| | | if (!batchData.Any()) break; |
| | | var groupedData = batchData.GroupBy(item => item.MasterId) |
| | | .Select(g => new |
| | | { |
| | | MasterId = g.Key, |
| | | WarehouseId = g.First().WarehouseId, |
| | | // åææ©çæææ¥æ |
| | | EarliestEffectiveDate = g.Min(item => |
| | | { |
| | | DateTime.TryParse(item.EffectiveDate, out DateTime date); |
| | | return date; |
| | | }), |
| | | CurrentExpirationlabel = g.First().CurrentExpirationlabel |
| | | }) |
| | | .ToList(); |
| | | |
| | | var updateDic = new Dictionary<long, int>(); |
| | | |
| | | foreach (var group in groupedData) |
| | | { |
| | | DateTime effectiveDate = group.EarliestEffectiveDate; |
| | | if (effectiveDate == default(DateTime)) // å¤çè§£æå¤±è´¥çæ
åµ |
| | | { |
| | | Console.WriteLine($"主表ID {group.MasterId} 䏿 æææ¥æï¼è·³è¿"); |
| | | continue; |
| | | } |
| | | |
| | | int newLabel; |
| | | if (effectiveDate < today) |
| | | { |
| | | newLabel = ExpirationlabelEnum.è¿æ.ObjToInt(); |
| | | } |
| | | else if (group.WarehouseId == 3) |
| | | { |
| | | int daysDiff = (effectiveDate - today).Days; |
| | | newLabel = daysDiff < 60 |
| | | ? ExpirationlabelEnum.临æé¢è¦.ObjToInt() |
| | | : ExpirationlabelEnum.æªä¸´æ.ObjToInt(); |
| | | } |
| | | else |
| | | { |
| | | int daysDiff = (effectiveDate - today).Days; |
| | | newLabel = daysDiff < 30 |
| | | ? ExpirationlabelEnum.临æé¢è¦.ObjToInt() |
| | | : ExpirationlabelEnum.æªä¸´æ.ObjToInt(); |
| | | } |
| | | |
| | | if (newLabel != group.CurrentExpirationlabel && !updateDic.ContainsKey(group.MasterId)) |
| | | { |
| | | updateDic[group.MasterId] = newLabel; |
| | | } |
| | | } |
| | | |
| | | if (updateDic.Any()) |
| | | { |
| | | var updateBuilder = BaseDal.Db.Updateable<Dt_StockInfo>(); |
| | | var idsToUpdate = updateDic.Keys.ToList(); |
| | | int updateValue = updateDic.First().Value; |
| | | updateBuilder.SetColumns(m => m.Expirationlabel == updateValue) |
| | | .Where(m => idsToUpdate.Contains(m.Id)); |
| | | |
| | | int batchUpdated = updateBuilder.ExecuteCommand(); |
| | | totalUpdated += batchUpdated; |
| | | |
| | | Console.WriteLine($"æ¹æ¬¡æ´æ°ï¼{batchUpdated} æ¡ï¼ç´¯è®¡æ´æ°ï¼{totalUpdated} æ¡ï¼æ´æ°æ¡ä»¶ï¼{JsonConvert.SerializeObject(idsToUpdate)}"); |
| | | } |
| | | |
| | | skipCount += batchSize; |
| | | } |
| | | |
| | | return WebResponseContent.Instance.OK($"æ´æ°æåï¼å
±æ´æ° {totalUpdated} æ¡è®°å½"); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error("æ´æ°å¤±è´¥ï¼è¯·è系管çå"); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// ééæºå¨äººæ¶æ¯æ¨éæµè¯ |
| | | /// </summary> |
| | | /// <returns></returns> |
| | | public async Task T0DingTalkText(string webhookUrl, string secret) |
| | | { |
| | | try |
| | | { |
| | | if (webhookUrl == null || secret == null) |
| | | { |
| | | webhookUrl = "https://oapi.dingtalk.com/robot/send?access_token=c3e05f2c6bcd595383ee02e713446174b9201bad91db216590620fe0acd4e75e"; |
| | | secret = "SEC617f06140fc7cbd8b91d3e203f270826320637af41e7423d756e62df40f62282"; |
| | | } |
| | | |
| | | // 1. å®ä¹ä»åºIDä¸ä»åºåç§°çæ å°å
³ç³»ï¼å¢å æåä»ï¼ |
| | | var warehouseIdToName = new Dictionary<int, string> |
| | | { |
| | | { 2, "油墨ä»" }, |
| | | { 3, "æ¿æä»" }, |
| | | { 4, "PPä»" }, |
| | | { 6, "æµè¯æ¶ä»" }, |
| | | { 7, "æåä»" }, // æ°å¢æåä» |
| | | { 11, "å¹²èä»" }, |
| | | { 12, "é»çä»" } |
| | | }; |
| | | |
| | | // 2. æ¶é´ç¸å
³é
ç½®ï¼ç¨äºçéè¶
è¿90å¤©çæ°æ® |
| | | var currentTime = DateTime.Now; |
| | | var ninetyDaysAgo = currentTime.AddDays(-90); |
| | | |
| | | // 3. å¤çåææä»ï¼ä»åºID â 7ï¼ |
| | | // 3.1 æ¥è¯¢æ è¯ç 为3ï¼è¿æï¼çä¸»è¡¨æ°æ®ï¼æé¤ä»åºID=5å7ï¼ |
| | | var expirationLabel3Stocks = BaseDal.Db.Queryable<Dt_StockInfo>() |
| | | .Where(s => s.Expirationlabel == 3 && s.WarehouseId != 5 && s.WarehouseId != 7 && s.LocationCode != "" && s.LocationCode != null) |
| | | .ToList(); |
| | | |
| | | // 3.2 æ¥è¯¢è¶
è¿90天æªä¿®æ¹ï¼æªä½¿ç¨ï¼çä¸»è¡¨æ°æ®ï¼æé¤ä»åºID=5å7ï¼ |
| | | var over90DaysStocks = BaseDal.Db.Queryable<Dt_StockInfo>() |
| | | .Where(s => s.ModifyDate <= ninetyDaysAgo && s.Expirationlabel != 3 && s.WarehouseId != 5 && s.WarehouseId != 7 && s.LocationCode != "" && s.LocationCode != null) |
| | | .ToList(); |
| | | |
| | | // 4. å¤çæåä»ï¼ä»åºID = 7ï¼ |
| | | var proOver90DaysStocks = new List<Dt_ProStockInfo>(); |
| | | if (warehouseIdToName.ContainsKey(7)) |
| | | { |
| | | proOver90DaysStocks = BaseDal.Db.Queryable<Dt_ProStockInfo>() |
| | | .Where(s => s.WarehouseId == 7 && s.ModifyDate <= ninetyDaysAgo && s.LocationCode != "" && s.LocationCode != null) |
| | | .ToList(); |
| | | } |
| | | |
| | | // æ ç¬¦åæ¡ä»¶æ°æ®æ¶ç´æ¥è¿å |
| | | if (!expirationLabel3Stocks.Any() && !over90DaysStocks.Any() && !proOver90DaysStocks.Any()) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | // 5. æååææä¸»è¡¨æ°æ®çID |
| | | var expirationLabel3StockIds = expirationLabel3Stocks.Select(s => s.Id).ToList(); |
| | | var over90DaysStockIds = over90DaysStocks.Select(s => s.Id).ToList(); |
| | | |
| | | // 6. å
³èæ¥è¯¢åæææç»è¡¨æ°æ® |
| | | var expirationLabel3Details = expirationLabel3StockIds.Any() |
| | | ? BaseDal.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(d => expirationLabel3StockIds.Contains(d.StockId)) |
| | | .ToList() |
| | | : new List<Dt_StockInfoDetail>(); |
| | | |
| | | var over90DaysDetails = over90DaysStockIds.Any() |
| | | ? BaseDal.Db.Queryable<Dt_StockInfoDetail>() |
| | | .Where(d => over90DaysStockIds.Contains(d.StockId)) |
| | | .ToList() |
| | | : new List<Dt_StockInfoDetail>(); |
| | | |
| | | // 7. å¤çæåä»æç»æ°æ® |
| | | var proOver90DaysDetails = new List<Dt_ProStockInfoDetail>(); |
| | | if (proOver90DaysStocks.Any()) |
| | | { |
| | | var proStockIds = proOver90DaysStocks.Select(s => s.Id).ToList(); |
| | | proOver90DaysDetails = BaseDal.Db.Queryable<Dt_ProStockInfoDetail>() |
| | | .Where(d => proStockIds.Contains(d.ProStockId)) |
| | | .ToList(); |
| | | } |
| | | |
| | | // 8. 建ç«ä¸»è¡¨IDå°ä»åºIDçæ å°ï¼å
æ¬æåä»ï¼ |
| | | var stockIdToWarehouseId = new Dictionary<int, int>(); |
| | | |
| | | // 忿仿 å° |
| | | foreach (var stock in expirationLabel3Stocks.Concat(over90DaysStocks)) |
| | | { |
| | | if (!stockIdToWarehouseId.ContainsKey(stock.Id)) |
| | | { |
| | | stockIdToWarehouseId[stock.Id] = stock.WarehouseId; |
| | | } |
| | | } |
| | | |
| | | // æå仿 å° |
| | | foreach (var proStock in proOver90DaysStocks) |
| | | { |
| | | if (!stockIdToWarehouseId.ContainsKey(proStock.Id)) |
| | | { |
| | | stockIdToWarehouseId[proStock.Id] = proStock.WarehouseId; |
| | | } |
| | | } |
| | | |
| | | // 9. æä»åºåç»å¤çç©ææ°æ® |
| | | // 9.1 åææè¿æç©æ |
| | | var expirationLabel3Groups = expirationLabel3Details |
| | | .GroupBy(d => stockIdToWarehouseId[d.StockId]) |
| | | .ToDictionary(g => g.Key, g => g.Select(d => new |
| | | { |
| | | MaterielCode = d.MaterielCode, |
| | | BatchNo = d.BatchNo, |
| | | IsProStock = false // æ 记为éæåä» |
| | | }).Distinct().ToList()); |
| | | |
| | | // 9.2 åææè¶
è¿90天æªä½¿ç¨ç©æ |
| | | var over90DaysGroups = over90DaysDetails |
| | | .GroupBy(d => stockIdToWarehouseId[d.StockId]) |
| | | .ToDictionary(g => g.Key, g => g.Select(d => new |
| | | { |
| | | MaterielCode = d.MaterielCode, |
| | | BatchNo = d.BatchNo, |
| | | IsProStock = false // æ 记为éæåä» |
| | | }).Distinct().ToList()); |
| | | |
| | | // 9.3 æåä»è¶
è¿90天æªä½¿ç¨ç©æ |
| | | if (proOver90DaysDetails.Any()) |
| | | { |
| | | var proWarehouseId = 7; |
| | | var proGroup = proOver90DaysDetails |
| | | .GroupBy(d => stockIdToWarehouseId[d.ProStockId]) |
| | | .Select(g => new |
| | | { |
| | | WarehouseId = g.Key, |
| | | Materials = g.Select(d => new |
| | | { |
| | | MaterielCode = d.ProductCode, // æåä»ä½¿ç¨ProductCodeåæ®µ |
| | | BatchNo = d.LotNumber, // æåä»ä½¿ç¨LotNumberåæ®µ |
| | | IsProStock = true // æ 记为æåä» |
| | | }).Distinct().ToList() |
| | | }) |
| | | .FirstOrDefault(); |
| | | |
| | | if (proGroup != null) |
| | | { |
| | | // æ·»å å°over90DaysGroupsä¸ |
| | | if (over90DaysGroups.ContainsKey(proWarehouseId)) |
| | | { |
| | | over90DaysGroups[proWarehouseId].AddRange(proGroup.Materials); |
| | | } |
| | | else |
| | | { |
| | | over90DaysGroups[proWarehouseId] = proGroup.Materials; |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 10. è·åæææ¶åçä»åºID |
| | | var allWarehouseIds = expirationLabel3Groups.Keys |
| | | .Union(over90DaysGroups.Keys) |
| | | .ToList(); |
| | | |
| | | // 11. åéééæ¶æ¯ |
| | | using (HttpClient httpClient = new HttpClient()) |
| | | { |
| | | foreach (var warehouseId in allWarehouseIds) |
| | | { |
| | | var warehouseName = warehouseIdToName.TryGetValue(warehouseId, out var name) |
| | | ? name |
| | | : $"ä»åº{warehouseId}"; |
| | | |
| | | // 11.1 æå»ºmarkdownæ ¼å¼æ¶æ¯ |
| | | var markdownContent = new StringBuilder(); |
| | | markdownContent.AppendLine($"## {warehouseName}ç©ææééç¥\n"); |
| | | |
| | | // ç»è®¡ä¿¡æ¯ |
| | | var expiredCount = expirationLabel3Groups.TryGetValue(warehouseId, out var expList) ? |
| | | expList.Count : 0; |
| | | |
| | | var over90Count = over90DaysGroups.TryGetValue(warehouseId, out var over90List) ? |
| | | over90List.Count : 0; |
| | | |
| | | // å¦ææ¯æåä»ï¼éè¦è¿æ»¤åºæåä»çæ°æ® |
| | | if (warehouseId == 7) |
| | | { |
| | | over90Count = over90List?.Count(m => m.IsProStock) ?? 0; |
| | | } |
| | | |
| | | markdownContent.AppendLine($"**ç»è®¡æ¦è§ï¼**"); |
| | | if (warehouseId == 7) |
| | | { |
| | | markdownContent.AppendLine($"- è¶
è¿90天æªä½¿ç¨æåï¼{over90Count}æ¡"); |
| | | } |
| | | else |
| | | { |
| | | markdownContent.AppendLine($"- è¿æç©æï¼{expiredCount}æ¡"); |
| | | markdownContent.AppendLine($"- è¶
è¿90天æªä½¿ç¨ç©æï¼{over90Count}æ¡"); |
| | | } |
| | | markdownContent.AppendLine(); |
| | | |
| | | // 11.2 æ·»å è¿æç©æè¡¨æ ¼ï¼å¦æææ°æ®ä¸ä¸æ¯æåä»ï¼ |
| | | if (expiredCount > 0 && warehouseId != 7) |
| | | { |
| | | markdownContent.AppendLine("### ä¸ãè¿æç©æ"); |
| | | markdownContent.AppendLine("| åºå· | ç©æç¼ç | æ¹æ¬¡å· |"); |
| | | markdownContent.AppendLine("| :--- | :--- | :--- |"); |
| | | |
| | | int index = 1; |
| | | var expiredToShow = expList.Take(200); |
| | | foreach (var material in expiredToShow) |
| | | { |
| | | markdownContent.AppendLine($"| {index} | {material.MaterielCode} | {material.BatchNo} |"); |
| | | index++; |
| | | } |
| | | |
| | | if (expiredCount > 200) |
| | | { |
| | | markdownContent.AppendLine($"| ... | å
±{expiredCount}æ¡ï¼ä»
æ¾ç¤ºå200æ¡ | ... |"); |
| | | } |
| | | markdownContent.AppendLine(); |
| | | } |
| | | |
| | | // 11.3 æ·»å è¶
è¿90天æªä½¿ç¨ç©æè¡¨æ ¼ï¼å¦æææ°æ®ï¼ |
| | | if (over90Count > 0) |
| | | { |
| | | if (warehouseId == 7) |
| | | { |
| | | markdownContent.AppendLine("### è¶
è¿90天æªä½¿ç¨æå"); |
| | | } |
| | | else |
| | | { |
| | | markdownContent.AppendLine("### äºãè¶
è¿90天æªä½¿ç¨ç©æ"); |
| | | } |
| | | |
| | | markdownContent.AppendLine("| åºå· | ç©æç¼ç | æ¹æ¬¡å· |"); |
| | | markdownContent.AppendLine("| :--- | :--- | :--- |"); |
| | | |
| | | int index = 1; |
| | | var over90ToShow = warehouseId == 7 ? |
| | | over90List?.Where(m => m.IsProStock).Take(500) : |
| | | over90List?.Take(500); |
| | | |
| | | if (over90ToShow != null) |
| | | { |
| | | foreach (var material in over90ToShow) |
| | | { |
| | | markdownContent.AppendLine($"| {index} | {material.MaterielCode} | {material.BatchNo} |"); |
| | | index++; |
| | | } |
| | | |
| | | if (over90Count > (warehouseId == 7 ? 500 : 200)) |
| | | { |
| | | markdownContent.AppendLine($"| ... | å
±{over90Count}æ¡ï¼ä»
æ¾ç¤ºå{(warehouseId == 7 ? 500 : 200)}æ¡ | ... |"); |
| | | } |
| | | } |
| | | markdownContent.AppendLine(); |
| | | } |
| | | |
| | | // 11.4 æ·»å æ¶é´æ³åæç¤ºä¿¡æ¯ |
| | | markdownContent.AppendLine($"**æ¥åæ¶é´ï¼** {currentTime:yyyy-MM-dd HH:mm:ss}"); |
| | | if (warehouseId == 7) |
| | | { |
| | | markdownContent.AppendLine("**夿³¨ï¼** 请æåä»ç®¡ç人ååæ¶å¤çè¶
è¿90天æªä½¿ç¨çæåã"); |
| | | } |
| | | else |
| | | { |
| | | markdownContent.AppendLine("**夿³¨ï¼** 请ç¸å
³ä»åºç®¡ç人ååæ¶å¤ç以ä¸ç©æã"); |
| | | } |
| | | |
| | | var messageContent = markdownContent.ToString(); |
| | | |
| | | // 11.5 çæééæ¶æ¯æéçæ¶é´æ³åç¾å |
| | | var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(); |
| | | var sign = GenerateSign(timestamp, secret); |
| | | |
| | | // 11.6 æå»ºéé请æ±URL |
| | | var uri = new Uri(webhookUrl); |
| | | var token = System.Web.HttpUtility.ParseQueryString(uri.Query)["access_token"]; |
| | | var baseUrl = uri.GetLeftPart(UriPartial.Path); |
| | | var url = $"{baseUrl}?access_token={token}×tamp={timestamp}&sign={sign}"; |
| | | |
| | | // 11.7 æå»ºè¯·æ±ä½ï¼ä½¿ç¨markdownæ ¼å¼ï¼ |
| | | var requestBody = new |
| | | { |
| | | msgtype = "markdown", |
| | | markdown = new |
| | | { |
| | | title = $"{warehouseName}ç©ææé", |
| | | text = messageContent |
| | | }, |
| | | at = new |
| | | { |
| | | // å¯ä»¥æå®@æäºäººï¼å¦æä¸éè¦å¯ä»¥å é¤è¿é¨å |
| | | // atMobiles = new[] { "138xxxx8888" }, |
| | | // isAtAll = false |
| | | } |
| | | }; |
| | | |
| | | var jsonBody = JsonConvert.SerializeObject(requestBody); |
| | | var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); |
| | | |
| | | // 11.8 åéPOST请æ±å¹¶å¤çååº |
| | | var response = await httpClient.PostAsync(url, content); |
| | | if (!response.IsSuccessStatusCode) |
| | | { |
| | | var errorContent = await response.Content.ReadAsStringAsync(); |
| | | throw new Exception($"ã{warehouseName}ãæ¶æ¯åé失败ï¼ç¶æç ï¼{response.StatusCode}ï¼é误信æ¯ï¼{errorContent}"); |
| | | } |
| | | |
| | | // é¿å
åéé¢çè¿å¿« |
| | | await Task.Delay(1000); |
| | | } |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | // æè·å¼å¸¸å¹¶è¡¥å
ä¸ä¸æï¼ä¾¿äºé®é¢å®ä½ |
| | | throw new Exception($"ééæ¶æ¯æ¨éæ´ä½å¤±è´¥ï¼é误详æ
ï¼{ex.Message}", ex); |
| | | } |
| | | } |
| | | |
| | | // ééç¾åçææ¹æ³ |
| | | private string GenerateSign(long timestamp, string secret) |
| | | { |
| | | var stringToSign = $"{timestamp}\n{secret}"; |
| | | using (var hmac = new System.Security.Cryptography.HMACSHA256(Encoding.UTF8.GetBytes(secret))) |
| | | { |
| | | var hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)); |
| | | return Convert.ToBase64String(hash); |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |