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
}