using Admin.NET.Application.CommonHelper; using Admin.NET.Application.Entity; using Furion.DatabaseAccessor; namespace Admin.NET.Application; /// /// pda组盘、解绑服务 /// [ApiDescriptionSettings(ApplicationConst.PdaOperationsGroup, Order = 100)] public class WmsGroupDiskService : IDynamicApiController, ITransient { private readonly SqlSugarRepository _wmsPlaceRep; private readonly SqlSugarRepository _v_wms_containerRep; private readonly SqlSugarRepository _wmsStockQuanRep; private readonly SqlSugarRepository _WmsContainerRep; private readonly SqlSugarRepository _repWmsContainerPlaceRep; private readonly SqlSugarRepository _wmsMaterialRep; private readonly SqlSugarRepository _wmsContainerPackagingRep; private readonly SqlSugarRepository _v_wms_stock_quanRep; private readonly SqlSugarRepository _wmsLogActionRep; private readonly SqlSugarRepository _wmsRecordTransRep; private readonly SqlSugarRepository _wmsBaseBusinessTypeRep; private readonly SqlSugarRepository _wmsAreaRep; public WmsGroupDiskService( SqlSugarRepository wmsPlaceRep, SqlSugarRepository v_wms_containerRep, SqlSugarRepository wmsStockQuanRep, SqlSugarRepository wmsContainerRep, SqlSugarRepository repWmsContainerPlaceRep, SqlSugarRepository wmsMaterialRep, SqlSugarRepository wmsContainerPackagingRep, SqlSugarRepository v_wms_stock_quanRep, SqlSugarRepository wmsLogActionRep, SqlSugarRepository wmsRecordTransRep, SqlSugarRepository wmsBaseBusinessTypeRep, SqlSugarRepository wmsAreaRep ) { _wmsPlaceRep = wmsPlaceRep; _v_wms_containerRep = v_wms_containerRep; _wmsStockQuanRep = wmsStockQuanRep; _WmsContainerRep = wmsContainerRep; _repWmsContainerPlaceRep = repWmsContainerPlaceRep; _wmsMaterialRep = wmsMaterialRep; _wmsContainerPackagingRep = wmsContainerPackagingRep; _v_wms_stock_quanRep = v_wms_stock_quanRep; _wmsLogActionRep = wmsLogActionRep; _wmsRecordTransRep = wmsRecordTransRep; _wmsBaseBusinessTypeRep = wmsBaseBusinessTypeRep; _wmsAreaRep = wmsAreaRep; } /// /// pda组盘查询-不分页查询容器上的物料-扫容器号 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "PdaContainerWithMaterial")] [Description("wmsGroupDisk/PdaContainerWithMaterial")] public async Task> PdaContainerWithMaterial([FromQuery] DiyWmsGroupDiskInput input) { var WmsContainerItem = await _WmsContainerRep.GetFirstAsync(w => w.ContainerCode == input.ContainerCode && w.IsDelete == false); if (WmsContainerItem == null) { throw Oops.Oh($"容器编号{input.ContainerCode}不存在!"); } if (WmsContainerItem.IsDisabled == true) { throw Oops.Oh($"容器编号{input.ContainerCode}不可用!"); } if (WmsContainerItem.IsVirtually == true) { throw Oops.Oh($"容器编号{input.ContainerCode}为虚拟状态!"); } //容器必须有库位关系才能组盘 去pda库位绑定中 进行绑定 var entityWmsContainerPlace = await _repWmsContainerPlaceRep.GetFirstAsync(u => u.ContainerCode == input.ContainerCode); ContainerPlaceHelper.ValidateContainerPlaceForGroupDisk(entityWmsContainerPlace, input.ContainerCode); //组盘时,容器必须不在立体库上 有料容器 var StockContainer = await _wmsStockQuanRep.GetFirstAsync(w => w.ContainerCode == input.ContainerCode); if (input.ActionType == 0) { ////绑定 //if (StockContainer != null && StockContainer.StockStatus == StockStatusEnum.待上架) //{ // throw Oops.Oh($"容器编号{input.ContainerCode}物料{StockContainer.MaterialCode}库存状态是{StockStatusEnum.待上架.GetDescription()}!"); //} } else { ////解绑 //if (StockContainer != null && StockContainer.StockStatus != StockStatusEnum.待上架) //{ // throw Oops.Oh($"容器编号{input.ContainerCode}物料{StockContainer.MaterialCode}库存状态不是{StockStatusEnum.待上架.GetDescription()}!"); //} } ////主动适配 空容器垛查询的问题 【Editby shaocx,2024-07-27】 //var emptyContainer = ""; //var v_wms_stock_quan_emptyCointer = await _v_wms_stock_quanRep.GetFirstAsync(w => w.SNCode == input.ContainerCode); //if (v_wms_stock_quan_emptyCointer != null) //{//说明是 空容器物料 // emptyContainer = v_wms_stock_quan_emptyCointer.ContainerCode; //} var query = _wmsStockQuanRep.AsQueryable() //.Where(u => u.ContainerCode.Contains(input.ContainerCode.Trim()) || (!string.IsNullOrEmpty(emptyContainer) && u.ContainerCode.Contains(emptyContainer))) .Where(u => u.ContainerCode.Contains(input.ContainerCode.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.SNCode), u => u.SNCode == input.SNCode.Trim()) //.WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), u => u.MaterialCode.Contains(input.MaterialCode.Trim())) .Select(); var restList = await query.OrderBuilder(input, "", "Id").Select().ToListAsync(); //注意:要单独过滤掉 空容器物料 【Editby shaocx,2024-07-28】 restList = restList.Where(x => x.SNCode != input.ContainerCode).ToList(); return restList; } /// /// pda组盘查询-不分页查询跟踪码对应的物料-扫跟踪码 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "PdaBindListForSNCode")] [Description("wmsGroupDisk/PdaBindListForSNCode")] public async Task PdaBindListForSNCode([FromQuery] DiyWmsGroupDiskBaseInput input) { PdaBindListForSNCodeOutput res = new PdaBindListForSNCodeOutput() { stockQuanOutput = null, ValidateFailReason = "", ValidateResult = true }; if (input.SNCode == null) { throw Oops.Oh($"物料跟踪码不能为空!"); } if (input.ContainerCode == null) { throw Oops.Oh($"容器号不能为空!"); } var toContainerCode = await ContainerHelper.GetWmsContainer(_WmsContainerRep, input.ContainerCode); if (toContainerCode.IsVirtually == true) { throw Oops.Oh($"容器号{input.ContainerCode}是虚拟容器,不允许操作!"); } var query = _wmsStockQuanRep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.SNCode), u => u.SNCode == input.SNCode.Trim()) .Select(); var allList = await query.Select().ToListAsync(); if (allList?.Count == 0) { throw Oops.Oh($"跟踪码{input.SNCode}没有找到库存!"); } //检验库存的容器是否跟组盘的容器一致 if (allList.Count() > 1) { throw Oops.Oh($"该跟踪码{input.SNCode}存在多个库存!"); } else if (allList.Count() == 1) { var dbObj = allList.First(); if (string.IsNullOrEmpty(dbObj.ContainerCode)) { throw Oops.Oh($"跟踪码{dbObj.SNCode}绑定的容器号为空!"); } var orgContainerCode = await ContainerHelper.GetWmsContainer(_WmsContainerRep, dbObj.ContainerCode); if (orgContainerCode.IsVirtually != true && dbObj.ContainerCode != input.ContainerCode) { res.ValidateResult = false; res.ValidateFailReason = $"跟踪码{input.SNCode}当前在容器{dbObj.ContainerCode}中,是否确认要将该物料继续组盘到新容器{input.ContainerCode}中"; } } res.stockQuanOutput = allList.First(); return res; } /// /// pda物料或空容器组盘 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "PdaBindUpdate")] [Description("wmsGroupDisk/PdaBindUpdate")] [UnitOfWork] public async Task PdaBindUpdate(WmsGroupDiskBaseInput input) { if (input is null) { throw Oops.Oh("输入参数不能为空"); } if (input.Flag <= 0 || input.Flag > 3) { throw Oops.Oh("标记不正确"); } if (input.orderDetails is null || input.orderDetails.Count == 0) { throw Oops.Oh("明细不能为空"); } var errMsgPre = input.Flag == 1 ? "跟踪码" : "容器号"; foreach (var item in input.orderDetails) { if (string.IsNullOrWhiteSpace(item.SNCode)) { throw Oops.Oh($"要组盘的{errMsgPre}不能为空"); } } if (input.orderDetails.Select(v => v.SNCode).Distinct().Count() != input.orderDetails.Count()) { throw Oops.Oh($"要组盘的{errMsgPre}不能重复"); } var toWmsContainer = await ContainerHelper.GetWmsContainer(_WmsContainerRep, input.ContainerCode); if (toWmsContainer.IsDisabled == true) { throw Oops.Oh($"容器编号{input.ContainerCode}不可用!"); } if (toWmsContainer.IsVirtually == true) { throw Oops.Oh($"容器编号{input.ContainerCode}为虚拟状态!"); } #region 验证 if (input.Flag == 1) { } else { var querySNCodeList = input.orderDetails.Select(x => x.SNCode).ToList(); var entityWmsContainerList = await _WmsContainerRep.GetListAsync(u => querySNCodeList.Contains(u.ContainerCode)); if (entityWmsContainerList.Count > 0 && entityWmsContainerList.Select(u => u.ContainerTypeName).Distinct().Count() > 1) { throw Oops.Oh($"不同容器类型的容器不能组盘!"); } } #endregion //容器必须有库位关系才能组盘 去pda库位绑定中 进行绑定 var entityWmsContainerPlace = await _repWmsContainerPlaceRep.GetFirstAsync(u => u.ContainerCode == input.ContainerCode); ContainerPlaceHelper.ValidateContainerPlaceForGroupDisk(entityWmsContainerPlace, input.ContainerCode); //update by liuwq 20240729 //获取目标库位 var toPlace = await BaseInfoHelper.GetPlace(entityWmsContainerPlace.PlaceCode, _wmsPlaceRep); List addWmsStockQuanList = new List();//新增库存列表 List updateWmsStockQuanList = new List();//更新库存列表 List deleteWmsStockQuanList = new List();//要删除的库存列表 //新增事务记录 List addWmsRecordTransList = new List(); //新增操作履历 List addWmsLogActionList = new List(); string recordTransRemarks = string.Empty; BusinessTypeEnum businessTypeEnum = BusinessTypeEnum.物料组盘; // 获取业务类型 var wmsBaseBusinessType = BusinessTypeHelper.GetBusinessTypeInfoFromDB((int)businessTypeEnum, _wmsBaseBusinessTypeRep); //查询该容器中已有的库存和前端传过来的库存汇总 List allContainerStockQuanViewList = await _v_wms_stock_quanRep.AsQueryable() .Where(x => x.ContainerCode == toWmsContainer.ContainerCode || input.orderDetails.Select(v => v.SNCode).Contains(x.SNCode)) .Where(u => u.IsDelete == false).Select() .ToListAsync(); List dbStockQuanList = await _wmsStockQuanRep.AsQueryable().Where(x => allContainerStockQuanViewList.Select(v => v.Id).Contains(x.Id)).ToListAsync(); //寻找前端传过来,但是不在库存中的 var noStock_SnList = input.orderDetails.Where(x => !allContainerStockQuanViewList.Select(y => y.SNCode).ToList().Contains(x.SNCode)).ToList(); if (input.Flag == 1) { if (noStock_SnList?.Count > 0) { throw Oops.Oh($"跟踪码{noStock_SnList.First().SNCode}不在库存中,不可组盘"); } //查询下,如果这个托盘有库存数据,就要清理下,因为可能在空容器组盘时会有遗留的 【Editby shaocx,2024-07-28】 var delObjList = dbStockQuanList.Where(x => x.SNCode == input.ContainerCode).ToList(); if (delObjList?.Count > 0) { deleteWmsStockQuanList.AddRange(delObjList); } } else {//空容器组盘,新增库存 foreach (var item in noStock_SnList) { //新增的组盘的物料一定是容器类型的物料 var itemAdd = item.Adapt(); StockQuanHelper.UpdateStockStatus(itemAdd, StockStatusEnum.待上架); itemAdd.Quantity = 1; itemAdd.QCStatus = StockQcStatusEnum.合格; itemAdd.QCStatusName = StockQcStatusEnum.合格.ToString(); itemAdd.SNCode = item.SNCode; itemAdd.MaterialCode = ApplicationConst.DefaultContinerMaterialCode; itemAdd.MaterialName = ApplicationConst.DefaultContinerMaterialName; itemAdd.ContainerCode = toWmsContainer.ContainerCode; itemAdd.ContainerId = toWmsContainer.Id; addWmsStockQuanList.Add(itemAdd); #region 转移库存添加事务、操作日志 recordTransRemarks = $"容器{toWmsContainer.ContainerCode},空容器号{item.SNCode}"; WmsRecordTrans addWmsRecordTrans = await CreateRecordTransInfoForZP(true, wmsBaseBusinessType, null, itemAdd, toPlace, "");//备注暂时为空 addWmsRecordTransList.Add(addWmsRecordTrans); //新增操作日志 WmsLogAction wareActionLog = LogActionHelper.CreateWmsLogAction(itemAdd.Id, recordTransRemarks, $"转移跟踪码{item.SNCode}库存"); addWmsLogActionList.Add(wareActionLog); #endregion } } // update by liuwq 20240717 //校验物料容器类型是否跟绑定的容器类型一致 if (input.Flag == 1) { await StockQuanHelper.CheckContainerType(_wmsMaterialRep, _wmsContainerPackagingRep, toWmsContainer, dbStockQuanList); } //更新容器编号 foreach (var item in dbStockQuanList) { if (item.ContainerCode != input.ContainerCode) { var itemAdd = item.Adapt(); itemAdd.ContainerCode = toWmsContainer.ContainerCode; itemAdd.ContainerId = toWmsContainer.Id; updateWmsStockQuanList.Add(itemAdd); #region 转移库存添加事务、操作日志 recordTransRemarks = $"容器{toWmsContainer.ContainerCode}跟踪码{item.SNCode}"; //获取源库存信息 var sourceStockView = StockQuanHelper.GetVMmsStockQuan(allContainerStockQuanViewList, item.SNCode); WmsRecordTrans addWmsRecordTrans = await CreateRecordTransInfoForZP(false, wmsBaseBusinessType, sourceStockView, itemAdd, toPlace, "");//备注暂时为空 addWmsRecordTransList.Add(addWmsRecordTrans); //新增操作日志 WmsLogAction wareActionLog = LogActionHelper.CreateWmsLogAction(item.Id, recordTransRemarks, $"转移跟踪码{item.SNCode}库存"); addWmsLogActionList.Add(wareActionLog); #endregion } } if (updateWmsStockQuanList.Count == 0 && addWmsStockQuanList.Count == 0) { throw Oops.Oh("组盘没有可处理的数据!"); } //累计容器使用次数,组盘一次,使用次数加1 update by liuwq 20240614 toWmsContainer.UsageCount++; try { if (updateWmsStockQuanList.Count > 0) { await _wmsStockQuanRep.UpdateRangeAsync(updateWmsStockQuanList); //1更新库存 } await _wmsStockQuanRep.InsertRangeAsync(addWmsStockQuanList);//新增库存 if (deleteWmsStockQuanList?.Count > 0) { await _wmsStockQuanRep.DeleteAsync(deleteWmsStockQuanList);//删除库存 } await _WmsContainerRep.UpdateAsync(toWmsContainer); //更新容器 update by liuwq 20240614 //新增事务记录、收货记录、操作日志 await _wmsLogActionRep.InsertRangeAsync(addWmsLogActionList); await _wmsRecordTransRep.InsertRangeAsync(addWmsRecordTransList); List newStockQuans = new List(); newStockQuans.AddRange(dbStockQuanList); newStockQuans.AddRange(addWmsStockQuanList); return new PdaBindUpdateOutput() { StockQuans = newStockQuans }; } catch { throw; } } /// /// pda物料或空容器解绑 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "PdaUnBindUpdate")] [Description("wmsGroupDisk/PdaUnBindUpdate")] public async Task PdaUnBindUpdate(WmsGroupDiskBaseInput input) { //新增事务记录 List addWmsRecordTransList = new List(); string recordTransRemarks = string.Empty; MoveTypeEnum moveType = MoveTypeEnum.其他; BusinessTypeEnum businessTypeEnum = BusinessTypeEnum.物料解绑; var WmsBaseBusinessType = BusinessTypeHelper.GetBusinessTypeInfoFromDB((int)businessTypeEnum, _wmsBaseBusinessTypeRep); if (input is null) { throw Oops.Oh("输入参数不能为空"); } if (input.orderDetails is null || input.orderDetails.Count == 0) { throw Oops.Oh("明细不能为空"); } if (input.Flag != 3 && input.Flag != 4) { throw Oops.Oh("标记不正确"); } if (input.Flag == 4) { businessTypeEnum = BusinessTypeEnum.空容器解绑; } var WmsContainerItem = await _WmsContainerRep.GetFirstAsync(w => w.ContainerCode == input.ContainerCode && w.IsDelete == false); if (WmsContainerItem == null) { throw Oops.Oh($"容器编号{input.ContainerCode}不存在!"); } if (WmsContainerItem.IsDisabled == true) { throw Oops.Oh($"容器编号{input.ContainerCode}不可用!"); } if (WmsContainerItem.IsVirtually == true) { throw Oops.Oh($"容器编号{input.ContainerCode}为虚拟状态!"); } //var dbOrder = await _wmsStockQuanRep.GetFirstAsync(w => w.ContainerCode == input.ContainerCode); //if (dbOrder == null) //{ // throw Oops.Oh($"容器编号{input.ContainerCode}的库存不存在"); //} //update by liuwq 20240729 var all_v_wms_stock_quan = await _v_wms_stock_quanRep.GetListAsync(w => w.ContainerCode == input.ContainerCode || w.SNCode == input.ContainerCode); if (all_v_wms_stock_quan?.Count <= 0) { throw Oops.Oh($"容器编号{input.ContainerCode}上没有库存!"); } var v_wms_stock_quan = all_v_wms_stock_quan.FirstOrDefault(w => w.ContainerCode == input.ContainerCode || w.SNCode == input.ContainerCode); if (v_wms_stock_quan == null) { throw Oops.Oh($"容器编号{input.ContainerCode}上没有库存!"); } var dibu_ContainerCode = "";//底部容器号 if (input.Flag == 3) { dibu_ContainerCode = input.ContainerCode; } else { dibu_ContainerCode = v_wms_stock_quan.ContainerCode; } List db_wmsStockQuanList = null; if (input.Flag == 3) { db_wmsStockQuanList = await _wmsStockQuanRep.AsQueryable() .Where(x => x.ContainerCode == v_wms_stock_quan.ContainerCode) .Where(u => u.IsDelete == false) .Select() .ToListAsync(); } else { db_wmsStockQuanList = await _wmsStockQuanRep.AsQueryable() .Where(x => x.ContainerCode == dibu_ContainerCode) .Where(u => u.IsDelete == false) .Select() .ToListAsync(); //校验,如果把底部容器也移除了,就提示错误 if (input.orderDetails.Any(p => p.SNCode == dibu_ContainerCode)) { throw Oops.Oh($"容器编号{dibu_ContainerCode}是该空容器垛的底部承载容器,不允许在空容器中解绑,如想解绑,需要操作【库位解绑】!"); } } ZtPlaceAndContainerOutput ztPlaceAndContainerOutput = await StockQuanHelper.VerifyZTPlaceAndContainerIsExist(_wmsPlaceRep, _WmsContainerRep, v_wms_stock_quan.AreaCode); var toWmsContainer = ztPlaceAndContainerOutput.ZtContainer; //寻找更新单据明细的物料 var updateList = db_wmsStockQuanList.Where(x => input.orderDetails.Any(p => p.SNCode == x.SNCode && p.ContainerCode == x.ContainerCode)).ToList(); //ly0814 空容器解绑 根据跟踪码寻找所有容器 var entityWmsContainerList = new List(); if (input.Flag == 4) { var querySNCodeList = input.orderDetails.Select(x => x.SNCode).ToList(); entityWmsContainerList = await _WmsContainerRep.GetListAsync(u => querySNCodeList.Contains(u.ContainerCode)); if (entityWmsContainerList.Count <= 0) { throw Oops.Oh($"传入的容器编号不存在!"); } } List addWmsContainerMaterial = new List(); foreach (var item in updateList) { var itemAdd = item.Adapt(); //解绑 - 解绑后的物料所在容器是该库区的在途容器 【Editby shaocx,2024-07-27】 itemAdd.ContainerCode = ztPlaceAndContainerOutput.ZtContainer.ContainerCode; itemAdd.ContainerId = ztPlaceAndContainerOutput.ZtContainer.Id; addWmsContainerMaterial.Add(itemAdd); //记录事物日志 recordTransRemarks = $"容器{toWmsContainer.ContainerCode}跟踪码{item.SNCode}"; //获取源库存信息 var sourceStockView = StockQuanHelper.GetVMmsStockQuan(all_v_wms_stock_quan, item.SNCode); WmsRecordTrans addWmsRecordTrans = await CreateRecordTransInfoForZP(false, WmsBaseBusinessType, sourceStockView, item, ztPlaceAndContainerOutput.ZtPlace, "");//备注暂时为空 //WmsRecordTrans addWmsRecordTrans = await CreateRecordTransInfoForZP(false, _v_wms_containerRep, item, moveType, businessTypeEnum, itemAdd, sourceContainer, toWmsContainer, recordTransRemarks); addWmsRecordTransList.Add(addWmsRecordTrans); } if (addWmsContainerMaterial == null || addWmsContainerMaterial.Count == 0) { throw Oops.Oh("没有要更新的数据!"); } try { await _wmsStockQuanRep.AsTenant().BeginTranAsync(); if (addWmsContainerMaterial.Count > 0) { await _wmsStockQuanRep.UpdateRangeAsync(addWmsContainerMaterial); //1更新库存表 } // 1、事务日志 await _wmsRecordTransRep.InsertRangeAsync(addWmsRecordTransList); //2、操作日志 await _wmsStockQuanRep.AsTenant().CommitTranAsync(); } catch { await _wmsStockQuanRep.AsTenant().RollbackTranAsync(); throw; } } /// /// PDA组盘创建事务记录入参方法 /// /// /// /// /// /// /// /// /// private static async Task CreateRecordTransInfoForZP( bool isEmptyConinter, WmsBaseBusinessType wmsBaseBusinessType, v_wms_stock_quan sourceStockView, WmsStockQuan toStockModel, WmsBasePlace toPlace , string remark) { //组盘 关联单号 行号 都是空值 TransferOtherDetail transferOtherDetail = new TransferOtherDetail() { RelationNo = string.Empty, RelationNoLineNumber = string.Empty, Remarks = remark }; //源信息 //新增的库存源信息都是空 if (isEmptyConinter) { sourceStockView = null; } //新增事务记录 WmsRecordTrans addWmsRecordTrans = LogRecordHelper.CreateWmsRecordTrans(wmsBaseBusinessType, sourceStockView, toStockModel, toPlace, transferOtherDetail); return addWmsRecordTrans; } }