using Admin.NET.Core.Service;
|
using Admin.NET.Application.Entity;
|
using Microsoft.AspNetCore.Http;
|
using Admin.NET.Application;
|
using StackExchange.Redis;
|
using System.Linq.Expressions;
|
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
|
using Qiniu.Storage;
|
using Mapster;
|
using Elastic.Clients.Elasticsearch;
|
using Furion.DatabaseAccessor;
|
using static SKIT.FlurlHttpClient.Wechat.Api.Models.ChannelsECMerchantAddFreightTemplateRequest.Types.FreightTemplate.Types;
|
using System.ComponentModel;
|
using static SKIT.FlurlHttpClient.Wechat.Api.Models.ChannelsECLogisticsEWaybillOrderCreateRequest.Types;
|
using NewLife.Security;
|
using Admin.NET.Application.CommonHelper;
|
using DocumentFormat.OpenXml.Office2013.Word;
|
using Newtonsoft.Json;
|
|
namespace Admin.NET.Application;
|
/// <summary>
|
/// 收货服务
|
/// </summary>
|
[ApiDescriptionSettings(ApplicationConst.WmsOperationsGroupName, Order = 100)]
|
public class ReceivingProcessService : IDynamicApiController, ITransient
|
{
|
private readonly SysFileService _sysFileService;
|
private readonly SqlSugarRepository<WmsRecordReceivingDelivery> _wareConfirmDeliveryRep;
|
private readonly SqlSugarRepository<SysDictData> _sysDictDataRep;
|
private readonly SqlSugarRepository<SysDictType> _sysDictTypeRep;
|
private readonly WmsOrderPurchaseService _wmsOrderPurchaseService;
|
private readonly SqlSugarRepository<WmsStockQuan> _wmsContainerMaterial;
|
private readonly SqlSugarRepository<WmsRecordTrans> _wmsRecordTransRep;
|
private readonly SqlSugarRepository<WmsContainerPlace> _wmsContainerPlaceRep;
|
private readonly SqlSugarRepository<WmsLogAction> _wareActionLogRep;
|
private readonly SqlSugarRepository<SysConfig> _sysConfigRep;
|
|
private readonly SqlSugarRepository<WmsOrderAsn> _wmsOrderAsnrep;
|
private readonly SqlSugarRepository<WmsOrderAsnDetails> _wmsOrderAsnDetailsRep;
|
|
private readonly SqlSugarRepository<WmsOrderPurchase> _wmsOrderPurchase;
|
private readonly SqlSugarRepository<WmsOrderPurchaseDetails> _wmsOrderPurchaseDetails;
|
|
private readonly SqlSugarRepository<WmsBaseMaterial> _wmsMaterialRep;
|
|
private readonly SqlSugarRepository<WmsBaseContainer> _wmsContainerRep;
|
private readonly SqlSugarRepository<WmsBaseArea> _wmsAreaRep;
|
private readonly SqlSugarRepository<WmsBasePlace> _wmsPlaceRep;
|
|
private readonly SqlSugarRepository<WmsOrderQc> _wmsQcRep;
|
private readonly SqlSugarRepository<WmsOrderQcDetails> _wmsQcDetailsRep;
|
private readonly SysConfigService _sysConfigService;
|
private readonly SqlSugarRepository<WmsBaseUnit> _wmsUnitRep;
|
private readonly SqlSugarRepository<WmsBaseBatchRule> _wmsBatchRuleDetailRep;
|
private readonly SqlSugarRepository<WmsConfigSerialSN> _repSNRep;
|
private readonly SqlSugarRepository<WmsConfigNoRule> _WmsNoCreateRuleRep;
|
private readonly SqlSugarRepository<WmsBaseBusinessType> _wmsBaseBusinessType;
|
|
public ReceivingProcessService(
|
SysFileService sysFileService,
|
SqlSugarRepository<WmsRecordReceivingDelivery> wareConfirmDeliveryRep,
|
SqlSugarRepository<SysDictData> sysDictDataRep,
|
SqlSugarRepository<SysDictType> sysDictTypeRep,
|
SqlSugarRepository<WmsStockQuan> wmsContainerMaterial,
|
WmsOrderPurchaseService wmsOrderPurchaseService,
|
SqlSugarRepository<WmsRecordTrans> wmsRecordTransRep,
|
SqlSugarRepository<WmsContainerPlace> wmsContainerPlaceRep,
|
SqlSugarRepository<WmsLogAction> wareActionLogRep,
|
SqlSugarRepository<WmsOrderAsn> wmsOrderAsnrep,
|
SqlSugarRepository<WmsOrderAsnDetails> wmsOrderAsnDetailsRep,
|
SqlSugarRepository<WmsOrderPurchase> wmsOrderPurchase,
|
SqlSugarRepository<WmsOrderPurchaseDetails> wmsOrderPurchaseDetails,
|
SqlSugarRepository<WmsBaseMaterial> wmsMaterialRep,
|
SqlSugarRepository<WmsBaseContainer> wmsContainerRep,
|
SqlSugarRepository<WmsBaseArea> wmsAreaRep,
|
SqlSugarRepository<WmsBasePlace> wmsPlaceRep,
|
SqlSugarRepository<WmsOrderQc> wmsQcRep,
|
SqlSugarRepository<WmsOrderQcDetails> wmsQcDetailsRep,
|
SqlSugarRepository<WmsBaseUnit> wmsUnitRep,
|
SqlSugarRepository<WmsBaseBatchRule> wmsBatchRuleDetailRep,
|
SysConfigService sysConfigService,
|
SqlSugarRepository<WmsConfigSerialSN> repSNRep,
|
SqlSugarRepository<WmsConfigNoRule> wmsNoCreateRuleRep,
|
SqlSugarRepository<WmsBaseBusinessType> wmsBaseBusinessType,
|
SqlSugarRepository<SysConfig> sysConfigRep
|
)
|
{
|
_sysFileService = sysFileService;
|
_wareConfirmDeliveryRep = wareConfirmDeliveryRep;
|
_sysDictDataRep = sysDictDataRep;
|
_sysDictTypeRep = sysDictTypeRep;
|
_wmsContainerMaterial = wmsContainerMaterial;
|
_wmsRecordTransRep = wmsRecordTransRep;
|
_wmsContainerPlaceRep = wmsContainerPlaceRep;
|
_wareActionLogRep = wareActionLogRep;
|
_wmsOrderAsnrep = wmsOrderAsnrep;
|
_wmsOrderAsnDetailsRep = wmsOrderAsnDetailsRep;
|
_wmsOrderPurchase = wmsOrderPurchase;
|
_wmsOrderPurchaseDetails = wmsOrderPurchaseDetails;
|
_wmsMaterialRep = wmsMaterialRep;
|
_wmsContainerRep = wmsContainerRep;
|
_wmsAreaRep = wmsAreaRep;
|
_wmsPlaceRep = wmsPlaceRep;
|
_wmsQcRep = wmsQcRep;
|
_wmsQcDetailsRep = wmsQcDetailsRep;
|
_sysConfigService = sysConfigService;
|
_wmsUnitRep = wmsUnitRep;
|
_wmsBatchRuleDetailRep = wmsBatchRuleDetailRep;
|
_repSNRep = repSNRep;
|
_WmsNoCreateRuleRep = wmsNoCreateRuleRep;
|
_wmsBaseBusinessType = wmsBaseBusinessType;
|
_wmsOrderPurchaseService = wmsOrderPurchaseService;
|
_sysConfigRep = sysConfigRep;
|
}
|
|
#region ASN单PDA收货
|
|
/// <summary>
|
/// ASN单PDA收货
|
/// </summary>
|
/// <param name="sourceinput"></param>
|
/// <returns></returns>
|
[HttpPost]
|
[ApiDescriptionSettings(Name = "Add")]
|
[Description("/receivingProcess/addDelivery")]
|
public async Task<long> AddDelivery(List<ReceivingProcessInput> sourceinput)
|
{
|
/*
|
* 1、获取asn单和明细
|
* 2.验证asn单明细和收货入参
|
* 3.SN码校验库存是否已存在
|
* 4.是否需要质检
|
* 4.1 质检进入待检区
|
* 4.2 不质检直接进收货区
|
* 4.新增库存 --
|
* 4.1 绑定容器和库位(收货容器、收货库位)
|
* 5.获取PO单和明细
|
* 6.更新po单和明细
|
* 7.插入收货记录
|
* 8.插入事务记录
|
* 9.操作日志
|
*/
|
|
|
List<ReceivingProcessInput> input = new List<ReceivingProcessInput>();
|
|
|
#region 校验
|
if (sourceinput?.Count == 0)
|
{
|
throw Oops.Oh("入参不能为空");
|
}
|
//if (sourceinput.Select(s=>s.OrderAsnDetailsId).Distinct().Count()>1)
|
//{
|
// throw Oops.Oh("本次收货的ASN单明细重复");
|
//}
|
|
|
var isExist = sourceinput.Exists(x => x.PDAReceivingActionType == null);
|
if (isExist)
|
{
|
throw Oops.Oh("PDA收货操作类型不能为空");
|
}
|
|
isExist = sourceinput.Exists(x => x.UncollectedQuantity <= 0);
|
if (isExist)
|
{
|
throw Oops.Oh("收货数量必须大于0");
|
}
|
|
|
//只存在前绑定收货
|
PDAReceivingActionTypeEnum pDAReceivingActionType = PDAReceivingActionTypeEnum.前绑定;
|
|
|
//TODO 批次规则验证
|
//TODO ERP库存地验证
|
|
//获取本次收货的ASN单明细
|
List<long> asndetailsIds = sourceinput.Select(s => s.OrderAsnDetailsId).ToList();
|
var receivingOrderAsndetails = await _wmsOrderAsnDetailsRep.AsQueryable().Where(u => asndetailsIds.Contains(u.Id)).ToListAsync();
|
if (receivingOrderAsndetails?.Count == 0)
|
{
|
throw Oops.Oh("本次收货的ASN单明细不存在");
|
}
|
|
//获取收货的ASN单
|
List<long> orderAsnIds = receivingOrderAsndetails.Select(s => s.AsnId).Distinct().ToList();
|
//判断
|
if (orderAsnIds.Count() > 1) throw Oops.Oh("不可同时下发不同ASN单!");
|
List<WmsOrderAsn> orderAsnList = await _wmsOrderAsnrep.AsQueryable().Where(u => orderAsnIds.Contains(u.Id)).ToListAsync();
|
if (orderAsnList?.Count == 0)
|
{
|
throw Oops.Oh("本次收货的ASN单不存在");
|
}
|
|
|
|
//获取全部的ASN单明细
|
var orderAsndetails = await _wmsOrderAsnDetailsRep.AsQueryable().Where(u => orderAsnIds.Contains(u.AsnId)).ToListAsync();
|
if (orderAsndetails?.Count == 0)
|
{
|
throw Oops.Oh("ASN单明细不存在");
|
}
|
//获取po单信息
|
List<string> poNoList = orderAsndetails.Where(w => !string.IsNullOrWhiteSpace(w.PoNo)).Select(u => u.PoNo).ToList();
|
List<WmsOrderPurchaseDetails> orderPurchaseDetailsList = null;
|
List<WmsOrderPurchase> orderPurchaseList = null;
|
if (poNoList?.Count > 0)
|
{
|
orderPurchaseDetailsList = await _wmsOrderPurchaseDetails.AsQueryable().Where(u => poNoList.Contains(u.PoNo) && u.IsDelete == false).ToListAsync();
|
orderPurchaseList = await _wmsOrderPurchase.AsQueryable().Where(u => poNoList.Contains(u.PurchaseNo) && u.IsDelete == false).ToListAsync();
|
|
}
|
|
//此处感觉没用了??????
|
////获取收货区、待检区库区、容器和库位信息
|
//List<string> toContainerCodeList = new List<string>()
|
//{
|
// OperationsContainerEnum.STAGING.ToString()//收货区容器
|
//};
|
//List<string> toPlaceCodeList = new List<string>()
|
//{
|
// OperationsPlaceEnum.STAGING.ToString()//收货区库位
|
//};
|
|
////收货区、待检区库位信息
|
//var toContainerList = await _wmsContainerRep.GetListAsync(x => toContainerCodeList.Contains(x.ContainerCode) && x.IsDelete == false);
|
////收货区、待检区容器信息
|
//var toPlaceList = await _wmsPlaceRep.GetListAsync(x => toPlaceCodeList.Contains(x.PlaceCode) && x.IsDelete == false);
|
////收货区、待检区库区信息
|
//var toAreaList = await _wmsAreaRep.GetListAsync(x => toPlaceList.Select(s => s.AreaId).Contains(x.Id) && x.IsDelete == false);
|
|
|
//获取所有要收货的物料基础数据
|
List<string> materialCodeList = orderAsndetails.Select(s => s.MaterialCode).ToList();
|
var wmsMaterialList = await _wmsMaterialRep.AsQueryable().Where(u => materialCodeList.Contains(u.MaterialCode)).Select<WmsMaterialOutput>().ToListAsync();
|
if (wmsMaterialList?.Count == 0)
|
{
|
throw Oops.Oh("物料基础数据不存在");
|
}
|
|
|
//获取批次规则
|
List<string> batchCodes = wmsMaterialList.Select(s => s.BatchRuleCode).ToList();
|
List<WmsBaseBatchRule> allWmsBatchRuleDetailList = null;
|
if (batchCodes?.Count > 0)
|
{
|
allWmsBatchRuleDetailList = await _wmsBatchRuleDetailRep.GetListAsync(u => batchCodes.Contains(u.RuleCode) && u.IsDisabled == false && u.IsDelete == false);
|
}
|
|
|
//获取收货物料所有采购单位信息
|
List<string> toPOUnitList = wmsMaterialList.Select(s => s.POUnit).Distinct().ToList();//
|
//获取收货物料所有库存单位信息
|
List<string> toMaterialUnitList = wmsMaterialList.Select(s => s.MaterialUnit).Distinct().ToList();
|
List<string> allUnitKeyList = new List<string>();
|
allUnitKeyList.AddRange(toPOUnitList);
|
allUnitKeyList.AddRange(toMaterialUnitList);
|
allUnitKeyList = allUnitKeyList.Distinct().ToList();
|
//所有的收货查询的物料单位信息
|
var allUnitList = await _wmsUnitRep.AsQueryable().Where(u => allUnitKeyList.Contains(u.UnitCode)).ToListAsync();
|
|
//验证入参相关的单据是否合法
|
ValidateInput(sourceinput, pDAReceivingActionType, orderAsndetails, orderAsnList, orderPurchaseDetailsList, orderPurchaseList, wmsMaterialList, allWmsBatchRuleDetailList);
|
|
|
//前绑定收货 根据SnCode获取库存信息
|
List<WmsStockQuan> allSnCodeContainerVsMaterialList = null;
|
//if (pDAReceivingActionType == PDAReceivingActionTypeEnum.前绑定)
|
//{
|
// List<string> sn1dCodeList = orderAsndetails.Where(w => !string.IsNullOrWhiteSpace(w.SN_1d)).Select(u => u.SN_1d).ToList();
|
// List<string> sn2dCodeList = orderAsndetails.Where(w => !string.IsNullOrWhiteSpace(w.SN_2d)).Select(u => u.SN_2d).ToList();
|
// allSnCodeContainerVsMaterialList = await _wmsContainerMaterial.GetListAsync(x => (sn1dCodeList.Contains(x.SNCode) || sn2dCodeList.Contains(x.SNCode)) && x.IsDelete == false);
|
//}
|
List<string> sn1dCodeList = orderAsndetails.Where(w => !string.IsNullOrWhiteSpace(w.SN_1d)).Select(u => u.SN_1d).ToList();
|
List<string> sn2dCodeList = orderAsndetails.Where(w => !string.IsNullOrWhiteSpace(w.SN_2d)).Select(u => u.SN_2d).ToList();
|
allSnCodeContainerVsMaterialList = await _wmsContainerMaterial.GetListAsync(x => (sn1dCodeList.Contains(x.SNCode) || sn2dCodeList.Contains(x.SNCode)) && x.IsDelete == false);
|
|
|
#endregion
|
|
List<WmsStockQuan> addWmsContainerMaterialList = new List<WmsStockQuan>();
|
List<WmsContainerPlace> addWmsContainerPlaceList = new List<WmsContainerPlace>();
|
|
List<WmsRecordTrans> addWmsRecordTransList = new List<WmsRecordTrans>();
|
List<WmsRecordReceivingDelivery> addWareConfirmDeliveryList = new List<WmsRecordReceivingDelivery>();
|
List<WmsLogAction> addWareActionLogList = new List<WmsLogAction>();
|
|
List<WmsOrderPurchaseDetails> updateWmsOrderPurchaseDetails = new List<WmsOrderPurchaseDetails>();
|
List<WmsOrderPurchase> updateWmsOrderPurchaseList = new List<WmsOrderPurchase>();
|
List<WmsOrderAsn> updateWmsOrderAsnList = new List<WmsOrderAsn>();
|
List<WmsOrderAsnDetails> updateWmsOrderAsnDetails = new List<WmsOrderAsnDetails>();
|
|
|
#region 循环处理收货
|
|
|
//string erpVoucher = Yitter.IdGenerator.YitIdHelper.NextId().ToString();//对接ERP 收货凭证号 推送erp系统成功后赋值
|
|
|
|
//ly - 0806 ERP库存地动态收货
|
var toAreaListFromErp = await _wmsAreaRep.GetListAsync(x => orderAsndetails.Select(s => s.ErpCode).Contains(x.ErpCode) && x.IsDelete == false);
|
var toPlaceListFromErp = await _wmsPlaceRep.GetListAsync(x => toAreaListFromErp.Select(s => s.AreaCode).Contains(x.AreaCode) && x.IsDelete == false);
|
var toContainerListFromErp = await _wmsContainerRep.GetListAsync(x => toPlaceListFromErp.Select(s => s.PlaceCode).Contains(x.ContainerCode) && x.IsDelete == false);
|
//ly - 0806
|
|
foreach (var receivingItem in sourceinput)
|
{
|
|
//获取当前ASN单明细
|
var currentAsnDetails = orderAsndetails.FirstOrDefault(f => f.Id == receivingItem.OrderAsnDetailsId);
|
|
//isUsedPo = true 表示使用PO单,isUsedPo = false 表示不使用PO单
|
//如果使用PO单,则验证PO单和明细
|
bool isUsedPo = false;
|
if (!string.IsNullOrWhiteSpace(currentAsnDetails.PoNo) && !string.IsNullOrWhiteSpace(currentAsnDetails.PoLineNumber))
|
{
|
isUsedPo = true;
|
}
|
|
//获取当前ASN单
|
var currentAsn = orderAsnList.FirstOrDefault(f => f.Id == currentAsnDetails.AsnId);
|
//处理动态字段
|
string _materialCode = currentAsnDetails.MaterialCode;
|
|
|
|
//获取SnCode跟踪码
|
//前绑定收货,跟踪码从ASN单明细获取
|
//后绑定收货,跟踪码自定义,暂时使用SN_+ 雪花ID
|
string snCode = GetSNCode(pDAReceivingActionType, currentAsnDetails);
|
|
//if (pDAReceivingActionType == PDAReceivingActionTypeEnum.前绑定)
|
//{
|
// //跟踪码获取库存
|
// WmsStockQuan containerVsMaterial = allSnCodeContainerVsMaterialList.FirstOrDefault(x => x.SNCode == snCode && x.IsDelete == false);
|
// //验证SNCode是否重复创建库存
|
// if (containerVsMaterial != null)
|
// {
|
// throw Oops.Oh($"SN码{snCode}库存已存在");
|
// }
|
//}
|
|
//跟踪码获取库存
|
WmsStockQuan containerVsMaterial = allSnCodeContainerVsMaterialList.FirstOrDefault(x => x.SNCode == snCode && x.IsDelete == false);
|
//验证SNCode是否重复创建库存
|
if (containerVsMaterial != null)
|
{
|
throw Oops.Oh($"SN码{snCode}库存已存在");
|
}
|
|
//获取当前收货物料的物料基础信息
|
var materialBaseInfo = wmsMaterialList.FirstOrDefault(f => f.MaterialCode == _materialCode);
|
|
decimal currentQuantity = receivingItem.UncollectedQuantity;//当前收的根据物料库存单位转换的库存数
|
|
decimal currentPoQuantity = (decimal)receivingItem.POQuantity;//当前收的根据物料采购单位转换的采购数
|
|
|
var needGoodQty = currentAsnDetails.Quantity - currentAsnDetails.GoodsQuantity;
|
|
if (needGoodQty < currentQuantity)
|
{
|
throw Oops.Oh(_materialCode + $" : 收货数{currentQuantity}不能超过ASN单剩余可收货数{needGoodQty}");
|
}
|
|
//更新ASN单明细
|
currentAsnDetails.GoodsQuantity += currentQuantity;//累计的ASN单的收货数 是 采购数
|
OrderHelper.UpdateOrderAsnDetailsStatus(currentAsnDetails);
|
|
updateWmsOrderAsnDetails.Add(currentAsnDetails);
|
|
|
//如果ASN单明细关联PO,就更新PO明细
|
WmsOrderPurchaseDetails currentPurchaseDetails = null;
|
if (isUsedPo)
|
{
|
//更新PO单明细
|
currentPurchaseDetails = orderPurchaseDetailsList.FirstOrDefault(f => f.PoNo == currentAsnDetails.PoNo && f.MaterialCode == currentAsnDetails.MaterialCode && f.PoLineNumber == currentAsnDetails.PoLineNumber);
|
currentPurchaseDetails.GoodsQuantity += currentPoQuantity;//累计的PO单的收货数 是 采购数
|
OrderHelper.UpdateOrderPurchaseDetailsStatus(currentPurchaseDetails);
|
updateWmsOrderPurchaseDetails.Add(currentPurchaseDetails);
|
}
|
|
|
#region 物料质检逻辑
|
var toPlace = "";
|
var toContainer = "";
|
StockQcStatusEnum setCheckStatus = default(StockQcStatusEnum);
|
StockStatusEnum setStockStatusEnum = default(StockStatusEnum);
|
|
//------------------ly-0806
|
|
////默认收货区容器 (不管是否需要质检,都在收货区)
|
//toContainer = OperationsContainerEnum.STAGING.ToString();
|
////默认收货区库位
|
//toPlace = OperationsPlaceEnum.STAGING.ToString();
|
|
//ly-0806 收货时,根据 ASN单上的erp库存地,寻找同名库区下的 top1 收货库位类型的库位,作为 收货库位,如果找不到,就报错。提示 用户要建立 相应的库区和库位
|
if (String.IsNullOrEmpty(currentAsnDetails.ErpCode))
|
{
|
throw Oops.Oh($"单号{currentAsnDetails.AsnNo}物料{currentAsnDetails.MaterialCode}行号{currentAsnDetails.AsnLineNumber}Erp库存地不存在,不能收货");
|
}
|
|
var getAreaErpItem = toAreaListFromErp.FirstOrDefault(x => currentAsnDetails.ErpCode ==x.ErpCode && x.IsDelete == false);
|
if (getAreaErpItem == null)
|
{
|
throw Oops.Oh($"ERP库存地是{currentAsnDetails.ErpCode}的库区不存在");
|
}
|
|
var getPlaceErpItem = toPlaceListFromErp.FirstOrDefault(x => getAreaErpItem.AreaCode == x.AreaCode && x.PlaceType ==PlaceTypeEnum.收货库位 && x.IsVirtually ==true && x.IsDelete == false);
|
if (getPlaceErpItem == null)
|
{
|
throw Oops.Oh($"在库区{getAreaErpItem.AreaCode}中,虚拟收货库位不存在!");
|
}
|
|
//一个库区 只能有一个 虚拟的收货库位
|
var ShPlaceList = toPlaceListFromErp.Where(x => getAreaErpItem.AreaCode == x.AreaCode && x.PlaceType == PlaceTypeEnum.收货库位 && x.IsVirtually == true && x.IsDelete == false).ToList();
|
if (ShPlaceList.Count > 1)
|
{
|
throw Oops.Oh($"库区{getAreaErpItem.AreaCode}中存在{ShPlaceList.Count}个虚拟的收货库位!");
|
}
|
//收货库位和收货容器要同名
|
var getContainerErpItem = toContainerListFromErp.FirstOrDefault(x => getPlaceErpItem.PlaceCode == x.ContainerCode && x.IsVirtually == true && x.IsDelete == false);
|
if (getContainerErpItem == null)
|
{
|
throw Oops.Oh($"库区{getAreaErpItem.AreaCode} 库位{getPlaceErpItem.PlaceCode}中不存在虚拟容器{getPlaceErpItem.PlaceCode}");
|
}
|
|
toPlace = getPlaceErpItem.PlaceCode;
|
toContainer = getContainerErpItem.ContainerCode;
|
|
if (toPlace == null || toContainer == null)
|
{
|
throw Oops.Oh($"目标库区 目标库位不能为空");
|
}
|
//-------------ly-0806
|
|
|
|
|
if (materialBaseInfo.IsCheck == true)//需要质检
|
{
|
|
//库存质检状态赋值
|
setCheckStatus = StockQcStatusEnum.待检;
|
//库存状态赋值
|
setStockStatusEnum = StockStatusEnum.待质检;
|
}
|
else//免检
|
{
|
|
//库存质检状态赋值
|
setCheckStatus = StockQcStatusEnum.合格;
|
//库存状态赋值
|
setStockStatusEnum = StockStatusEnum.待上架;
|
|
}
|
|
#endregion
|
|
//根据批次规则生成批次号
|
|
var batchRuleDetailsList = allWmsBatchRuleDetailList.Where(u => u.RuleCode == materialBaseInfo.BatchRuleCode).ToList();
|
|
string batchNo = BatchRuleHelper.GetBatch(currentAsnDetails, materialBaseInfo, batchRuleDetailsList);
|
|
#region 获取上架的 库位、库区、容器数据信息
|
|
//查询上架的容器信息
|
WmsBaseContainer toContainerInfo = await BaseInfoHelper.GetContainer(toContainer, _wmsContainerRep);
|
|
// 查询上架的库位信息
|
WmsBasePlace toPlaceInfo = await BaseInfoHelper.GetPlace(toPlace, _wmsPlaceRep);
|
|
//查询上架的库区信息
|
WmsBaseArea toAreaInfo = await BaseInfoHelper.GetAreaByPlace(toPlaceInfo, _wmsAreaRep);
|
#endregion
|
|
|
#region 新增库存、事务记录、收货记录、操作日志
|
|
string actionTitle = $"PDA{PDAReceivingActionTypeEnum.前绑定.ToString()}收货";//操作履历标题
|
//获取业务类型
|
var businessTypeInfo = BusinessTypeHelper.GetBusinessTypeInfoFromDB(currentAsn.BusinessType, _wmsBaseBusinessType);
|
|
//新增库存
|
WmsStockQuan addStockQuan = CreateWmsContainerMaterial(batchNo, materialBaseInfo, allUnitList, receivingItem, currentAsnDetails, snCode, setCheckStatus, setStockStatusEnum, toContainerInfo, toPlaceInfo, toAreaInfo);
|
|
|
|
//创建事务的入参
|
#region 创建事务的入参
|
TransferOtherDetail transferOtherDetail = new TransferOtherDetail()
|
{
|
RelationNo = currentAsnDetails.AsnNo,
|
RelationNoLineNumber = currentAsnDetails.AsnLineNumber,
|
Remarks = $"ASN单{currentAsnDetails.AsnNo}{currentAsn.BusinessTypeName}"
|
|
};
|
|
#endregion
|
|
//新增事务记录
|
//新增的库存源信息都是空
|
|
addWmsRecordTransList.Add(LogRecordHelper.CreateWmsRecordTrans(businessTypeInfo, null, addStockQuan, toPlaceInfo, transferOtherDetail));
|
|
//新增收货记录
|
WmsRecordReceivingDelivery addRecordReceivingDelivery = CreateWareConfirmDelivery(batchNo, pDAReceivingActionType, receivingItem, currentAsn, currentAsnDetails, snCode, currentPurchaseDetails);
|
addRecordReceivingDelivery.Id = Yitter.IdGenerator.YitIdHelper.NextId();
|
//判断是否需要记录收货适配器记录,并推送Erp
|
var sysConfigModel = await _sysConfigRep.AsQueryable().FirstAsync(p => p.Id == 573736595685445);
|
if (sysConfigModel.Value == "True")
|
{
|
var receivingAdapterLogsInput = new ReceivingAdapterLogsInput();
|
receivingAdapterLogsInput.OPOrderReceivingAdapterAdd = sourceinput;
|
receivingAdapterLogsInput.KeyCode = addRecordReceivingDelivery.Id;
|
await _wmsOrderPurchaseService.ReceivingAdapterLogs(receivingAdapterLogsInput);
|
}
|
//新增操作日志
|
WmsLogAction wareActionLog = LogActionHelper.CreateWmsLogAction(currentAsnDetails.Id, actionTitle, $"跟踪码{snCode}");
|
|
addWareConfirmDeliveryList.Add(addRecordReceivingDelivery);
|
|
addWmsContainerMaterialList.Add(addStockQuan);
|
addWareActionLogList.Add(wareActionLog);
|
#endregion
|
|
|
}
|
|
#endregion
|
|
|
//处理ANS单
|
|
if (orderAsnList.Count > 0)
|
{
|
foreach (var item in orderAsnList)
|
{
|
var updateOrderAsndetails = orderAsndetails.Where(w => w.AsnId == item.Id).ToList();
|
////计算 ASN单的状态和总已收货数
|
OrderHelper.UpdateWmsOrderAsnStatus(orderAsndetails, item);
|
updateWmsOrderAsnList.Add(item);
|
}
|
}
|
|
|
|
// 处理PO单
|
if (orderPurchaseList?.Count > 0)
|
{
|
foreach (var item in orderPurchaseList)
|
{
|
var updatePurchaseDetails = orderPurchaseDetailsList.Where(w => w.PoId == item.Id).ToList();
|
|
////计算 PO单的状态 和总已收货数
|
OrderHelper.UpdatOrderPurchaseStatus(updatePurchaseDetails, item);
|
updateWmsOrderPurchaseList.Add(item);
|
}
|
}
|
|
//创建报检单
|
WmsQcInfoByReceiving wmsQcInfoByReceiving = await CreateWmsQc(addWmsContainerMaterialList, orderAsndetails, addWmsRecordTransList);
|
|
var _tenant = _wmsContainerMaterial.AsTenant();
|
try
|
{
|
await _tenant.BeginTranAsync();
|
|
#region 事务内执行操作
|
//新增库存
|
await _wmsContainerMaterial.InsertRangeAsync(addWmsContainerMaterialList);
|
await _wmsContainerPlaceRep.InsertRangeAsync(addWmsContainerPlaceList);
|
//更新ASN单
|
await _wmsOrderAsnDetailsRep.UpdateRangeAsync(updateWmsOrderAsnDetails);
|
await _wmsOrderAsnrep.UpdateRangeAsync(updateWmsOrderAsnList);
|
//更新PO单
|
await _wmsOrderPurchaseDetails.UpdateRangeAsync(updateWmsOrderPurchaseDetails);
|
await _wmsOrderPurchase.UpdateRangeAsync(updateWmsOrderPurchaseList);
|
|
//新增事务记录、收货记录、操作日志
|
await _wareActionLogRep.InsertRangeAsync(addWareActionLogList);
|
await _wareConfirmDeliveryRep.InsertRangeAsync(addWareConfirmDeliveryList);
|
await _wmsRecordTransRep.InsertRangeAsync(addWmsRecordTransList);
|
|
if (wmsQcInfoByReceiving != null)
|
{
|
await _wmsQcRep.InsertAsync(wmsQcInfoByReceiving.wmsQc);
|
await _wmsQcDetailsRep.InsertRangeAsync(wmsQcInfoByReceiving.wmsQcDetails);
|
}
|
|
#endregion
|
|
await _tenant.CommitTranAsync();
|
}
|
catch
|
{
|
await _tenant.RollbackTranAsync();
|
throw;
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
//public async Task ReceivingAdapterLogs(ReceivingAdapterLogsInput input)
|
//{
|
// var getAdapterModel = await _repAdapterManagement.AsQueryable().FirstAsync(p => p.AdapterMethodName.Contains("PO单接收"));
|
// string OrderADapter = JsonConvert.SerializeObject(wcsInput.OPOrderAdapterAdd);
|
// string Message = JsonConvert.SerializeObject(wcsInput.AdapterReturnMassageObject);
|
// //插入一条记录,初始化记录的时候一定要先将记录变成未处理
|
// if (getAdapterModel == null) throw Oops.Oh("当前接口地址不正确,未找到相应适配器");
|
// var newRecordAdapter = new RecordAdapter()
|
// {
|
// AdapterCategoryId = getAdapterModel.AdapterCategoryId,
|
// AdapterName = getAdapterModel.AdapterName,
|
// CategoryName = getAdapterModel.CategoryName,
|
// AdapterId = getAdapterModel.Id,
|
// AdapterMethodName = getAdapterModel.AdapterMethodName,
|
// RequestSoure = "CC",
|
// AdapterSID = wcsInput.SID,
|
// BeginTime = DateTime.Now,
|
// DealWithStatus = AdapterLogDealWithEnum.未处理,
|
// ErrMessage = wcsInput.AdapterReturnMassageObject.Message,
|
// // ErrMessage = wcsInput.ErrMessage == null ? "" : wcsInput.ErrMessage,
|
// AdapterInput = OrderADapter,
|
// AdapterReturnMassage = Message,
|
// OrderNo = wcsInput.AdapterReturnMassageObject.Result.ToString()
|
// };
|
// await _repRecordAdapter.InsertAsync(newRecordAdapter);
|
//}
|
|
/// <summary>
|
/// 创建报检单
|
/// </summary>
|
/// <param name="addWmsContainerMaterialList"></param>
|
/// <param name="wmsOrderAsnDetails"></param>
|
/// <param name="addRecordTransList"></param>
|
/// <returns></returns>
|
private async Task<WmsQcInfoByReceiving> CreateWmsQc(List<WmsStockQuan> addWmsContainerMaterialList, List<WmsOrderAsnDetails> wmsOrderAsnDetails, List<WmsRecordTrans> addRecordTransList)
|
{
|
//新增表头
|
|
//系统配置 收货是否创建报检单
|
var addQCOrder = await _sysConfigService.GetConfigValue<bool>(CommonConst.SysAddQCOrder);
|
if (addQCOrder != true)
|
{
|
return null;
|
}
|
var checkList = addWmsContainerMaterialList.Where(w => w.StockStatus == StockStatusEnum.待质检).ToList();
|
if (checkList?.Count > 0)
|
{
|
WmsQcInfoByReceiving result = new WmsQcInfoByReceiving();
|
WmsOrderQc warehousOrder = new WmsOrderQc();
|
List<WmsOrderQcDetails> wmsQcDetails = new List<WmsOrderQcDetails>();
|
|
var hearId = Yitter.IdGenerator.YitIdHelper.NextId();
|
warehousOrder.Id = hearId;
|
|
// 获取当前时间
|
DateTime currentTime = DateTime.Now;
|
|
// 格式化为年月日字符串
|
string formattedDate = currentTime.ToString("yyyyMMdd");
|
|
//按照单号规则生成单号 - 查找最新的创建的一条单据记录
|
//var newestOrder = await _wmsQcRep.AsQueryable().Where(p => p.RelationOrderType == OrderTypeEnum.报检单).Where(p => p.QCNo.Contains(formattedDate)).OrderBy(it => it.CreateTime, OrderByType.Desc)
|
// .FirstAsync();
|
|
|
var newestOrder = await _wmsQcRep.AsQueryable().OrderBy(it => it.CreateTime, OrderByType.Desc)
|
.FirstAsync();
|
|
//按照单号规则生成单号-ly
|
warehousOrder.QCNo = await SerialUtilOrder.GetSerialOrder(OrderTypeEnum.报检单, _WmsNoCreateRuleRep, _repSNRep, (int)BusinessTypeEnum.进料检验, newestOrder == null ? null : newestOrder.QCNo);
|
if (warehousOrder.QCNo == null || warehousOrder.QCNo == "")
|
{
|
warehousOrder.QCNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString();
|
}
|
|
|
warehousOrder.QCOrderStatus = OrderStatusEnum.新建;
|
warehousOrder.QCOrderStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建);
|
warehousOrder.QCStatusName = GetEnumDescriptionUtil.GetEnumDescription(QcStatusEnum.待检);
|
warehousOrder.QCStatus = QcStatusEnum.待检;
|
//TODO 关联单据类型
|
//warehousOrder.RelationOrderType =null; //一次收货只能是一种关联单据类型
|
warehousOrder.BusinessType = BusinessTypeEnum.进料检验;
|
warehousOrder.BusinessTypeName = BusinessTypeEnum.进料检验.GetDescription();
|
if (addRecordTransList.Select(p => p.RelationNo).Distinct().ToList().Count() > 1) throw Oops.Oh("下发了不同的ASN单号!");
|
warehousOrder.RelationNo = addRecordTransList.Select(p => p.RelationNo).First();
|
warehousOrder.RelationOrderType = OrderTypeEnum.ASN单;
|
//warehousOrder.RelationOrderType = addRecordTransList.Select(p => p.RelationOrderType).First(); //事务记录 已经去掉这个字段了
|
int lineNumber = 0;//行号 后期根据对接的第三方返回的格式重新定义
|
foreach (var item in checkList)
|
{
|
lineNumber++;
|
WmsRecordTrans wmsRecordTrans = addRecordTransList.FirstOrDefault(f => f.ToSNCode.Equals(item.SNCode));
|
//查询PO单行号
|
if (wmsRecordTrans == null)
|
{
|
throw Oops.Oh($"跟踪码{item.SNCode}未获取到事务记录,创建报检单失败");
|
}
|
|
var currentAsnDetails = wmsOrderAsnDetails.FirstOrDefault(f => f.AsnNo == wmsRecordTrans.RelationNo && f.AsnLineNumber == wmsRecordTrans.RelationNoLineNumber);
|
if (currentAsnDetails == null)
|
{
|
throw Oops.Oh($"创建报检单ASN单{wmsRecordTrans.RelationNo}行号{wmsRecordTrans.RelationNoLineNumber}未获取到ASN单明细");
|
}
|
WmsOrderQcDetails wmsQcDetailsInput = new WmsOrderQcDetails()
|
{
|
QCLineNumber = lineNumber.ToString(),
|
ErpVoucher = item.ErpVoucher,//对接ERP收货返回的凭证,用于获取质检结果
|
SNCode = item.SNCode,
|
QCOrderId = warehousOrder.Id,
|
QCOrderNo = warehousOrder.QCNo,
|
PassQuantity = 0,
|
RejectQuantity = 0,
|
GoodsQuantity = item.Quantity,
|
QCQuantity = 0,
|
QCStatus = QcStatusEnum.待检,
|
QCStatusName = QcStatusEnum.待检.GetDescription(),
|
MaterialCode = item.MaterialCode,
|
MaterialName = item.MaterialName,
|
Unit = currentAsnDetails.POUnit,
|
SupplierCode = item.SupplierCode,
|
SupplierName = item.SupplierName,
|
QCOrderStatus = OrderStatusEnum.新建,
|
QCOrderStatusName = OrderStatusEnum.新建.GetDescription(),
|
PoNo = currentAsnDetails.PoNo,
|
PoLineNumber = currentAsnDetails.PoLineNumber,
|
AsnNo = wmsRecordTrans.RelationNo,
|
AsnLineNumber = wmsRecordTrans.RelationNoLineNumber,
|
};
|
wmsQcDetails.Add(wmsQcDetailsInput);
|
}
|
//warehousOrder.RelationNo= wmsQcDetails[0].RelationNo;//TODO 一个报检单的明细是否只能是同一个关联单号(ASN单)
|
//warehousOrder.RelationOrderType = wmsQcDetails[0].RelationOrderType;//
|
warehousOrder.SupplierName = wmsQcDetails[0].SupplierName;
|
warehousOrder.SupplierCode = wmsQcDetails[0].SupplierCode;
|
|
|
result.wmsQc = warehousOrder;
|
result.wmsQcDetails = wmsQcDetails;
|
return result;
|
}
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
/// 创建收货记录
|
/// </summary>
|
/// <param name="batchNo"></param>
|
/// <param name="pDAReceivingActionType"></param>
|
/// <param name="receivingItem"></param>
|
/// <param name="currentOrderAsn"></param>
|
/// <param name="currentAsnDetails"></param>
|
/// <param name="erpVoucher"></param>
|
/// <param name="snCode"></param>
|
/// <param name="currentPurchaseDetails"></param>
|
/// <returns></returns>
|
private WmsRecordReceivingDelivery CreateWareConfirmDelivery(string batchNo, PDAReceivingActionTypeEnum pDAReceivingActionType, ReceivingProcessInput receivingItem, WmsOrderAsn currentOrderAsn, WmsOrderAsnDetails currentAsnDetails, string snCode, WmsOrderPurchaseDetails currentPurchaseDetails)
|
{
|
WmsRecordReceivingDelivery wareConfirmDelivery = new WmsRecordReceivingDelivery()
|
{
|
Remarks = GetEnumDescriptionUtil.GetEnumDescription(pDAReceivingActionType),
|
OrderNoLineNumber = currentAsnDetails.AsnLineNumber,
|
OrderNo = currentAsnDetails.AsnNo,
|
Batch = batchNo,//根据批次规则创建的批次
|
OrderType = currentOrderAsn.AsnType,//全部都是asn单收货
|
OrderTypeName = currentOrderAsn.AsnTypeName,
|
BusinessType = currentOrderAsn.BusinessType,
|
BusinessTypeName = currentOrderAsn.BusinessTypeName,
|
Quantity = receivingItem.UncollectedQuantity,
|
POQuantity = receivingItem.POQuantity,
|
ErpCode = currentAsnDetails.ErpCode,
|
ErpOrderNo = currentAsnDetails.ErpOrderNo,
|
Images = receivingItem.ImageIds,//上传图片暂时空着
|
MaterialCode = currentAsnDetails.MaterialCode,
|
MaterialName = currentAsnDetails.MaterialName,
|
MoveType = MoveTypeEnum.收货,
|
MoveTypeName = MoveTypeEnum.收货.GetDescription(),
|
RelationNoLineNumber = currentPurchaseDetails != null ? currentPurchaseDetails.PoLineNumber : "",
|
RelationNo = currentPurchaseDetails != null ? currentPurchaseDetails.PoNo : "",
|
SNCode = snCode,
|
SupplierBatch = currentAsnDetails.SupplierBatch,//供应商批次
|
SupplierCode = currentAsnDetails.SupplierCode,
|
SupplierName = currentAsnDetails.SupplierName,
|
POUnit = currentAsnDetails.POUnit,
|
MaterialUnit = currentAsnDetails.MaterialUnit,
|
InOutFlag = InOutFlagEnum.入
|
};
|
return wareConfirmDelivery;
|
}
|
/// <summary>
|
/// 收货创建库存实体
|
/// </summary>
|
/// <param name="receivingItem"></param>
|
/// <param name="currentAsnDetails"></param>
|
/// <param name="erpVoucher"></param>
|
/// <param name="snCode"></param>
|
/// <param name="setCheckStatus"></param>
|
/// <param name="setStockStatusEnum"></param>
|
/// <param name="wmsContainer"></param>
|
/// <param name="wmsPlace"></param>
|
/// <param name="wmsArea"></param>
|
/// <returns></returns>
|
private WmsStockQuan CreateWmsContainerMaterial(string batchNo, WmsMaterialOutput materialBaseInfo, List<WmsBaseUnit> allUnitList, ReceivingProcessInput receivingItem, WmsOrderAsnDetails currentAsnDetails, string snCode, StockQcStatusEnum setCheckStatus, StockStatusEnum setStockStatusEnum, WmsBaseContainer wmsContainer, WmsBasePlace wmsPlace, WmsBaseArea wmsArea)
|
{
|
|
//获取物料基础信息
|
|
decimal inQuantity = receivingItem.UncollectedQuantity;//实际收货库存
|
#region 单位换算,重新计算收货库存
|
//TODO 库存单位跟采购单位不一致,进行单位换算,重新计算入库库存
|
//TODO 实际库存 不要影响 收货数,应该在创建库存信息的时候在计算库存数
|
|
|
|
#endregion
|
|
//物料基础信息库存单位不等于采购单位,库存根据单位换算率计算,库存=收货数*换算率
|
WmsStockQuan addWmsStockQuan = new WmsStockQuan()
|
{
|
|
ContainerCode = wmsContainer.ContainerCode,//收货区容器\待检区容器
|
RelationNo = currentAsnDetails.AsnNo,//TODO关联单号记录ASN单还是PO单号,存在没有PO单直接建asn单收货的情况???
|
ContainerId = wmsContainer.Id,
|
SupplierBatch = currentAsnDetails.SupplierBatch,
|
Batch = batchNo,
|
MaterialCode = currentAsnDetails.MaterialCode,
|
MaterialName = currentAsnDetails.MaterialName,
|
Quantity = inQuantity,
|
QCStatus = setCheckStatus,
|
QCStatusName = setCheckStatus.ToString(),
|
StockStatus = setStockStatusEnum,
|
StockStatusName = setStockStatusEnum.ToString(),
|
RecordInsertTime = DateTime.Now,
|
SNCode = snCode,
|
SourceSNCode = snCode,//赋值源跟踪码-新增的库存,源跟踪码=跟踪码 update by liuwq 20240708
|
ErpCode = currentAsnDetails.ErpCode,
|
ErpOrderNo = currentAsnDetails.ErpOrderNo,
|
SN_1d = currentAsnDetails.SN_1d,
|
SN_2d = currentAsnDetails.SN_2d,
|
SupplierCode = currentAsnDetails.SupplierCode,
|
SupplierName = currentAsnDetails.SupplierName,
|
Remarks = "收货",
|
MaterialUnit = materialBaseInfo.MaterialUnit//库存单位
|
|
};
|
return addWmsStockQuan;
|
}
|
|
|
|
|
//private WmsRecordTrans CreateStockRecordTrans()
|
//{
|
|
//}
|
|
|
//验证入参
|
private void ValidateInput(
|
List<ReceivingProcessInput> sourceinput,
|
PDAReceivingActionTypeEnum pDAReceivingActionType,
|
List<WmsOrderAsnDetails> orderAsndetails,
|
List<WmsOrderAsn> orderAsnList,
|
List<WmsOrderPurchaseDetails> orderPurchaseDetailsList,
|
List<WmsOrderPurchase> orderPurchaseList,
|
List<WmsMaterialOutput> materialList, List<WmsBaseBatchRule> allBatchRuleDetailsList)
|
{
|
|
//当前收货的asn单明细 前绑定asn单明细一维码或二维码必须有一个有值,实际业务不太可能同时有值
|
|
if (orderAsndetails.Count(w => string.IsNullOrWhiteSpace(w.SN_1d) && string.IsNullOrWhiteSpace(w.SN_2d)&& sourceinput.Select(s=>s.OrderAsnDetailsId).Contains(w.Id) ) > 0)
|
{
|
throw Oops.Oh("前绑定收货ASN单明细一维码和二维码不能同时为空");
|
}
|
|
//if (pDAReceivingActionType == PDAReceivingActionTypeEnum.前绑定)
|
//{
|
// //前绑定asn单明细一维码或二维码必须有一个有值,实际业务不太可能同时有值
|
|
// if (orderAsndetails.Count(w => string.IsNullOrWhiteSpace(w.SN_1d) && string.IsNullOrWhiteSpace(w.SN_2d)) > 0)
|
// {
|
// throw Oops.Oh("前绑定收货ASN单明细一维码和二维码不能同时为空");
|
// }
|
//}
|
//else
|
//{
|
// //后绑定asn单明细一维码和二维码不能有值
|
// if (orderAsndetails.Count(w => !string.IsNullOrWhiteSpace(w.SN_1d) || !string.IsNullOrWhiteSpace(w.SN_2d)) > 0)
|
// {
|
// throw Oops.Oh("后绑定收货ASN单明细一维码或二维码不能有值");
|
// }
|
|
//}
|
|
//验证asn单
|
foreach (var item in orderAsndetails)
|
{
|
//验证asn单是否存咋
|
var orderAsn = orderAsnList.FirstOrDefault(u => u.Id == item.AsnId);
|
if (orderAsn == null)
|
{
|
throw Oops.Oh($"ID{item.AsnId}未查询到ASN单!");
|
}
|
//验证asn单的状态
|
if (orderAsn.AsnStatus != OrderStatusEnum.新建 && orderAsn.AsnStatus != OrderStatusEnum.处理中)
|
{
|
throw Oops.Oh($"ASN单{orderAsn.AsnNo}状态是[{orderAsn.AsnStatus.GetDescription()}],不能操作!");
|
}
|
}
|
|
|
|
|
|
|
// 验证收货明细
|
foreach (var validateItem in sourceinput)
|
{
|
|
//根据validateItem.OrderAsnDetailsId获取明细
|
var orderAsndetail = orderAsndetails.FirstOrDefault(u => u.Id == validateItem.OrderAsnDetailsId);
|
if (orderAsndetail == null)
|
{
|
throw Oops.Oh($"本次收货的ASN单明细ID[{validateItem.OrderAsnDetailsId}]未查询到数据");
|
}
|
|
|
#region 验证物料是否有基础数据
|
string _materialCode = orderAsndetail.MaterialCode;
|
var material = materialList.FirstOrDefault(u => u.MaterialCode == _materialCode);
|
|
if (material == null)
|
{
|
throw Oops.Oh($"ASN单{orderAsndetail.AsnNo}物料{_materialCode}没有配置物料基础信息");
|
}
|
if (material.IsDisabled)
|
{
|
throw Oops.Oh($"ASN单{orderAsndetail.AsnNo}物料{_materialCode}基础数据已禁用");
|
}
|
|
if (material.POUnit != orderAsndetail.POUnit)
|
{
|
throw Oops.Oh($"ASN单{orderAsndetail.AsnNo}物料{_materialCode}单位{orderAsndetail.POUnit}跟物料基础数据采购单位{material.POUnit}不一致");
|
}
|
#endregion
|
|
//物料可以不配置批次规则
|
//配置了批次规则就要验证明细是否存在
|
|
if (!string.IsNullOrWhiteSpace(material.BatchRuleCode))
|
{
|
var batchRuleDetailsList = allBatchRuleDetailsList.Where(u => u.RuleCode == material.BatchRuleCode).ToList();
|
|
if (batchRuleDetailsList?.Count <= 0)
|
{
|
throw Oops.Oh($"批次规则{material.BatchRuleCode}没有获取到有效的规则明细");
|
}
|
}
|
|
|
|
|
//isUsedPo = true 表示使用PO单,isUsedPo = false 表示不使用PO单
|
//如果使用PO单,则验证PO单和明细
|
bool isUsedPo = false;
|
if (!string.IsNullOrWhiteSpace(orderAsndetail.PoNo) && !string.IsNullOrWhiteSpace(orderAsndetail.PoLineNumber))
|
{
|
isUsedPo = true;
|
}
|
if (isUsedPo)
|
{
|
//获取ASN单明细关联的PO明细
|
|
|
//验证PO单
|
if (orderPurchaseList?.Count == 0)
|
{
|
throw Oops.Oh("本次收货的PO单不存在");
|
|
}
|
|
var orderPurchaseDetail = orderPurchaseDetailsList.FirstOrDefault(f => f.PoNo == orderAsndetail.PoNo && f.MaterialCode == orderAsndetail.MaterialCode && f.PoLineNumber == orderAsndetail.PoLineNumber);
|
if (orderPurchaseDetail == null)
|
{
|
throw Oops.Oh($"ASN单{orderAsndetail.AsnNo}明细关联的PO单号{orderAsndetail.PoNo},物料{orderAsndetail.MaterialCode},行号{orderAsndetail.PoLineNumber}未查询到PO单明细!");
|
}
|
|
//验证asn单是否存咋
|
var orderPurchase = orderPurchaseList.FirstOrDefault(u => u.Id == orderPurchaseDetail.PoId);
|
if (orderPurchase == null)
|
{
|
throw Oops.Oh($"ID{orderPurchaseDetail.PoId}未查询到PO单!");
|
}
|
//验证PO单的状态
|
if (orderPurchase.PoStatus != OrderStatusEnum.新建 && orderPurchase.PoStatus != OrderStatusEnum.处理中)
|
{
|
throw Oops.Oh($"PO单{orderPurchase.PurchaseNo}状态是[{orderPurchase.PoStatus.GetDescription()}],不能操作!");
|
}
|
|
|
}
|
|
if (pDAReceivingActionType == PDAReceivingActionTypeEnum.前绑定)
|
{
|
string snCode = string.IsNullOrWhiteSpace(orderAsndetail.SN_1d) ? orderAsndetail.SN_2d : orderAsndetail.SN_1d;
|
//前绑定只有新建状态的明细才能收货
|
if (orderAsndetail.AsnStatus != OrderStatusEnum.新建)
|
{
|
throw Oops.Oh($"ASN单{orderAsndetail.AsnNo}跟踪码[{snCode}]的ASN单明细状态不是[{OrderStatusEnum.新建.GetDescription()}],不能操作!");
|
}
|
if (orderAsndetail.GoodsQuantity > 0)
|
{
|
throw Oops.Oh($"ASN单{orderAsndetail.AsnNo}跟踪码[{snCode}]的ASN单明细已收货数[{orderAsndetail.GoodsQuantity}]大于0,不能操作!");
|
}
|
//validateItem收货数必须等于明细的需求数
|
if (validateItem.UncollectedQuantity != orderAsndetail.Quantity)
|
{
|
throw Oops.Oh($"ASN单{orderAsndetail.AsnNo}跟踪码[{snCode}]的ASN单明细的需求数{orderAsndetail.Quantity}不等于本次收货数{validateItem.UncollectedQuantity}!");
|
}
|
}
|
else
|
{ //后绑定asn单明细的 状态只能是新建或执行中才能收货
|
if (orderAsndetail.AsnStatus != OrderStatusEnum.新建 && orderAsndetail.AsnStatus != OrderStatusEnum.处理中)
|
{
|
throw Oops.Oh($"ASN单{orderAsndetail.AsnNo}物料[{orderAsndetail.MaterialCode}]Asn单明细行号[{orderAsndetail.AsnLineNumber}]的ASN单明细状态是[{orderAsndetail.AsnStatus.GetDescription()}],不能操作!");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
/// <summary>
|
/// 根据PDA收货操作类型获取SN条码
|
/// </summary>
|
/// <param name="pDAReceivingActionType"></param>
|
/// <param name="currentAsnDetails"></param>
|
/// <returns></returns>
|
private static string GetSNCode(PDAReceivingActionTypeEnum pDAReceivingActionType, WmsOrderAsnDetails currentAsnDetails)
|
{
|
//现在都是用前绑定收货了,自建的ASN也会根据条码规则生成跟踪码
|
//1.前绑定跟踪码取asn单明细的一维码或二维码,哪个有值取哪个。实际业务不太可能同时有值。
|
//2.后绑定自动生成跟踪码。
|
string SNCode;
|
if (pDAReceivingActionType == PDAReceivingActionTypeEnum.前绑定)
|
{
|
|
if (!string.IsNullOrWhiteSpace(currentAsnDetails.SN_1d))
|
{
|
SNCode = currentAsnDetails.SN_1d;
|
}
|
else
|
{
|
SNCode = currentAsnDetails.SN_2d;
|
}
|
|
}
|
else
|
{
|
//TODO 测试先用雪花ID
|
SNCode = "SN_" + Yitter.IdGenerator.YitIdHelper.NextId();
|
}
|
|
return SNCode;
|
}
|
#endregion
|
|
}
|