| | |
| | | using AutoMapper; |
| | | using MailKit.Search; |
| | | using Newtonsoft.Json; |
| | | using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; |
| | | using SqlSugar; |
| | | using System; |
| | | using System.Collections.Generic; |
| | | using System.Linq; |
| | | using System.Net.Http; |
| | | using System.Text; |
| | | using System.Threading.Tasks; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Core; |
| | | using WIDESEA_Core.BaseServices; |
| | | using WIDESEA_Core.Enums; |
| | |
| | | using WIDESEA_IStockRepository; |
| | | using WIDESEA_IStockService; |
| | | using WIDESEA_Model.Models; |
| | | using WIDESEA_StockRepository; |
| | | |
| | | namespace WIDESEA_StockService |
| | | { |
| | |
| | | _outboundRepository = outboundRepository; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ¥è¯¢è®¢åç«åºåºåè§å¾ |
| | | /// </summary> |
| | | /// <param name="orderId"></param> |
| | | /// <param name="materielCode"></param> |
| | | /// <returns></returns> |
| | | public List<StockSelectViewDTO> GetStockSelectViews(int orderId, string materielCode) |
| | | { |
| | | try |
| | |
| | | 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 |
| | | { |
| | |
| | | } |
| | | |
| | | } |
| | | public StockOutboundOrderDTO GetStockOutboundOrder(SaveModel saveModel) |
| | | /// <summary> |
| | | /// æ¥è¯¢è®¢åå¹³åºåºåè§å¾ |
| | | /// </summary> |
| | | /// <param name="orderId"></param> |
| | | /// <param name="materielCode"></param> |
| | | /// <returns></returns> |
| | | public List<StockSelectViewDTO> GetPKStockSelectViews(int orderId, string materielCode) |
| | | { |
| | | try |
| | | { |
| | | var palletCode = saveModel.MainData["barcode"].ToString(); |
| | | Dt_StockInfo stockInfo = BaseDal.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == palletCode).Includes(x => x.Details).First(); |
| | | if (stockInfo == null) |
| | | Dt_OutboundOrder outboundOrder = _outboundRepository.OutboundOrderRepository.QueryFirst(x => x.Id == orderId); |
| | | if (outboundOrder == null) |
| | | { |
| | | throw new Exception($"æªæ¾å°åºåä¿¡æ¯"); |
| | | throw new Exception($"æªæ¾å°åºåºåä¿¡æ¯"); |
| | | } |
| | | Dt_StockInfoDetail stockInfoDetail = stockInfo.Details.FirstOrDefault(); |
| | | if (stockInfoDetail == null) |
| | | return BaseDal.QueryTabs<Dt_StockInfo, Dt_StockInfoDetail, StockSelectViewDTO>((a, b) => a.Id == b.StockId && a.WarehouseId == outboundOrder.WarehouseId, (a, b) => new StockSelectViewDTO |
| | | { |
| | | throw new Exception($"æªæ¾å°åºå详æ
"); |
| | | } |
| | | BaseDal.QueryTabs<Dt_OutboundOrder, Dt_OutboundOrderDetail, StockOutboundOrderDTO>((a, b) => a.Id == b.OrderId, (a, b) => new StockOutboundOrderDTO |
| | | { |
| | | OrderNo = a.OrderNo, |
| | | LocationCode = a.LocationCode, |
| | | MaterielCode = b.MaterielCode, |
| | | MaterielName = b.MaterielName, |
| | | PalletCode = stockInfo.PalletCode, |
| | | BatchNo = b.BatchNo, |
| | | OrderQuantity = b.OrderQuantity, |
| | | OverOutQuantity = b.OverOutQuantity, |
| | | OutboundQuantity = stockInfoDetail.OutboundQuantity, |
| | | SerialNumber = stockInfoDetail.SerialNumber, |
| | | StockQuantity = stockInfoDetail.StockQuantity, |
| | | |
| | | }, a => true, b => b.BatchNo == stockInfoDetail.BatchNo && b.MaterielCode == stockInfoDetail.MaterielCode, x => true).Select(x => new StockOutboundOrderDTO |
| | | PalletCode = a.PalletCode, |
| | | UseableQuantity = b.StockQuantity - b.OutboundQuantity |
| | | }, a => a.LocationCode == "å¹³åºä½", b => b.StockQuantity > b.OutboundQuantity && b.MaterielCode == materielCode, x => true).GroupBy(x => x.PalletCode).Select(x => new StockSelectViewDTO |
| | | { |
| | | OrderNo = x.OrderNo, |
| | | MaterielCode = x.MaterielCode, |
| | | MaterielName = x.MaterielName, |
| | | PalletCode = x.PalletCode, |
| | | BatchNo = x.BatchNo, |
| | | OrderQuantity = x.OrderQuantity, |
| | | OverOutQuantity = x.OverOutQuantity, |
| | | OutboundQuantity = x.OutboundQuantity, |
| | | SerialNumber = x.SerialNumber, |
| | | StockQuantity = x.StockQuantity, |
| | | LocationCode = x.FirstOrDefault()?.LocationCode ?? "", |
| | | MaterielCode = x.FirstOrDefault()?.MaterielCode ?? "", |
| | | MaterielName = x.FirstOrDefault()?.MaterielName ?? "", |
| | | PalletCode = x.Key, |
| | | UseableQuantity = x.Sum(x => x.UseableQuantity) |
| | | }).ToList(); |
| | | return new StockOutboundOrderDTO(); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | 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) |
| | | { |
| | | try |
| | | { |
| | | var barcode = saveModel.MainData["barcode"].ToString(); |
| | | var warehouseId = saveModel.MainData["warehouseId"].ObjToInt(); |
| | | Dt_StockInfo stockInfo = BaseDal.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == barcode && x.WarehouseId == warehouseId).Includes(x => x.Details).First(); |
| | | if (stockInfo == null) throw new Exception("æªæ¾å°æçä¿¡æ¯"); |
| | | return WebResponseContent.Instance.OK(data: stockInfo); |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | return WebResponseContent.Instance.Error(ex.Message); |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | /// <param name="stockInfos"></param> |
| | | /// <param name="materielCode"></param> |
| | | /// <param name="needQuantity"></param> |
| | | /// <param name="residueQuantity"></param> |
| | | /// <returns></returns> |
| | | public List<Dt_StockInfo> GetOutboundStocks(List<Dt_StockInfo> stockInfos, string materielCode, float needQuantity, out float residueQuantity) |
| | | { |
| | | List<Dt_StockInfo> outStocks = new List<Dt_StockInfo>(); |
| | | float stockTotalQuantity = stockInfos.Select(x => x.Details.Sum(v => v.StockQuantity - v.OutboundQuantity)).Sum(x => x); |
| | | stockInfos = stockInfos.OrderBy(x => x.Id).ToList(); |
| | | //stockInfos = stockInfos.OrderBy(x => x.Id).ToList(); |
| | | if (stockTotalQuantity >= needQuantity)//åºåå¤ |
| | | { |
| | | int index = 0; |
| | |
| | | { |
| | | Dt_StockInfo stockInfo = stockInfos[index]; |
| | | float useableStockQuantity = stockInfo.Details.Where(x => x.MaterielCode == materielCode).Sum(x => x.StockQuantity - x.OutboundQuantity); |
| | | if (useableStockQuantity < needQuantity) |
| | | if (useableStockQuantity < needQuantity && useableStockQuantity>0) |
| | | { |
| | | stockInfo.Details.ForEach(x => x.OutboundQuantity = x.StockQuantity); |
| | | needQuantity -= useableStockQuantity; |
| | |
| | | } |
| | | 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; |
| | |
| | | |
| | | return BaseDal.GetStockInfos(materielCode, batchNo, locationCodes); |
| | | } |
| | | |
| | | public List<Dt_StockInfo> GetUseableStocks(string materielCode, string batchNo, string palletcode, int warehoseId) |
| | | { |
| | | Dt_StockInfo stockInfo = BaseDal.Db.Queryable<Dt_StockInfo>().Where(x => x.PalletCode == palletcode && x.WarehouseId == warehoseId).Includes(x => x.Details).First(); |
| | | |
| | | List<string> locationCodes = _basicRepository.LocationInfoRepository.GetCanOutLocationCodes(stockInfo.LocationCode); |
| | | |
| | | 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=fbc3aaf4133ea650d8116fb86b3ebfd0c5e0d46775966ce87893a41886bdf9dc"; |
| | | secret = "SECf221842b26356f22ccac84c4e60714e5287408ee8332a8f63503791382c3f5fb"; |
| | | } |
| | | HttpClient httpClient = new HttpClient(); |
| | | ///è·åæ¶é´æ³ |
| | | var timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(); |
| | | ///çæç¾å |
| | | var sign = GenerateSign(timestamp,secret); |
| | | // æå»ºè¯·æ±URL |
| | | var url = $"{webhookUrl.Split('?')[0]}?access_token={new Uri(webhookUrl).Query.Split('=')[1]}×tamp={timestamp}&sign={sign}"; |
| | | var requestBody = new |
| | | { |
| | | msgtype = "text", |
| | | text = new { content = "å°æ´ä¸»äººè¯´: å°æ´è¦åå°å¦å¤©ä¸ç¬¬ä¸ææå¥½" }, |
| | | }; |
| | | var jsonBody = JsonConvert.SerializeObject(requestBody); |
| | | var content = new StringContent(jsonBody, Encoding.UTF8, "application/json"); |
| | | |
| | | // åéPOSTè¯·æ± |
| | | var response = await httpClient.PostAsync(url, content); |
| | | if (!response.IsSuccessStatusCode) |
| | | { |
| | | // å¤ç请æ±å¤±è´¥çæ
åµ |
| | | var errorContent = await response.Content.ReadAsStringAsync(); |
| | | throw new Exception($"ééæ¶æ¯åé失败ï¼ç¶æç : {response.StatusCode}ï¼é误å
容: {errorContent}"); |
| | | } |
| | | } |
| | | catch(Exception ex) |
| | | { |
| | | throw new Exception($"ééæ¶æ¯åé失败ï¼é误å
容: {ex.Message}"); |
| | | } |
| | | } |
| | | |
| | | /// <summary> |
| | | /// çæå ç¾ç¾å |
| | | /// </summary> |
| | | /// <param name="timestamp">æ¶é´æ³</param> |
| | | /// <returns>ç¾å</returns> |
| | | private string GenerateSign(long timestamp,string secret) |
| | | { |
| | | var stringToSign = $"{timestamp}\n{secret}"; |
| | | using (var hmacsha256 = new System.Security.Cryptography.HMACSHA256(Encoding.UTF8.GetBytes(secret))) |
| | | { |
| | | var hashBytes = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)); |
| | | return Convert.ToBase64String(hashBytes).Replace("+", "%2B").Replace("/", "%2F"); |
| | | } |
| | | } |
| | | } |
| | | } |