using Admin.NET.Core.Service; using Admin.NET.Application.Entity; using Microsoft.AspNetCore.Http; using System.Data; using System.Web; using System.Text; using Admin.NET.Application.CommonHelper; using System.Linq.Expressions; using Furion.LinqBuilder; using OracleInternal.Sharding; using System; using Furion.DatabaseAccessor; namespace Admin.NET.Application; /// /// 盘点单明细服务 /// [ApiDescriptionSettings(ApplicationConst.WmsInventoryCheckGroupName, Order = 100)] public class WmsInventoryCheckOrderDetailsService : IDynamicApiController, ITransient { private readonly SqlSugarRepository _wmsBaseBusinessTypeRep; private readonly SqlSugarRepository _wmsInventoryCheckOrderDetailsRep; private readonly SqlSugarRepository _wmsInventoryCheckOrderRep; private readonly SqlSugarRepository _wmsInventoryCheckRangeRep; private readonly SqlSugarRepository _wmsInventoryCheckRecord; private readonly SqlSugarRepository _wmsAreaRep; private readonly SqlSugarRepository _wmsPlaceRep; private readonly SqlSugarRepository _wmsContainerRep; private readonly SqlSugarRepository _wmsContainerPlaceRep; private readonly SqlSugarRepository _wmsStockQuanRep; private readonly SqlSugarRepository _wmsRecordTransRep; private readonly SqlSugarRepository _wareActionLogRep; private readonly SqlSugarRepository _v_wms_stock_quanRep; private readonly SqlSugarRepository _wmsTaskRep; private readonly SqlSugarRepository _wmsStockQuanZeroRep; private readonly UserManager _userManager; private readonly WmsStockQuanService _wmsStockQuanService; private readonly SqlSugarRepository _v_wms_inventory_check_order_details_orderRep; public WmsInventoryCheckOrderDetailsService( WmsStockQuanService wmsStockQuanService, SqlSugarRepository wmsBaseBusinessTypeRep, SqlSugarRepository wmsInventoryCheckOrderDetailsRep, SqlSugarRepository wmsInventoryCheckOrderRep, SqlSugarRepository wmsInventoryCheckRangeRep, SqlSugarRepository wmsInventoryCheckRecord, SqlSugarRepository wmsAreaRep, SqlSugarRepository wmsPlaceRep, SqlSugarRepository wmsContainerPlaceRep, SqlSugarRepository wmsContainerRep, SqlSugarRepository wmsStockQuanRep, SqlSugarRepository wmsRecordTransRep, SqlSugarRepository wareActionLogRep, SqlSugarRepository v_wms_stock_quanRep, SqlSugarRepository wmsTaskRep, SqlSugarRepository wmsStockQuanZeroRep, UserManager userManager, SqlSugarRepository v_wms_inventory_check_order_details_orderRep ) { _wmsStockQuanService = wmsStockQuanService; _wmsBaseBusinessTypeRep = wmsBaseBusinessTypeRep; _wmsInventoryCheckOrderDetailsRep = wmsInventoryCheckOrderDetailsRep; _wmsInventoryCheckOrderRep = wmsInventoryCheckOrderRep; _wmsInventoryCheckRangeRep = wmsInventoryCheckRangeRep; _wmsInventoryCheckRecord = wmsInventoryCheckRecord; _wmsAreaRep = wmsAreaRep; _wmsPlaceRep = wmsPlaceRep; _wmsContainerPlaceRep = wmsContainerPlaceRep; _wmsContainerRep = wmsContainerRep; _wmsStockQuanRep = wmsStockQuanRep; _wmsRecordTransRep = wmsRecordTransRep; _wareActionLogRep = wareActionLogRep; _v_wms_stock_quanRep = v_wms_stock_quanRep; _wmsTaskRep = wmsTaskRep; _wmsStockQuanZeroRep = wmsStockQuanZeroRep; _userManager = userManager; _v_wms_inventory_check_order_details_orderRep = v_wms_inventory_check_order_details_orderRep; } /// /// 分页查询盘点单明细 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Page")] [Description("WmsInventoryCheckOrderDetails/Page")] public async Task> Page(WmsInventoryCheckOrderDetailsInput input) { var query = CommonPageFilter(input); return await query.OrderBuilder(input, "", "Id").ToPagedListAsync(input.Page, input.PageSize); } /// /// 分页查询盘点单明细 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "PDAInventoryQueryAndInsert")] [Description("WmsInventoryCheckOrderDetails/PDAInventoryQueryAndInsert")] [UnitOfWork] public async Task> PDAInventoryQueryAndInsert([FromQuery] WmsInventoryCheckOrderDetailsInput input) { if (input.OrderNo == null) throw Oops.Oh("必须传入盘点单号!"); if (string.IsNullOrEmpty(input.ContainerCodeAndPlaceCodeForpda) && string.IsNullOrEmpty(input.SNCode)) { return null; } var InventoryDetailsModel = await _wmsInventoryCheckOrderDetailsRep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.OrderNo), u => u.OrderNo.Contains(input.OrderNo.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.SNCode), u => u.SNCode.Contains(input.SNCode.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.ContainerCodeAndPlaceCodeForpda), u => u.ContainerCode.Contains(input.ContainerCodeAndPlaceCodeForpda.Trim()) || u.PlaceCode.Contains(input.ContainerCodeAndPlaceCodeForpda.Trim()) ).FirstAsync(); if (InventoryDetailsModel == null) { var orderMain = await _wmsInventoryCheckOrderRep.AsQueryable().FirstAsync(p => p.OrderNo == input.OrderNo); if (orderMain == null) throw Oops.Oh("当前盘点单未找到"); //设置 if (string.IsNullOrEmpty(input.ContainerCodeAndPlaceCodeForpda)) { throw Oops.Oh("请扫描容器编号或库位"); } var containerPlaceModel = await _wmsContainerPlaceRep.GetFirstAsync(p => (p.ContainerCode == input.ContainerCodeAndPlaceCodeForpda || p.PlaceCode == input.ContainerCodeAndPlaceCodeForpda)); if (containerPlaceModel == null) { throw Oops.Oh($"容器编号或库位'{input.ContainerCodeAndPlaceCodeForpda}'没有找到库位和容器绑定关系"); } //查询库区 var placeModel = await _wmsPlaceRep.GetFirstAsync(p => p.PlaceCode == containerPlaceModel.PlaceCode); if (placeModel == null) throw Oops.Oh($"库位{containerPlaceModel.PlaceCode}没有找到信息"); if (string.IsNullOrEmpty(input.SNCode)) { return null; } var materialModel = await _v_wms_stock_quanRep.AsQueryable().FirstAsync(p => p.SNCode == input.SNCode); if (materialModel == null) { var zeroModel = await _wmsStockQuanService.GetStockBySnCodeIncludeDelete(input.SNCode); if (zeroModel == null) throw Oops.Oh("未找到当前跟踪码" + input.SNCode + "库存信息"); var newInventoryCheckDetailsModel = new WmsInventoryCheckOrderDetails() { OrderId = orderMain.Id, OrderNo = input.OrderNo, SNCode = input.SNCode, ContainerCode = containerPlaceModel.ContainerCode, PlaceCode = containerPlaceModel.PlaceCode, PlaceName = containerPlaceModel.PlaceName, AreaCode = placeModel.AreaCode, AreaName = placeModel.AreaName, Batch = zeroModel.Batch, MaterialCode = zeroModel.MaterialCode, MaterialName = zeroModel.MaterialName, Quantity = 0, CheckStatus = CheckStatusEnum.盘点中, CheckStatusName = CheckStatusEnum.盘点中.GetDescription(), CheckResult = CheckResultEnum.未盘, CheckResultName = CheckResultEnum.未盘.GetDescription(), CheckCount = 0, CheckOperatorClassify = CheckOperatorClassifyEnum.初盘, CheckOperatorClassifyName = CheckOperatorClassifyEnum.初盘.GetDescription() }; await _wmsInventoryCheckOrderDetailsRep.InsertAsync(newInventoryCheckDetailsModel); } else { var newInventoryCheckDetailsModel = new WmsInventoryCheckOrderDetails() { OrderId = orderMain.Id, OrderNo = input.OrderNo, SNCode = input.SNCode, ContainerCode = containerPlaceModel.ContainerCode, AreaCode = placeModel.AreaCode, AreaName = placeModel.AreaName, PlaceCode = containerPlaceModel.PlaceCode, PlaceName = containerPlaceModel.PlaceName, Batch = materialModel.Batch, MaterialCode = materialModel.MaterialCode, MaterialName = materialModel.MaterialName, Quantity = 0, CheckStatus = CheckStatusEnum.盘点中, CheckStatusName = CheckStatusEnum.盘点中.GetDescription(), CheckResult = CheckResultEnum.未盘, CheckResultName = CheckResultEnum.未盘.GetDescription(), CheckCount = 0, CheckOperatorClassify = CheckOperatorClassifyEnum.初盘, CheckOperatorClassifyName = CheckOperatorClassifyEnum.初盘.GetDescription() }; await _wmsInventoryCheckOrderDetailsRep.InsertAsync(newInventoryCheckDetailsModel); } input.SNCode = input.SNCode; var query = CommonPageFilter(input); return await query.OrderBuilder(input, "", "Id").ToPagedListAsync(input.Page, input.PageSize); } else { input.SNCode = InventoryDetailsModel.SNCode; input.OrderNo = InventoryDetailsModel.OrderNo; input.ContainerCode = null; input.ContainerCodeAndPlaceCodeForpda = null; var query = CommonPageFilter(input); return await query.OrderBuilder(input, "", "Id").ToPagedListAsync(input.Page, input.PageSize); } } /// /// 分页查询盘点单明细-pda下发 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "PageForPda")] [Description("WmsInventoryCheckOrderDetails/PageForPda")] public async Task> PageForPda(WmsInventoryCheckOrderDetailsInput input) { /* pda 盘点下发 - 二级明细 - 按照容器编号分组 */ var query = await _wmsInventoryCheckOrderDetailsRep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.OrderNo), u => u.OrderNo.Contains(input.OrderNo.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.ContainerCode), u => u.ContainerCode.Contains(input.ContainerCode.Trim())) .WhereIF(input.CheckStatus.HasValue, u => u.CheckStatus == input.CheckStatus) .WhereIF(input.CheckStatus.HasValue, u => u.CheckStatusName == input.CheckStatusName) .WhereIF(input.CheckResult.HasValue, u => u.CheckResult == input.CheckResult) .WhereIF(input.CheckOperatorClassify.HasValue, u => u.CheckOperatorClassify == input.CheckOperatorClassify) .Where(u => u.CheckStatus == CheckStatusEnum.未盘点) //初盘 复盘时 只显示未盘点 .Select().ToListAsync(); ; var newList = query.GroupBy(it => new { it.ContainerCode, it.OrderNo, it.CheckStatusName, it.CheckStatus }).Select(s => new { s.Key.ContainerCode, s.Key.OrderNo, s.Key.CheckStatusName, s.Key.CheckStatus }).ToList(); List resultList = newList.Adapt>(); var groupList = resultList.ToPagedList(input.Page, input.PageSize); return groupList; } /// /// 不分页查询盘点单明细 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "List")] [Description("WmsInventoryCheckOrderDetails/List")] public async Task> List([FromQuery] WmsInventoryCheckOrderDetailsInput input) { var query = CommonPageFilter(input); return await query.OrderBuilder(input, "", "Id").Select().ToListAsync(); } /// /// 增加盘点单明细 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Add")] [Description("WmsInventoryCheckOrderDetails/Add")] public async Task Add(AddWmsInventoryCheckOrderDetailsInput input) { var entity = input.Adapt(); //重复性验证 await CheckExist(entity); await _wmsInventoryCheckOrderDetailsRep.InsertAsync(entity); return entity.Id; } /// /// 初盘开启、复盘开启 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "StartInventoryCheck")] [Description("WmsInventoryCheckOrderDetails/StartInventoryCheck")] public async Task StartInventoryCheck(WmsStartInventoryCheckInput input) { /*1.根据盘点单据的ID,获取盘点单和盘点范围 *2.根据盘点范围获取所有库存信息、容器信息和库位信息 * 2.1库区+物料 获取要盘点的库存信息 * 2.2根据库存信息获取容器 *3.不判断库位是立体库或平库 * 整个容器的所有库存全部锁定,库存状态变为已冻结,赋值记录冻结前的库存状态 *4.创建盘点单据明细 *4 增加事务记录-业务类型:盘点冻结(未实现) *5 增加操作履历(未实现) * */ List upadteWmsStockQuanList = new List(); List addWmsRecordTransList = new List(); List addWmsLogActionList = new List(); List addWmsInventoryCheckOrderDetailsList = new List(); List updateWmsInventoryCheckOrderDetailsList = new List(); List updateWmsInventoryCheckOrderList = new List(); if (input.OrderId <= 0) { throw Oops.Oh("盘点单据ID不能为空!"); } if (!input.CheckOperatorClassify.HasValue) { throw Oops.Oh("盘点操作分类不能为空!"); } CheckOperatorClassifyEnum CheckOperatorClassify = (CheckOperatorClassifyEnum)input.CheckOperatorClassify; CheckStageEnum checkStage = CheckStageEnum.初盘开启; //判断是初盘还是复盘 if (CheckOperatorClassify == CheckOperatorClassifyEnum.复盘) { checkStage = CheckStageEnum.复盘开启; } //获取盘点单据 var inventoryCheckOrder = await _wmsInventoryCheckOrderRep.GetFirstAsync(u => u.Id == input.OrderId && u.IsDelete == false) ?? throw Oops.Oh("盘点单信息不存在!"); if (inventoryCheckOrder.CheckStage != CheckStageEnum.新建 && inventoryCheckOrder.CheckStage != CheckStageEnum.初盘已完成) { throw Oops.Oh($"盘点单状态是{inventoryCheckOrder.CheckStage.GetDescription()},不能操作!"); } List snCodeList = new List(); List check_v_wms_stock_quanList = null;//要盘点的库存视图 List checkOrderDetailsList = null; if (CheckOperatorClassify == CheckOperatorClassifyEnum.复盘) { //复盘开启获取可盘点库存校验 checkOrderDetailsList = await CheckForFP(input, inventoryCheckOrder, checkOrderDetailsList); //获取要盘点的库存视图-根据盘点库区的容器和盘点范围的物料获取盘点库存-包含库位信息、库区信息 check_v_wms_stock_quanList = await _v_wms_stock_quanRep.GetListAsync(u => checkOrderDetailsList.Select(s => s.SNCode).ToList().Contains(u.SNCode)); } else { check_v_wms_stock_quanList = await GetLastCheck_v_wms_stock_quanListForCP(inventoryCheckOrder, check_v_wms_stock_quanList); //没有获取到盘点库存 不创建盘点单明细,仍然让用户开启盘点 } // 校验盘点的容器是否有未完成调度任务的容器、盘点单 await CheckContainer(inventoryCheckOrder,_v_wms_inventory_check_order_details_orderRep, check_v_wms_stock_quanList); //最终可以盘点的容器 var lastCheckContainerCodeList = check_v_wms_stock_quanList.Select(s => s.ContainerCode).Distinct().ToList(); ////获取盘点容器上所有的库存详情-视图 var checkStockQuanViewList = await _v_wms_stock_quanRep.GetListAsync(u => lastCheckContainerCodeList.Contains(u.ContainerCode)); ////获取盘点容器上所有的库存信息-锁定库存用 var checkStockQuanList = await _wmsStockQuanRep.GetListAsync(u => lastCheckContainerCodeList.Contains(u.ContainerCode)); //获取库位相信 var placeCodeList = checkStockQuanViewList.Select(s => s.PlaceCode).Distinct().ToList(); var allPlaeList = await _wmsPlaceRep.GetListAsync(u => placeCodeList.Contains(u.PlaceCode) && u.IsDelete == false); // 获取业务类型 update by liuwq 2024 07 30 BusinessTypeEnum businessTypeEnum = BusinessTypeEnum.盘点冻结; var wmsBaseBusinessType = BusinessTypeHelper.GetBusinessTypeInfoFromDB((int)businessTypeEnum, _wmsBaseBusinessTypeRep); string remarks = $"{wmsBaseBusinessType.BusinessTypeName}"; //变更盘点单阶段 inventoryCheckOrder.CheckStage = checkStage; inventoryCheckOrder.CheckStageName = checkStage.GetDescription(); //循环库存创建盘点单据明细 //初盘新建盘点单据明细 foreach (var item in checkStockQuanList) { //获取库存详情-包含库位信息、库区信息 var viewStockQuan = checkStockQuanViewList.FirstOrDefault(f => f.SNCode.Equals(item.SNCode)); if (viewStockQuan == null) { throw Oops.Oh($"跟踪码{item.SNCode}库存信息不存在"); } //冻结库存 LockInfo freezeInfo = new LockInfo() { LockReason = businessTypeEnum.GetDescription(), LockTime = DateTime.Now, LockUser = _userManager.RealName,//登录人的真实姓名 LockStatus = LockStatusEnum.已锁定,// }; StockQuanHelper.UpdateStockLockStatus(item, freezeInfo); //添加冻结库存集合 upadteWmsStockQuanList.Add(item); //初盘创建盘点单据明细实体 if (CheckOperatorClassify == CheckOperatorClassifyEnum.初盘) { if (check_v_wms_stock_quanList.Select(x => x.MaterialCode).ToList().Contains(item.MaterialCode)) {//只有在本次盘点范围的物料才能创建盘点单明细 var entityDetails = new WmsInventoryCheckOrderDetails() { OrderId = inventoryCheckOrder.Id, OrderNo = inventoryCheckOrder.OrderNo, AreaCode = viewStockQuan.AreaCode, AreaName = viewStockQuan.AreaName, PlaceCode = viewStockQuan.PlaceCode, PlaceName = viewStockQuan.PlaceName, MaterialCode = item.MaterialCode, MaterialName = item.MaterialName, Quantity = item.Quantity, SNCode = item.SNCode, Batch = item.Batch, CheckOperatorClassify = CheckOperatorClassifyEnum.初盘, CheckOperatorClassifyName = CheckOperatorClassifyEnum.初盘.GetDescription(), CheckCount = 0, ContainerCode = item.ContainerCode, }; //盘点状态赋值 OrderHelper.UpdateInventoryCheckOrderDetailsCheckStatus(entityDetails, CheckStatusEnum.未盘点); //盘点结果赋值 OrderHelper.UpdateInventoryCheckOrderDetailsCheckResult(entityDetails, CheckResultEnum.未盘); //盘点操作分类 OrderHelper.UpdateInventoryCheckOrderDetailsCheckOperatorClassify(entityDetails, CheckOperatorClassifyEnum.初盘); //添加盘点单据明细集合 addWmsInventoryCheckOrderDetailsList.Add(entityDetails); } } #region 添加事务 #region 创建事务日志入参 //获取源库存信息 var sourceStockView = StockQuanHelper.GetVMmsStockQuan(checkStockQuanViewList, item.SNCode); //update by liuwq 20240730 //获取目标库位 //开启盘点库存没有变更库位,目标库位还是源库位 //调度任务改变库位到盘点区域库位,调度任务添加事务 var toPlace = BaseInfoHelper.GetPlace(sourceStockView.PlaceCode, allPlaeList); // 其他参数对象 TransferOtherDetail transferOtherDetail = new TransferOtherDetail() { RelationNo = inventoryCheckOrder.OrderNo, RelationNoLineNumber = "", Remarks = remarks, }; #endregion //新增事务记录 //仅变更冻结状态 addWmsRecordTransList.Add(LogRecordHelper.CreateWmsRecordTrans(wmsBaseBusinessType, sourceStockView, item, toPlace, transferOtherDetail)); addWmsLogActionList.Add(new WmsLogAction() { Title = businessTypeEnum.GetDescription(), Remarks = $"盘点单{inventoryCheckOrder.OrderNo}跟踪码{item.SNCode}" }); #endregion } //复盘更新盘点单明细状态 if (checkOrderDetailsList?.Count > 0) { foreach (var updateDetails in checkOrderDetailsList) { //复盘更新初盘已完成的盘点单明细 var item = checkStockQuanList.FirstOrDefault(f => f.SNCode.Equals(updateDetails.SNCode)); if (item == null) { throw Oops.Oh($"盘点单{updateDetails.OrderNo}物料{updateDetails.MaterialCode}跟踪码{item.SNCode}未获取到库存信息"); } OrderHelper.UpdateInventoryCheckOrderDetailsCheckStatus(updateDetails, CheckStatusEnum.未盘点); //盘点结果赋值 OrderHelper.UpdateInventoryCheckOrderDetailsCheckResult(updateDetails, CheckResultEnum.未盘); //盘点操作分类 OrderHelper.UpdateInventoryCheckOrderDetailsCheckOperatorClassify(updateDetails, CheckOperatorClassifyEnum.复盘); updateWmsInventoryCheckOrderDetailsList.Add(updateDetails); } } var _tenant = _wmsInventoryCheckOrderRep.AsTenant(); try { await _tenant.BeginTranAsync(); #region 事务内执行操作 //更新盘点单 await _wmsInventoryCheckOrderRep.UpdateAsync(inventoryCheckOrder); //新增盘点单明细 if (addWmsInventoryCheckOrderDetailsList?.Count > 0) { await _wmsInventoryCheckOrderDetailsRep.InsertRangeAsync(addWmsInventoryCheckOrderDetailsList); } if (updateWmsInventoryCheckOrderDetailsList?.Count > 0) { await _wmsInventoryCheckOrderDetailsRep.UpdateRangeAsync(updateWmsInventoryCheckOrderDetailsList); } await _wmsRecordTransRep.InsertRangeAsync(addWmsRecordTransList); //更新库存 await _wmsStockQuanRep.UpdateRangeAsync(upadteWmsStockQuanList); // 操作日志 await _wareActionLogRep.InsertRangeAsync(addWmsLogActionList); #endregion await _tenant.CommitTranAsync(); } catch { await _tenant.RollbackTranAsync(); throw; } return 1; } /// /// 复盘开启获取可盘点库存校验 /// /// /// /// /// private async Task> CheckForFP(WmsStartInventoryCheckInput input, WmsInventoryCheckOrder inventoryCheckOrder, List checkOrderDetailsList) { if (input.DetailsId == null) { throw Oops.Oh("复盘开启明细不能为空!"); } if (input.DetailsId.Any(a => a <= 0)) { throw Oops.Oh("复盘开启明细ID不能为空!"); } //获取复盘的明细ID checkOrderDetailsList = await _wmsInventoryCheckOrderDetailsRep.AsQueryable().Where(u => u.OrderId == inventoryCheckOrder.Id && input.DetailsId.Contains(u.Id) && u.IsDelete == false) .Select().ToListAsync(); if (checkOrderDetailsList?.Count <= 0) { throw Oops.Oh($"盘点单{inventoryCheckOrder.OrderNo}没有获取到可复盘的盘点单明细"); } if (checkOrderDetailsList.Any(a => a.CheckResult != CheckResultEnum.盘亏 && a.CheckResult != CheckResultEnum.盘盈)) { throw Oops.Oh($"存在盘点结果没有差异的盘点单明细"); } return checkOrderDetailsList; } /// /// 获取初盘可盘点的库存 /// /// /// /// private async Task> GetLastCheck_v_wms_stock_quanListForCP(WmsInventoryCheckOrder inventoryCheckOrder, List check_v_wms_stock_quanList) { List checkAreaCodeList = ParamHelper.GetStringParamToList(inventoryCheckOrder.AreaCode); List checkMaterialCodeList = null; //获取盘点范围的物料 var rangeList = await _wmsInventoryCheckRangeRep.GetListAsync(u => u.OrderId == inventoryCheckOrder.Id && u.IsDelete == false); if (rangeList?.Count > 0) { checkMaterialCodeList = rangeList.Select(s => s.MaterialCode).ToList(); } #region 盘点范围 //虚拟库区的库存也锁定 Expression> predicate = null; //获取指定库区库存 if (checkAreaCodeList?.Count > 0) { if (predicate == null) { predicate = u => 1 == 1; } //获取盘点指定库区的正常库位库存\非禁用库位库存、非禁用库区库存 predicate = predicate.And(u => checkAreaCodeList.Contains(u.AreaCode) && u.PlaceStatus == PlaceStatusEnum.正常 && u.IsDisabledPlace == false && u.IsDisabledArea == false); } //获取指定盘点范围的物料 if (checkMaterialCodeList?.Count > 0) { if (predicate == null) { predicate = u => 1 == 1; } predicate = predicate.And(u => checkMaterialCodeList.Contains(u.MaterialCode)); } if (predicate != null) { //虚拟库位库存不盘点 predicate = predicate.And(x => x.IsDelete == false && x.IsVirtuallyPlace == false); } #endregion //获取要盘点的库存视图-根据盘点库区的容器和盘点范围的物料获取盘点库存-包含库位信息、库区信息 if (predicate == null) { check_v_wms_stock_quanList = new List(); } else { check_v_wms_stock_quanList = await _v_wms_stock_quanRep.GetListAsync(predicate); } return check_v_wms_stock_quanList; } /// /// 校验盘点的容器是否有未完成调度任务的容器、盘点单 /// /// /// /// /// private async Task CheckContainer(WmsInventoryCheckOrder checkOrder, SqlSugarRepository _v_wms_inventory_check_order_details_orderRep, List check_v_wms_stock_quanList) { //获取盘点的容器 var allContainerCodeList = check_v_wms_stock_quanList.Select(s => s.ContainerCode).Distinct().ToList(); //获取容器未完成的调度任务 var activeTaskList = await TaskHelper.GetActiveTaskByContainerCode(allContainerCodeList, _wmsTaskRep); //盘点的容器获取未完成的盘点单 var notFinishCheckOrderList = await GetNotFinishCheckOrder(checkOrder, _v_wms_inventory_check_order_details_orderRep, allContainerCodeList, _v_wms_stock_quanRep); foreach (var item in check_v_wms_stock_quanList) { //容器有未完成的调度任务 var activeTask = activeTaskList.FirstOrDefault(w => w.ContainerCode == item.ContainerCode); if (activeTask!=null) { throw Oops.Oh($"物料{item.MaterialCode}跟踪码{item.SNCode}所在容器{item.ContainerCode}有未完成的调度任务{activeTask.TaskNo}"); } //容器虽有跟踪码有未完成的盘点单 var notFinishCheckOrder = notFinishCheckOrderList.FirstOrDefault(w => w.SNCode == item.SNCode); if (notFinishCheckOrder!=null) { throw Oops.Oh($"物料{item.MaterialCode}跟踪码{item.SNCode}所在容器{item.ContainerCode}有未完成的盘点单{notFinishCheckOrder.OrderNo}"); } } } /// /// 盘点的容器获取未完成的盘点单 /// /// /// /// /// /// private async Task> GetNotFinishCheckOrder(WmsInventoryCheckOrder checkOrder, SqlSugarRepository _v_wms_inventory_check_order_details_orderRep, List containerCodeList, SqlSugarRepository _v_wms_stock_quanRep) { //校验盘点单的库区和物料所在容器的 库存 是否存在未完成的盘点单 var stockList = await _v_wms_stock_quanRep.GetListAsync(u => containerCodeList.Contains(u.ContainerCode)); var snCodeList = stockList.Select(s => s.SNCode).ToList(); //根据要创建盘点的物料跟踪码获取已创建的未完成的盘点明细-排除当前盘点单 List notFinishCheckOrderDetailsList = await _v_wms_inventory_check_order_details_orderRep. GetListAsync(u => snCodeList.Contains(u.SNCode)&&u.OrderId!= checkOrder.Id && u.CheckStage != CheckStageEnum.已关闭 && u.CheckStage != CheckStageEnum.已取消 && u.CheckStage != CheckStageEnum.已调账); return notFinishCheckOrderDetailsList; } /// /// 盘点完成 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "OutFinish")] [Description("WmsInventoryCheckOrderDetails/OutFinish")] public async Task OutFinish(WmsInventoryCheckOutFinishInput input) { /* * 0.容器存在活跃的调度任务,不能操作 * 1.检验单盘点单阶段 * 1.1 初盘操作:阶段不是初盘中 不能操作 * 1.2 复盘操作:阶段不是复盘中 不能操作 * * 3. 循环处理盘点明细 * 3.1 校验 盘点的物料跟踪码不在盘点明细中,报错(以后考虑 这种场景的处理) * 3.2 盘点单明细赋值 状态、盘点次数、盘点数量、库存数量、盘点结果 * 状态=》已盘点 * 盘点次数=》累计 * 盘点数量=》实际盘点用户输入的数量 * 库存数量=》此时查询到的库存信息的数量 * 盘点结果: * 盘点数量>库存数量:盘点结果=》盘盈 * 盘点数量<库存数量:盘点结果=》盘亏 * 盘点数量=库存数量:盘点结果=》盘平 * 4.增加盘点记录 * 6 增加操作履历 * */ List addWmsLogActionList = new List(); List updateWmsInventoryCheckOrderDetailsList = new List(); List updateWmsInventoryCheckOrderList = new List(); List addWmsInventoryCheckRecordList = new List(); #region 校验 await Check(input); var orderId = input.Details[0].OrderId; CheckOperatorClassifyEnum checkOperatorClassify = CheckOperatorClassifyEnum.初盘; //获取盘点单据 var inventoryCheckOrder = await _wmsInventoryCheckOrderRep.GetFirstAsync(u => u.Id == orderId && u.IsDelete == false) ?? throw Oops.Oh("盘点单信息不存在!"); if (inventoryCheckOrder.CheckStage != CheckStageEnum.初盘中 && inventoryCheckOrder.CheckStage != CheckStageEnum.复盘中) { throw Oops.Oh($"盘点单状态是{inventoryCheckOrder.CheckStage.GetDescription()}不能盘点!"); } //判断盘点操作分类是初盘还是复盘 if (inventoryCheckOrder.CheckStage == CheckStageEnum.复盘中) { checkOperatorClassify = CheckOperatorClassifyEnum.复盘; } //获取盘点明细 List checkOrderDetailsList = await _wmsInventoryCheckOrderDetailsRep.AsQueryable().Where(u => u.OrderId == inventoryCheckOrder.Id && u.IsDelete == false) .Select().ToListAsync(); if (checkOrderDetailsList?.Count <= 0) { throw Oops.Oh($"盘点单{inventoryCheckOrder.OrderNo}没有获取到盘点单明细信息"); } //获取盘点下架容器的所有库存 var checkOutStockQuanList = await _v_wms_stock_quanRep.GetListAsync(u => (u.ContainerCode.Equals(input.ContainerCode) || u.PlaceCode.Equals(input.ContainerCode)) && u.IsDelete == false); #endregion //循环盘点单据明细 foreach (var item in input.Details) { // 盘点的物料跟踪码不在盘点明细中,报错(以后考虑 这种场景的处理) var checkItem = checkOrderDetailsList.FirstOrDefault(f => f.SNCode.Equals(item.SNCode)); if (checkItem == null) { throw Oops.Oh($"物料{item.MaterialCode}跟踪码{item.SNCode}不在盘点单明细中"); } if (checkItem.CheckStatus != CheckStatusEnum.盘点中) { throw Oops.Oh($"物料{item.MaterialCode}跟踪码{item.SNCode}盘点单明细状态不是{CheckStatusEnum.盘点中.GetDescription()}"); } ////获取当前盘点的库存详情-库位、库区、容器、库存信息 //var currentStockQuanView = checkOutStockQuanList.FirstOrDefault(w => w.SNCode == item.SNCode); //if (currentStockQuanView == null) //{ // throw Oops.Oh($"盘点单明细物料{currentStockQuanView.MaterialCode}跟踪码{currentStockQuanView.SNCode}库存信息不存在"); //} //累计 盘点次数 var CheckCount = checkItem.CheckCount ?? 0; CheckCount += 1; if (CheckCount > 2) CheckCount = 2; checkItem.CheckCount = CheckCount; //赋值盘点数量 checkItem.CheckQuantity = item.CheckQuantity; //更新最新的库存数量 checkItem.Quantity = item.Quantity; //计算盘点结果 if (checkItem.CheckQuantity > checkItem.Quantity) { //盘点数量 > 库存数量:盘点结果 =》盘盈 //更新盘点结果 OrderHelper.UpdateInventoryCheckOrderDetailsCheckResult(checkItem, CheckResultEnum.盘盈); } else if (checkItem.CheckQuantity < checkItem.Quantity) { //盘点数量<库存数量:盘点结果=》盘亏 //更新盘点结果 OrderHelper.UpdateInventoryCheckOrderDetailsCheckResult(checkItem, CheckResultEnum.盘亏); } else { //更新盘点结果 OrderHelper.UpdateInventoryCheckOrderDetailsCheckResult(checkItem, CheckResultEnum.盘平); } //变更状态 OrderHelper.UpdateInventoryCheckOrderDetailsCheckStatus(checkItem, CheckStatusEnum.已盘点); updateWmsInventoryCheckOrderDetailsList.Add(checkItem); //新增盘点记录 WmsInventoryCheckRecord addWmsInventoryCheckRecord = new WmsInventoryCheckRecord() { Quantity = checkItem.Quantity, CheckQuantity = checkItem.CheckQuantity, CheckStatus = checkItem.CheckStatus, CheckStatusName = checkItem.CheckStatus.GetDescription(), CheckResult = checkItem.CheckResult, CheckResultName = checkItem.CheckResultName, AreaCode = item.AreaCode, AreaName = item.AreaName, PlaceCode = item.PlaceCode, PlaceName = item.PlaceName, Batch = item.Batch, ContainerCode = item.ContainerCode, MaterialCode = item.MaterialCode, MaterialName = item.MaterialName, SNCode = item.SNCode, CheckOperatorClassify = checkOperatorClassify, CheckOperatorClassifyName = checkOperatorClassify.GetDescription(), OrderId = inventoryCheckOrder.Id, OrderNo = inventoryCheckOrder.OrderNo, }; addWmsInventoryCheckRecordList.Add(addWmsInventoryCheckRecord); } //创建操作日志 string title = "盘点单" + inventoryCheckOrder.OrderNo + "容器" + input.ContainerCode + "操作" + BusinessTypeEnum.盘点完成.GetDescription(); WmsLogAction addWmsActionLog = LogActionHelper.CreateWmsLogAction(inventoryCheckOrder.Id, title); addWmsLogActionList.Add(addWmsActionLog); var _tenant = _wmsInventoryCheckOrderRep.AsTenant(); try { await _tenant.BeginTranAsync(); #region 事务内执行操作 //新增盘点记录 await _wmsInventoryCheckRecord.InsertRangeAsync(addWmsInventoryCheckRecordList); //更新盘点单明细 await _wmsInventoryCheckOrderDetailsRep.UpdateRangeAsync(updateWmsInventoryCheckOrderDetailsList); //操作日志 await _wareActionLogRep.InsertAsync(addWmsActionLog); #endregion await _tenant.CommitTranAsync(); } catch { await _tenant.RollbackTranAsync(); throw; } return 1; } private async Task Check(WmsInventoryCheckOutFinishInput input) { if (string.IsNullOrWhiteSpace(input.ContainerCode)) { throw Oops.Oh("容器编号不能为空"); } if (input.Details == null) { throw Oops.Oh("盘点物料不能为空"); } if (input.Details.Any(x => x.CheckQuantity < 0)) { throw Oops.Oh("盘点数量不能小于0"); } //一次只能盘点同一个盘点单据的明细 if (input.Details.Select(s => s.OrderId).Distinct().Count() > 1) { throw Oops.Oh("一次盘点只能操作一个盘点单"); } var container = await _wmsContainerRep.GetFirstAsync(x => x.ContainerCode == input.ContainerCode && x.IsDelete == false); if (container == null) { var place = await _wmsPlaceRep.GetFirstAsync(x => x.PlaceCode == input.ContainerCode && x.IsDelete == false); if (place == null) { throw Oops.Oh($"容器\\库位{input.ContainerCode}不存在"); } } //根据容器或库位获取活跃的调度任务 var taskList = await TaskHelper.GetActiveTaskByContainerCodeOrPlaceCode(new List { input.ContainerCode }, _wmsTaskRep); if (taskList?.Count > 0) { throw Oops.Oh($"容器{input.ContainerCode}存在未完成任务不能盘点"); } } /// /// 删除盘点单明细 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Delete")] [Description("WmsInventoryCheckOrderDetails/Delete")] public async Task Delete(DeleteWmsInventoryCheckOrderDetailsInput input) { var entity = await _wmsInventoryCheckOrderDetailsRep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002); //await _rep.FakeDeleteAsync(entity); //假删除 await _wmsInventoryCheckOrderDetailsRep.DeleteAsync(entity); //真删除 } /// /// 更新盘点单明细 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Update")] [Description("WmsInventoryCheckOrderDetails/Update")] public async Task Update(UpdateWmsInventoryCheckOrderDetailsInput input) { var entity = input.Adapt(); //重复性验证 await CheckExist(entity, true); await _wmsInventoryCheckOrderDetailsRep.AsUpdateable(entity).IgnoreColumns(ignoreAllNullColumns: true).ExecuteCommandAsync(); } /// /// 获取盘点单明细 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "Detail")] [Description("WmsInventoryCheckOrderDetails/Detail")] public async Task Detail([FromQuery] QueryByIdWmsInventoryCheckOrderDetailsInput input) { return await _wmsInventoryCheckOrderDetailsRep.GetFirstAsync(u => u.Id == input.Id); } #region 私有方法 /// /// 公共查询盘点单明细条件 /// /// /// private ISugarQueryable CommonPageFilter(WmsInventoryCheckOrderDetailsInput input) { var query = _wmsInventoryCheckOrderDetailsRep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u => u.OrderNo.Contains(input.SearchKey.Trim()) || u.AreaCode.Contains(input.SearchKey.Trim()) || u.PlaceCode.Contains(input.SearchKey.Trim()) || u.SNCode.Contains(input.SearchKey.Trim()) || u.Batch.Contains(input.SearchKey.Trim()) || u.MaterialCode.Contains(input.SearchKey.Trim()) || u.MaterialName.Contains(input.SearchKey.Trim()) || u.ContainerCode.Contains(input.SearchKey.Trim()) || u.CreateUserName.Contains(input.SearchKey.Trim()) || u.UpdateUserName.Contains(input.SearchKey.Trim()) ) .WhereIF(!string.IsNullOrWhiteSpace(input.OrderNo), u => u.OrderNo.Contains(input.OrderNo.Trim())) .WhereIF(input.OrderId > 0, u => u.OrderId == input.OrderId) //盘点差异 明细用 .WhereIF(!string.IsNullOrWhiteSpace(input.ContainerCodeAndPlaceCodeForpda), u => u.PlaceCode == input.ContainerCodeAndPlaceCodeForpda.Trim() || u.ContainerCode == input.ContainerCodeAndPlaceCodeForpda.Trim()) //ly0724 - pad盘点-容器编号 库位编号查询 .WhereIF(!string.IsNullOrWhiteSpace(input.AreaCode), u => u.AreaCode.Contains(input.AreaCode.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.PlaceCode), u => u.PlaceCode.Contains(input.PlaceCode.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.SNCode), u => u.SNCode.Contains(input.SNCode.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.Batch), u => u.Batch.Contains(input.Batch.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), u => u.MaterialCode.Contains(input.MaterialCode.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialName), u => u.MaterialName.Contains(input.MaterialName.Trim())) .WhereIF(!string.IsNullOrWhiteSpace(input.ContainerCode), u => u.ContainerCode.Contains(input.ContainerCode.Trim())) .WhereIF(input.CheckStatus.HasValue, u => u.CheckStatus == input.CheckStatus) .WhereIF(input.CheckResult.HasValue, u => u.CheckResult == input.CheckResult) .WhereIF(input.CheckOperatorClassify.HasValue, u => u.CheckOperatorClassify == input.CheckOperatorClassify) .WhereIF(!string.IsNullOrWhiteSpace(input.CheckSendForpda), u => u.CheckResult != CheckResultEnum.盘平 ) //ly0807-pda盘点下发 - 不显示盘平 .Select(); return query; } /// /// 重复性验证 /// /// 验证对象 /// 是否是编辑 /// private async Task CheckExist(WmsInventoryCheckOrderDetails input, bool isEdit = false) { //没有配置组合校验,不需要验重 //没有配置单独校验,不需要验重 } /// /// 根据组合校验和单独校验验证数据是否已存在-导入时验证 /// /// /// private async Task CheckExisitForImport(List inputs) { if (inputs?.Count <= 0) { throw Oops.Oh($"导入数据不能为空"); } //根据组合校验验证表格中中是否已存在相同数据 //根据单独校验验证表格中中是否已存在相同数据 } #endregion }