using DS.Module.Core; using DS.Module.SqlSugar; using DS.Module.UserModule; using DS.WMS.Core.Op.Dtos; using DS.WMS.Core.Op.Entity; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using NLog; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Mapster; using DS.WMS.Core.Op.Interface; using Microsoft.Extensions.Logging; namespace DS.WMS.Core.Op.Method { /// /// 舱位库存 /// public class BookingSlotStockService: IBookingSlotStockService { private readonly IServiceProvider _serviceProvider; private readonly ISqlSugarClient db; private readonly IUser user; private readonly ISaasDbService saasService; private static readonly NLog.Logger Logger = LogManager.GetCurrentClassLogger(); /// /// /// /// public BookingSlotStockService(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; db = _serviceProvider.GetRequiredService(); user = _serviceProvider.GetRequiredService(); saasService = _serviceProvider.GetRequiredService(); } #region 计算舱位库存 /// /// 计算舱位库存 /// /// 请求参数 /// 返回回执 public async Task> BookingSlotStock(BookingSlotStockUpdateModel paraObj) { Logger.Log(NLog.LogLevel.Info, $"收到更新库存订阅请求:{ JsonConvert.SerializeObject(paraObj)}"); if (string.IsNullOrEmpty(paraObj.Vessel) || string.IsNullOrEmpty(paraObj.Voyno) || string.IsNullOrEmpty(paraObj.ContractNo) || string.IsNullOrEmpty(paraObj.BookingSlotType) || string.IsNullOrEmpty(paraObj.CarrierCode) || string.IsNullOrEmpty(paraObj.PortLoadId) || string.IsNullOrEmpty(paraObj.PortDischargeId)) { Logger.Log(NLog.LogLevel.Info, $"收到更新库存订阅请求:部分参数存在空值,结束"); return DataResult.FailedData(string.Empty); } var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var baseList = await tenantDb.Queryable() .Where(x => !x.Deleted //&& x.TenantId == paraObj.TenantId && x.Vessel == paraObj.Vessel && x.Voyno == paraObj.Voyno && x.ContractNo == paraObj.ContractNo && x.BookingSlotType == paraObj.BookingSlotType && x.CarrierCode == paraObj.CarrierCode && x.PortLoadCode == paraObj.PortLoadId && x.PortDischargeCode == paraObj.PortDischargeId) .OrderByDescending(x => x.UpdateTime) .ToListAsync(); var stockObj = await tenantDb.Queryable() .FirstAsync(x => !x.Deleted //&& x.TenantId == paraObj.TenantId && x.Vessel == paraObj.Vessel && x.Voyno == paraObj.Voyno && x.ContractNo == paraObj.ContractNo && x.BookingSlotType == paraObj.BookingSlotType && x.CarrierCode == paraObj.CarrierCode && x.PortLoadId == paraObj.PortLoadId && x.PortDischargeId == paraObj.PortDischargeId); if (!baseList.Any()) { if (stockObj != null) { // 从库存表删除这7项维度的库存数据 await tenantDb.Deleteable(stockObj).ExecuteCommandAsync(); } return DataResult.FailedData(string.Empty); } var isInsert = stockObj == null; var idTemp = stockObj?.Id; stockObj = baseList[0].Adapt(stockObj); if (isInsert) { stockObj.Id = 0; } else { stockObj.Id = (long)idTemp; } stockObj.PortLoadId = baseList[0].PortLoadCode; stockObj.PortDischargeId = baseList[0].PortDischargeCode; // 总舱位数 stockObj.TotalOrders = baseList.Count; // 取消舱位数 stockObj.CancelNum = baseList.Count(x => x.IsCancellation); // 舱位主键列表 var slotBaseIdList = baseList.Select(x => x.Id).ToList(); // 总的箱型箱量 var ctnAllList = await tenantDb.Queryable() .Where(x => !x.Deleted && slotBaseIdList.Contains(x.SlotId)) .GroupBy(x => x.CtnAll) .Select(x => new { x.CtnAll, CTNNUM = SqlFunc.AggregateSum(x.CtnNum) }).ToListAsync(); stockObj.CtnStat = string.Join(' ', ctnAllList.Select(c => c.CtnAll + "*" + c.CTNNUM)); // 总箱数 stockObj.TotalCtns = ctnAllList.Sum(x => x.CTNNUM); // 订舱引用表主键与订舱主表主键 var lstAllocKeyList = await tenantDb.Queryable() //.Filter(null, true) .Where(x => !x.Deleted && slotBaseIdList.Contains(x.BookingSlotId)) .Select(x => new { x.Id, x.BookingSlotId }) .ToListAsync(); // 如果舱位未被引用过,可以直接确定库存 if (!lstAllocKeyList.Any()) { // 已使用舱位数 stockObj.UseNum = 0; // 已使用的箱型箱量 stockObj.UseCtnStat = ""; // 已使用的箱数 stockObj.UseCtnsNum = 0; // 剩余的箱型箱量 stockObj.RemainCtnStat = stockObj.CtnStat; // 剩余箱数 stockObj.RemainCtnsNum = stockObj.TotalCtns; } else { // 已使用舱位数 //stockObj.USE_NUM = lstAllocKeyList.DistinctBy(x => x.BOOKING_SLOT_ID).Count(); // 订舱引用表主键列表 var allocIdList = lstAllocKeyList.Select(x => x.Id).ToList(); var allocSlotIdList = lstAllocKeyList.Select(x => x.BookingSlotId).Distinct().ToList(); var userCtnNumList = await tenantDb.Queryable().Filter(null, true) .Where(x => !x.Deleted && allocIdList.Contains(x.SlotAllocId)) .GroupBy(x => x.SlotAllocId) .Select(x => new { x.SlotAllocId, CTNNUM = SqlFunc.AggregateSum(x.CtnNum) }).ToListAsync(); var hasCtnNumList = await tenantDb.Queryable().Filter(null, true) .Where(x => !x.Deleted && allocSlotIdList.Contains(x.SlotId)) .GroupBy(x => x.SlotId) .Select(x => new { x.SlotId, CTNNUM = SqlFunc.AggregateSum(x.CtnNum) }) .ToListAsync(); var useNum = 0; foreach (long slotId in allocSlotIdList) { List temp1 = lstAllocKeyList.Where(x => x.BookingSlotId == slotId).Select(x => x.Id).ToList(); var userNum = userCtnNumList.Where(x => temp1.Contains(x.SlotAllocId)).Sum(x => x.CTNNUM); var hasNum = hasCtnNumList.Where(x => x.SlotId == slotId).Sum(x => x.CTNNUM); if (userNum >= hasNum) { useNum++; } } // 已使用舱位数 stockObj.UseNum = useNum; // 已使用的箱型箱量 var userCtnList = await tenantDb.Queryable() .Filter(null, true) .Where(x => !x.Deleted && allocIdList.Contains(x.SlotAllocId)) .GroupBy(x => x.CtnAll) .Select(x => new { x.CtnAll, CTNNUM = SqlFunc.AggregateSum(x.CtnNum) }).ToListAsync(); stockObj.UseCtnStat = string.Join(' ', userCtnList.Select(c => c.CtnAll + "*" + c.CTNNUM)); // 已使用的箱数 stockObj.UseCtnsNum = userCtnList.Sum(x => x.CTNNUM); // 剩余的箱型箱量 Dictionary remainCtnList = new(ctnAllList.Count); foreach (var item in ctnAllList) { var useItem = userCtnList.FirstOrDefault(x => x.CtnAll == item.CtnAll); if (useItem == null) { remainCtnList.Add(item.CtnAll, item.CTNNUM); } else { int remainCtnNum = item.CTNNUM - useItem.CTNNUM; if (remainCtnNum > 0) { remainCtnList.Add(item.CtnAll, remainCtnNum); } } } stockObj.RemainCtnStat = string.Join(' ', remainCtnList.Select(x => x.Key + "*" + x.Value)); // 剩余箱数 stockObj.RemainCtnsNum = stockObj.TotalCtns - stockObj.UseCtnsNum; } if (isInsert) { await tenantDb.Insertable(stockObj).ExecuteCommandAsync(); } else { await tenantDb.Updateable(stockObj).ExecuteCommandAsync(); } return DataResult.Success(string.Empty); } #endregion #region 重新计算某租户下面所有的库存 /// /// 重新计算某租户下面所有的库存 /// /// public async Task RefreshAllStock() { var tenantDb = saasService.GetBizDbScopeById(user.TenantId); var n = await tenantDb.Deleteable().ExecuteCommandAsync(); var group = await tenantDb.Queryable() .Where(x => x.Deleted == false) .GroupBy(x => new { x.Vessel, x.Voyno, x.CarrierCode, x.ContractNo, x.BookingSlotType, x.PortLoadCode, x.PortDischargeCode, }).Select(x => new { x.Vessel, x.Voyno, x.CarrierCode, x.ContractNo, x.BookingSlotType, x.PortLoadCode, x.PortDischargeCode, }).ToListAsync(); foreach (var item in group) { BookingSlotStockUpdateModel model = new BookingSlotStockUpdateModel { Vessel = item.Vessel, Voyno = item.Voyno, CarrierCode = item.CarrierCode, ContractNo = item.ContractNo, BookingSlotType = item.BookingSlotType, PortLoadId = item.PortLoadCode, PortDischargeId = item.PortDischargeCode, }; await BookingSlotStock(model); } } #endregion } }