| | |
| | | using AutoMapper; |
| | | using SqlSugar; |
| | | using WIDESEA_Common.LocationEnum; |
| | | using WIDESEA_Common.StockEnum; |
| | | using WIDESEA_Core.BaseRepository; |
| | | using WIDESEA_Core.BaseServices; |
| | | using WIDESEA_Core.Helper; |
| | | using WIDESEA_IBasicService; |
| | | using WIDESEA_IRecordService; |
| | | using WIDESEA_IStockService; |
| | | using WIDESEA_Model.Models; |
| | |
| | | private readonly IRecordService _recordService; |
| | | public IRepository<Dt_StockInfo> Repository => BaseDal; |
| | | private readonly IRepository<Dt_StockInfoDetail> _stockInfoDetailRepository; |
| | | public StockInfoService(IRepository<Dt_StockInfo> BaseDal, IMapper mapper, IRepository<Dt_StockInfoDetail> stockInfoDetailRepository, IRecordService recordService) : base(BaseDal) |
| | | |
| | | private readonly ILocationInfoService _locationInfoService; |
| | | public StockInfoService(IRepository<Dt_StockInfo> BaseDal, IMapper mapper, IRepository<Dt_StockInfoDetail> stockInfoDetailRepository, IRecordService recordService, ILocationInfoService locationInfoService) : base(BaseDal) |
| | | { |
| | | _mapper = mapper; |
| | | _stockInfoDetailRepository = stockInfoDetailRepository; |
| | | _recordService = recordService; |
| | | _locationInfoService = locationInfoService; |
| | | } |
| | | |
| | | /// <summary> |
| | |
| | | _recordService.StockQuantityChangeRecordService.AddStockChangeRecord(stockInfo, stockInfo.Details, beforeQuantity, stockInfo.Details.Sum(x => x.StockQuantity) + beforeQuantity, WIDESEA_Common.StockEnum.StockChangeType.MaterielGroup); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | /// <param name="stockInfos"></param> |
| | | /// <param name="materielCode"></param> |
| | | /// <param name="needQuantity"></param> |
| | | /// <param name="residueQuantity"></param> |
| | | /// <returns></returns> |
| | | public (List<Dt_StockInfo>, Dictionary<int, decimal>) GetOutboundStocks(List<Dt_StockInfo> stockInfos, string materielCode, decimal needQuantity, out decimal residueQuantity) |
| | | { |
| | | List<Dt_StockInfo> outStocks = new List<Dt_StockInfo>(); |
| | | Dictionary<int, decimal> stockAllocations = new Dictionary<int, decimal>(); // è®°å½æ¯ä¸ªåºåæç»çåé
æ°é |
| | | |
| | | // æå
è¿å
åºæåºææç¸å
³çåºåæç» |
| | | var sortedStockDetails = stockInfos |
| | | .SelectMany(x => x.Details) |
| | | .Where(x => x.MaterielCode == materielCode && |
| | | x.StockQuantity > x.OutboundQuantity) // æå¯ç¨åºå |
| | | .OrderBy(x => x.ProductionDate) // æçäº§æ¥ææåºï¼å
è¿å
åº |
| | | .ThenBy(x => x.StockId) // ç¸åçäº§æ¥ææåºåIDæåº |
| | | .ToList(); |
| | | |
| | | if (!sortedStockDetails.Any()) |
| | | { |
| | | residueQuantity = needQuantity; |
| | | return (outStocks, stockAllocations); |
| | | } |
| | | |
| | | // è®¡ç®æ»å¯ç¨åºå |
| | | var stockTotalQuantity = sortedStockDetails.Sum(x => x.StockQuantity - x.OutboundQuantity); |
| | | |
| | | if (stockTotalQuantity < needQuantity) |
| | | { |
| | | residueQuantity = needQuantity - stockTotalQuantity; |
| | | |
| | | } |
| | | else |
| | | { |
| | | residueQuantity = 0; |
| | | } |
| | | |
| | | decimal remainingNeed = needQuantity; |
| | | |
| | | // æå
è¿å
åºé¡ºåºåé
åºå |
| | | foreach (var detail in sortedStockDetails) |
| | | { |
| | | if (remainingNeed <= 0) break; |
| | | |
| | | decimal availableQuantity = detail.StockQuantity - detail.OutboundQuantity; |
| | | if (availableQuantity <= 0) continue; |
| | | |
| | | decimal allocateQuantity = Math.Min(availableQuantity, remainingNeed); |
| | | |
| | | // æ´æ°åºåºæ°é |
| | | detail.OutboundQuantity += allocateQuantity; |
| | | remainingNeed -= allocateQuantity; |
| | | |
| | | // è®°å½åé
æ°é |
| | | stockAllocations[detail.Id] = allocateQuantity; |
| | | |
| | | // 妿è¿ä¸ªåºåè¿æ²¡æ·»å å°åºåºå表ä¸ï¼å°±æ·»å |
| | | var stockInfo = stockInfos.First(x => x.Id == detail.StockId); |
| | | if (!outStocks.Contains(stockInfo)) |
| | | { |
| | | outStocks.Add(stockInfo); |
| | | } |
| | | } |
| | | |
| | | residueQuantity = remainingNeed; |
| | | return (outStocks, stockAllocations); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// æ ¹æ®æ¡ç è·ååºåä¿¡æ¯ |
| | | /// </summary> |
| | | public async Task<Dt_StockInfoDetail> GetStockDetailByBarcode(string barcode, string materielCode) |
| | | { |
| | | return await Db.Queryable<Dt_StockInfoDetail>() |
| | | .Includes(x => x.StockInfo) |
| | | .Where(x => x.Barcode == barcode && x.MaterielCode == materielCode) |
| | | .FirstAsync(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// è·åç©æçæææ¡ç ä¿¡æ¯ |
| | | /// </summary> |
| | | public async Task<List<Dt_StockInfoDetail>> GetMaterialBarcodes(string materielCode, string batchNo = null) |
| | | { |
| | | var query = Db.Queryable<Dt_StockInfoDetail>() |
| | | .Includes(x => x.StockInfo) |
| | | .Where(x => x.MaterielCode == materielCode && x.StockQuantity > x.OutboundQuantity); |
| | | |
| | | if (!string.IsNullOrEmpty(batchNo)) |
| | | { |
| | | query = query.Where(x => x.BatchNo == batchNo); |
| | | } |
| | | |
| | | return await query.OrderBy(x => x.ProductionDate).ToListAsync(); |
| | | } |
| | | public List<Dt_StockInfo> GetStockInfos(string materielCode, string lotNo, List<string> locationCodes) |
| | | { |
| | | var query = Db.Queryable<Dt_StockInfo>() |
| | | .Where(x => locationCodes.Contains(x.LocationCode) |
| | | // && x.StockStatus == (int)StockStatusEmun.æ£å¸¸) |
| | | ).Includes(x => x.Details); |
| | | |
| | | if (!string.IsNullOrEmpty(materielCode)) |
| | | { |
| | | query = query.Where(x => x.Details.Any(d => d.MaterielCode == materielCode)); |
| | | } |
| | | |
| | | if (!string.IsNullOrEmpty(lotNo)) |
| | | { |
| | | query = query.Where(x => x.Details.Any(d => d.BatchNo == lotNo)); |
| | | } |
| | | |
| | | var stocks = query.ToList(); |
| | | |
| | | return stocks.OrderBy(x => x.Details.Where(d => d.MaterielCode == materielCode && |
| | | (string.IsNullOrEmpty(lotNo) || d.BatchNo == lotNo)).Min(d => d.ProductionDate)).ToList(); |
| | | //ISugarQueryable<Dt_LocationInfo> sugarQueryable = Db.Queryable<Dt_LocationInfo>().Where(x => locationCodes.Contains(x.LocationCode)); |
| | | //ISugarQueryable<Dt_StockInfo> sugarQueryable1 = Db.Queryable<Dt_StockInfo>().Includes(x => x.Details).Where(x => x.Details.Any(v => v.MaterielCode == materielCode)); |
| | | //return sugarQueryable.InnerJoin(sugarQueryable1, (a, b) => a.LocationCode == b.LocationCode).Select((a, b) => b).OrderBy(a => a.CreateDate).Includes(a => a.Details).ToList(); |
| | | } |
| | | |
| | | public List<Dt_StockInfo> GetUseableStocks(string materielCode, string batchNo) |
| | | { |
| | | List<string> locationCodes = _locationInfoService.GetCanOutLocationCodes(); |
| | | |
| | | return GetStockInfos(materielCode, batchNo, locationCodes); |
| | | } |
| | | |
| | | public Dt_StockInfo GetPalletStockInfo(int locationType) |
| | | { |
| | | |
| | | return Db.Queryable<Dt_StockInfo>().Where(x => x.StockStatus == StockStatusEmun.å
¥åºå®æ.ObjToInt() && SqlFunc.Subqueryable<Dt_LocationInfo>().Where(v => v.LocationCode == x.LocationCode && v.LocationType == locationType && v.LocationStatus == LocationStatusEnum.Pallet.ObjToInt() && (v.EnableStatus == EnableStatusEnum.OnlyOut.ObjToInt() || EnableStatusEnum.Normal.ObjToInt() == v.EnableStatus)).Any()).OrderBy(x => x.ModifyDate).First(); |
| | | } |
| | | } |
| | | } |