using Admin.NET.Application.CommonHelper; using Admin.NET.Application.Entity; using Admin.NET.Core.Helper.ExcelHelper; using DocumentFormat.OpenXml.Wordprocessing; using Elastic.Clients.Elasticsearch.Snapshot; using Furion.DatabaseAccessor; using Microsoft.AspNetCore.Http; using MimeKit; using System.Data; using System.Text; using System.Web; using static SKIT.FlurlHttpClient.Wechat.Api.Models.ChannelsECMerchantAddFreightTemplateRequest.Types.FreightTemplate.Types; namespace Admin.NET.Application; /// /// 移动单服务 /// [ApiDescriptionSettings(ApplicationConst.WmsOrderGroupName, Order = 100)] public class WmsOrderMovementService : IDynamicApiController, ITransient { private readonly SqlSugarRepository _rep; private readonly SqlSugarRepository _WmsStockQuanRep; private readonly SqlSugarRepository _WmsOrderMovementDetailsRep; private readonly SqlSugarRepository _v_wmsOrderMovementDetailsRep; private readonly SqlSugarRepository _BaseCustomerRep; private readonly SqlSugarRepository _wmsMaterialRep; private readonly SqlSugarRepository _WmsBaseBusinessTypeRep; private readonly SqlSugarRepository _WmsNoCreateRuleRep; private readonly SqlSugarRepository _repSNRep; private readonly SqlSugarRepository _repRuleDetailRep; private readonly SqlSugarRepository _WmsOrderDeliverDetailsRep; private readonly SqlSugarRepository _wareActionLogRep; private readonly WmsStockQuanService _wmsStockQuanService; private readonly SqlSugarRepository _wmsPlaceRep; private readonly SqlSugarRepository _wmsContainerRep; private readonly SqlSugarRepository _wmsContainerPlace; private readonly SqlSugarRepository _wmsOrderMovementRep; private readonly SqlSugarRepository _wmsAreaRep; private readonly SqlSugarRepository _v_wms_stock_quanRep; private readonly SqlSugarRepository _v_wms_containerRep; private readonly SqlSugarRepository _wmsTask; public WmsOrderMovementService( SqlSugarRepository rep, SqlSugarRepository wmsStockQuanRep, SqlSugarRepository wmsOrderMovementDetailsRep, SqlSugarRepository baseCustomerRep, SqlSugarRepository WmsBaseBusinessTypeRep, SqlSugarRepository wmsNoCreateRuleRep, SqlSugarRepository repSNRep, SqlSugarRepository repRuleDetailRep, SqlSugarRepository WmsOrderDeliverDetailsRep , SqlSugarRepository wareActionLogRep , WmsStockQuanService wmsStockQuanService, SqlSugarRepository v_wmsOrderMovementDetailsRep , SqlSugarRepository WmsMaterial, SqlSugarRepository WmsBaseBusinessType, SqlSugarRepository wmsPlaceRep, SqlSugarRepository wmsContainerRep, SqlSugarRepository wmsContainerPlace, SqlSugarRepository wmsOrderMovementRep, SqlSugarRepository wmsAreaRep, SqlSugarRepository v_wms_stock_quanRep, SqlSugarRepository v_wms_containerRep, SqlSugarRepository wmsTask ) { _v_wmsOrderMovementDetailsRep = v_wmsOrderMovementDetailsRep; _rep = rep; _WmsStockQuanRep = wmsStockQuanRep; _WmsOrderMovementDetailsRep = wmsOrderMovementDetailsRep; _BaseCustomerRep = baseCustomerRep; _WmsBaseBusinessTypeRep = WmsBaseBusinessTypeRep; _WmsNoCreateRuleRep = wmsNoCreateRuleRep; _repSNRep = repSNRep; _repRuleDetailRep = repRuleDetailRep; _WmsOrderDeliverDetailsRep = WmsOrderDeliverDetailsRep; _wareActionLogRep = wareActionLogRep; _wmsStockQuanService = wmsStockQuanService; _wmsMaterialRep = WmsMaterial; _WmsBaseBusinessTypeRep = WmsBaseBusinessType; _wmsPlaceRep = wmsPlaceRep; _wmsContainerRep = wmsContainerRep; _wmsContainerPlace = wmsContainerPlace; _wmsOrderMovementRep = wmsOrderMovementRep; _wmsAreaRep = wmsAreaRep; _v_wms_stock_quanRep = v_wms_stock_quanRep; _v_wms_containerRep = v_wms_containerRep; _wmsTask = wmsTask; } /// /// 分页查询移动单 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Page")] [Description("WmsOrderMovement/Page")] public async Task> Page(WmsOrderMovementInput input) { var query = CommonPageFilter(input); return await query .OrderBy(x => x.OrderStatus).OrderByDescending(x => x.CreateTime) //.OrderBuilder(input) .ToPagedListAsync(input.Page, input.PageSize); } /// /// 不分页查询移动单 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "List")] [Description("WmsOrderMovement/List")] public async Task> List([FromQuery] WmsOrderMovementInput input) { var query = CommonPageFilter(input); return await query.OrderBuilder(input, "", "Id").Select().ToListAsync(); } /// /// 增加移动单 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Add")] [Description("WmsOrderMovement/Add")] public async Task Add(AddWmsOrderMovementInput input) { var entity = input.Adapt(); //重复性验证 await CheckExist(entity); await _rep.InsertAsync(entity); return entity.Id; } /// /// 增加下架单 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "AddOff")] [Description("WmsOrderMovement/AddOff")] [UnitOfWork] public async Task> AddOff(DiyAddWmsOrderMovementInput input) { if (input.orderDetails is null || input.orderDetails.Count == 0) { throw Oops.Oh("明细不能为空"); } var hearId = await AddOrderEFsql(input); return hearId; } private async Task> AddOrderEFsql(DiyAddWmsOrderMovementInput input) { //新增表头 var warehousOrder = input.Adapt(); var hearId = Yitter.IdGenerator.YitIdHelper.NextId(); warehousOrder.Id = hearId; warehousOrder.OrderType = OrderTypeEnum.下架单; warehousOrder.OrderTypeName = OrderTypeEnum.下架单.GetDescription(); warehousOrder.BusinessType = (int)input.BusinessType; var entity = await _WmsBaseBusinessTypeRep.GetFirstAsync(u => u.BusinessTypeValue == (int)input.BusinessType); if (entity == null) { throw Oops.Oh("业务类型名称获取失败"); } if (string.IsNullOrWhiteSpace(warehousOrder.ToPlaceCode) && string.IsNullOrWhiteSpace(warehousOrder.ToAreaCode)) { throw Oops.Oh($"目标库区、目标库位不能同时为空"); } warehousOrder.BusinessTypeName = entity.BusinessTypeName; //warehousOrder.BusinessTypeName = GetEnumDescriptionUtil.GetEnumDescription(input.BusinessType); warehousOrder.OrderSocure = input.OrderSocure == null ? SourceByEnum.自建 : input.OrderSocure; warehousOrder.OrderStatus = OrderStatusEnum.新建; warehousOrder.OrderStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建); // 获取当前时间 DateTime currentTime = DateTime.Now; // 格式化为年月日字符串 string formattedDate = currentTime.ToString("yyyyMMdd"); //按照单号规则生成单号 - 查找最新的创建的一条单据记录 var newestOrder = await _rep.AsQueryable().Where(p => p.OrderType == OrderTypeEnum.下架单).Where(p => p.OrderNo.Contains(formattedDate)).OrderBy(it => it.CreateTime, OrderByType.Desc) .FirstAsync(); //按照单号规则生成单号-ly warehousOrder.OrderNo = await SerialUtilOrder.GetSerialOrder(OrderTypeEnum.下架单, _WmsNoCreateRuleRep, _repSNRep, (int)warehousOrder.BusinessType, newestOrder == null ? null : newestOrder.OrderNo); if (warehousOrder.OrderNo == null || warehousOrder.OrderNo == "") { warehousOrder.OrderNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(); } if (input.FinancialType.HasValue) { warehousOrder.FinancialTypeName = GetEnumDescriptionUtil.GetEnumDescription(input.FinancialType); } if (!String.IsNullOrEmpty(input.CustCode)) { var Item_BaseCustomer = await _BaseCustomerRep.GetFirstAsync(u => u.CustCode == input.CustCode); if (Item_BaseCustomer != null) { warehousOrder.CustCode = Item_BaseCustomer.CustCode; warehousOrder.CustChinaName = Item_BaseCustomer.CustChinaName; warehousOrder.CustEnglishName = Item_BaseCustomer.CustEnglishName; } else { throw Oops.Oh("客户编号不正确!"); } } //新增明细 var warehousOrderDetails1 = input.orderDetails.Adapt>(); //--------ly关联DO单 入口是DO单,寻找需要更新的DO单明细 await HandleValidDoDetail(input); //--------ly关联DO单 入口是DO单,寻找需要更新的DO单明细 int index = 0; foreach (var w in warehousOrderDetails1) { if (w.Quantity <= 0) { throw Oops.Oh("创建失败:数量需要大于0"); } var idMaterial = Yitter.IdGenerator.YitIdHelper.NextId(); index++; string myLineNumeber = index.ToString(); w.Id = idMaterial; w.MovementNo = warehousOrder.OrderNo; w.MovementId = warehousOrder.Id; w.OrderStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建); w.LineNumber = OrderHelper.AutoCompleEBELP(myLineNumeber, 4); if (!String.IsNullOrEmpty(warehousOrder.CustCode)) { w.CustCode = warehousOrder.CustCode; w.CustName = warehousOrder.CustChinaName; } w.Unit = w.Unit; w.IsDelete = false; } try { // await _rep.AsTenant().BeginTranAsync(); //插入主表 if (warehousOrder != null) { await _rep.InsertAsync(warehousOrder); } //插入明细表 if (warehousOrderDetails1.Count > 0) { await _WmsOrderMovementDetailsRep.InsertRangeAsync(warehousOrderDetails1); } // await _rep.AsTenant().CommitTranAsync(); } catch { // await _rep.AsTenant().RollbackTranAsync(); throw; } return warehousOrderDetails1; } /// /// 验证Do单是否还有物料可用 /// /// /// private async Task HandleValidDoDetail(DiyAddWmsOrderMovementInput input) { //------------ly-0726 验证下架单和do----------- List handleListXjd = new List(); List handleListDeliverDetails = new List(); List queryCodeListForXjd = input.orderDetails.Where(v=> !String.IsNullOrEmpty(v.RelationNo) == true).Select(v => v.RelationNo).Distinct().ToList(); //DoNo if (queryCodeListForXjd.Count > 0) { //查询下架单中已关联do的数据 handleListXjd = await _WmsOrderMovementDetailsRep.GetListAsync(u => queryCodeListForXjd.Contains(u.RelationNo) && u.IsDelete == false); //查询所有相关Do的数据 handleListDeliverDetails = await _WmsOrderDeliverDetailsRep.GetListAsync(u => queryCodeListForXjd.Contains(u.DoNo) && u.IsDelete == false); } foreach (var item in input.orderDetails) { if (!String.IsNullOrEmpty(item.RelationNo)) { //所有DO总数 decimal hasUsedDoQty = handleListDeliverDetails.Where(x => x.MaterialCode == item.MaterialCode && x.DoLineNumber == item.RelationNoLineNumber && x.DoNo == item.RelationNo && (x.DoDetailStatus == OrderStatusEnum.新建 || x.DoDetailStatus == OrderStatusEnum.处理中)).Sum(x => x.Quantity); if (hasUsedDoQty > 0) { //所有下架单中已关联Do总数 decimal hasUsedPoQtyInXjd = handleListXjd.Where(x => x.MaterialCode == item.MaterialCode && x.RelationNoLineNumber == item.RelationNoLineNumber && x.RelationNo == item.RelationNo && (x.OrderStatus == OrderStatusEnum.新建 || x.OrderStatus == OrderStatusEnum.处理中) && x.MovementNo != item.MovementNo).Sum(x => (decimal)x.Quantity); if (hasUsedDoQty < hasUsedPoQtyInXjd) //下架单中已关联po总数 { throw Oops.Oh($"创建失败:DO单号{item.RelationNo},物料编号{item.MaterialCode},DO行号{item.RelationNoLineNumber}需求数量{hasUsedDoQty}已全部创建下架单!"); } decimal usedQtyHasNow = hasUsedDoQty - hasUsedPoQtyInXjd; if (usedQtyHasNow < item.Quantity) { throw Oops.Oh($"创建失败:DO单号{item.RelationNo},物料编号{item.MaterialCode},DO行号{item.RelationNoLineNumber}剩余可用数{usedQtyHasNow}!"); } } } } } /// /// 取消移动单 -下架单 ly /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Delete")] [Description("WmsOrderMovement/Delete")] public async Task Delete(DeleteWmsOrderMovementInput input) { var entity = await _rep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002); entity.OrderStatus = OrderStatusEnum.已取消; entity.OrderStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已取消); var OrderDetails = await _WmsOrderMovementDetailsRep.AsQueryable() .Where(x => x.MovementId == entity.Id) .Where(u => u.IsDelete == false) .Select() .ToListAsync(); //取消明细 List deleteWareOrderDetails = new List(); var deleteList = OrderDetails.Where(x => x.IsDelete == false).ToList(); foreach (var item in deleteList) { if (item.OrderStatus != OrderStatusEnum.新建) { throw Oops.Oh($"物料{item.MaterialCode}的状态{item.OrderStatusName},不允许取消"); } item.OrderStatus = OrderStatusEnum.已取消; item.OrderStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已取消); deleteWareOrderDetails.Add(item); } try { await _rep.AsTenant().BeginTranAsync(); await _rep.UpdateAsync(entity); //更新状态 await _WmsOrderMovementDetailsRep.UpdateRangeAsync(deleteWareOrderDetails); //更新状态 await _rep.AsTenant().CommitTranAsync(); } catch { await _rep.AsTenant().RollbackTranAsync(); throw; } } /// /// 更新移动单--下架单 ly /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "Update")] [Description("WmsOrderMovement/Update")] public async Task Update(DiyAddWmsOrderMovementInput input) { if (input.orderDetails is null || input.orderDetails.Count == 0) { throw Oops.Oh("明细不能为空"); } var dbOrder = await _rep.GetFirstAsync(w => w.OrderNo == input.OrderNo); if (dbOrder == null) { throw Oops.Oh($"订单{input.OrderNo}不存在"); } if (dbOrder.OrderStatus != OrderStatusEnum.新建) { throw Oops.Oh($"订单状态{input.OrderStatus}不可操作"); } dbOrder.PlannedDate = input.PlannedDate; dbOrder.CostCenter = input.CostCenter; dbOrder.DeliveryAddress = input.DeliveryAddress; dbOrder.FinancialType = input.FinancialType; if (input.FinancialType != null) { dbOrder.FinancialTypeName = GetEnumDescriptionUtil.GetEnumDescription(input.FinancialType); } dbOrder.SourceWarehouseCode = input.SourceWarehouseCode; dbOrder.ToAreaCode = input.ToAreaCode; dbOrder.ToPlaceCode = input.ToPlaceCode; dbOrder.CustCode = input.CustCode; var Item_BaseCustomer = await _BaseCustomerRep.GetFirstAsync(u => u.CustCode == input.CustCode); if (Item_BaseCustomer != null) { dbOrder.CustChinaName = Item_BaseCustomer.CustChinaName; dbOrder.CustEnglishName = Item_BaseCustomer.CustEnglishName; } dbOrder.Priority = input.Priority; dbOrder.OrderReason = input.OrderReason; var AsnOrderDetails = await _WmsOrderMovementDetailsRep.AsQueryable() .Where(x => x.MovementId == dbOrder.Id) .Where(u => u.IsDelete == false) .Select() .ToListAsync(); List addWareAsnOrderDetails = new List(); List updateWareAsnOrderDetails = new List(); List deleteWareAsnOrderDetails = new List(); //--------ly关联DO单 入口是DO单,寻找需要更新的DO单明细 await HandleValidDoDetail(input); //--------ly关联DO单 入口是DO单,寻找需要更新的DO单明细 //寻找更新的 var updateList = AsnOrderDetails.Where(x => input.orderDetails.Any(p => p.LineNumber == x.LineNumber && p.MaterialCode == x.MaterialCode)).ToList(); foreach (var item in updateList) { var orderDetails = input.orderDetails.FirstOrDefault(x => x.MaterialCode == item.MaterialCode && x.LineNumber == item.LineNumber); if (orderDetails == null) { continue; } else { if (orderDetails.Quantity<=0) { throw Oops.Oh("创建失败:数量需要大于0"); } item.Quantity = (decimal)orderDetails.Quantity; item.LineNumber = orderDetails.LineNumber; item.CustCode = dbOrder.CustCode; item.CustName = dbOrder.CustChinaName; item.ToAreaCode = dbOrder.ToAreaCode; item.ToPlaceCode = dbOrder.ToPlaceCode; } //变更明细的状态 updateWareAsnOrderDetails.Add(item); } //寻找删除的 var deleteList = AsnOrderDetails.Where(x => !input.orderDetails.Any(p => p.LineNumber == x.LineNumber && p.MaterialCode == x.MaterialCode)).ToList(); foreach (var item in deleteList) { if (item.CreateWaveQuantity > 0) { throw Oops.Oh($"物料{item.MaterialCode}的已发数量{item.CreateWaveQuantity}大于0,不允许删除"); } deleteWareAsnOrderDetails.Add(item); } //获取最大行号 var maxAsnLineNumber = AsnOrderDetails.Max(u => u.LineNumber); int index = Convert.ToInt32(maxAsnLineNumber); //寻找新增的 var addList = input.orderDetails.Where(x => !AsnOrderDetails.Any(p => p.LineNumber == x.LineNumber && p.MaterialCode == x.MaterialCode)).ToList(); foreach (var w in addList) { if (w.Quantity == 0) { throw Oops.Oh("创建失败:数量需要大于0"); } index++;//行号递增 var newLineNumber = OrderHelper.AutoCompleEBELP(index.ToString(), 4); WmsOrderMovementDetails item = new WmsOrderMovementDetails() { Id = Yitter.IdGenerator.YitIdHelper.NextId(), OrderStatus = OrderStatusEnum.新建, OrderStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.新建), MovementNo = dbOrder.OrderNo, MovementId = dbOrder.Id, LineNumber = newLineNumber, MaterialCode = w.MaterialCode, MaterialName = w.MaterialName, SupplierCode = w.SupplierCode, Quantity = (decimal)w.Quantity, PredetermineQuantity = (decimal)w.PredetermineQuantity, PickQuantity = (decimal)w.PickQuantity, OffShelvesQuantity = (decimal)w.OffShelvesQuantity, CreateWaveQuantity = (decimal)w.CreateWaveQuantity, CustCode = dbOrder.CustCode, CustName = dbOrder.CustChinaName, RelationNo= w.RelationNo, RelationNoLineNumber= w.RelationNoLineNumber, Unit = w.Unit, ToAreaCode = dbOrder.ToAreaCode, ToPlaceCode = dbOrder.ToPlaceCode, }; addWareAsnOrderDetails.Add(item); } try { await _rep.AsTenant().BeginTranAsync(); await _rep.UpdateAsync(dbOrder); if (addWareAsnOrderDetails.Count > 0) { await _WmsOrderMovementDetailsRep.InsertRangeAsync(addWareAsnOrderDetails); } if (updateWareAsnOrderDetails.Count > 0) { await _WmsOrderMovementDetailsRep.UpdateRangeAsync(updateWareAsnOrderDetails); } if (deleteWareAsnOrderDetails.Count > 0) { await _WmsOrderMovementDetailsRep.DeleteAsync(deleteWareAsnOrderDetails); } await _rep.AsTenant().CommitTranAsync(); } catch { await _rep.AsTenant().RollbackTranAsync(); throw; } } /// /// 获取移动单 /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "Detail")] [Description("WmsOrderMovement/Detail")] public async Task Detail([FromQuery] QueryByIdWmsOrderMovementInput input) { return await _rep.GetFirstAsync(u => u.Id == input.Id); } #region 导入 /// /// Excel模板导入移动单功能 /// /// Excel模板文件 /// 导入的记录数 [HttpPost] [ApiDescriptionSettings(Name = "ImportExcel")] [Description("WmsOrderMovement/ImportExcel")] public async Task ImportExcelAsync(IFormFile file) { //声明下架单新增的参数信息 var AddInfoList = new DiyAddWmsOrderMovementInput(); int _HeadStartLine = 2;//第1行是说明,第2行是列名 int _DataStartLine = 3;//第3行开始是数据 DataTable importDataTable = ExcelUtil.ImportExcelToDataTable(file, _HeadStartLine, _DataStartLine); var addList = await CommonImport(importDataTable, _DataStartLine); //var XIAJIATypeList = await _WmsBaseBusinessTypeRep.AsQueryable().Where(p => p.UpDownShelvesType == UpDownShelvesTypeEnum.下架).Select(p => p.BusinessTypeValue).ToListAsync(); if (addList.BusinessType == 0) throw Oops.Oh("上传的业务类型编号" + (int)addList.BusinessType + "不正确,请检查后再上传"); await AddOff(addList); if (addList.FinancialType != FinancialTypeEnum.测试类型) throw Oops.Oh("财务类型" + (int)addList.FinancialType + "不正确,请检查后再上传"); return addList.orderDetails.Count; } /// /// DataTable转换实体对象列表 /// /// /// 模版列名开始行 /// private async Task CommonImport(DataTable dataTable, int dataStartLine) { var mainOrder = new DiyAddWmsOrderMovementInput(); var details = new List(); int index = dataStartLine;//模版列名开始行 foreach (System.Data.DataRow row in dataTable.Rows) { index++; //导入模版定制化代码(替换模版使用) var addItem = new DiyWmsOrderMovementDetailsInput(); #region 定义变量 //主表 var _BusinessTypeName = "";//业务类型 var _PlannedDate = "";//计划/交货日期 var _CostCenter = "";//成本中心 var _CustName = "";//客户 var _DeliveryAddress = "";//客户发往地 var _MainToAreaCode = "";//目标库区 var _MainToPlaceCode = "";//目标库位 var _MainPriority = ""; //优先级(主表) var _Remarks = "";//单据原因 //明细 var _MaterialCode = "";//物料编号 var _Quantity = "";//数量 #endregion var BusinessTypeModel = new WmsBaseBusinessType(); #region 取值 //主表 _BusinessTypeName = row["业务类型"]?.ToString(); _PlannedDate = row["计划/交货日期"]?.ToString(); _CostCenter = row["成本中心"]?.ToString(); _CustName = row["客户"]?.ToString(); _DeliveryAddress = row["客户发往地"]?.ToString(); _MainToAreaCode = row["目标库区"]?.ToString(); _MainToPlaceCode = row["目标库位"]?.ToString(); _MainPriority = row["优先级"]?.ToString(); _Remarks = row["单据原因(可空)"]?.ToString(); //明细表 _MaterialCode = row["物料编号"]?.ToString(); _Quantity = row["数量"]?.ToString(); #endregion if (index == 4) { //主表字段 if (string.IsNullOrEmpty(_BusinessTypeName)) { throw Oops.Oh($"第{index}行[业务类型]{_BusinessTypeName}不能为空!"); } if (!string.IsNullOrEmpty(_BusinessTypeName)) { mainOrder.BusinessTypeName = (string)(_BusinessTypeName.Trim()); BusinessTypeModel = BusinessTypeHelper.GetBusinessNameInfoFromDB(_BusinessTypeName, _WmsBaseBusinessTypeRep); mainOrder.BusinessType = (BusinessTypeEnum)(int)BusinessTypeModel.BusinessTypeValue; } //时间格式判断和提示 if (!string.IsNullOrEmpty(_PlannedDate)) { var plannedDate = (string)(_PlannedDate.Trim()); DateTime dateTime; // 尝试使用不同的日期时间格式解析 if (DateTime.TryParseExact(plannedDate, new string[] { "yyyyMMdd", "yyyy-MM-dd", "yyyy/MM/dd" }, null, System.Globalization.DateTimeStyles.None, out dateTime)) { mainOrder.PlannedDate = dateTime; } else { throw new ArgumentException($"无法将输入字符串 '{plannedDate}' 转换为 DateTime.可以尝试将日期写为“yyyyMMdd\", \"yyyy-MM-dd\", \"yyyy/MM/dd”格式的"); } // mainOrder.PlannedDate = Convert.ToDateTime(Convert.ToDateTime(_PlannedDate.Trim()).ToShortDateString()); } if (!string.IsNullOrEmpty(_CostCenter)) { mainOrder.CostCenter = (string)(_CostCenter.Trim()); } //客户 if (!string.IsNullOrEmpty(_CustName)) { mainOrder.CustCode = (string)(_CustName.Trim()); } if (!string.IsNullOrEmpty(_DeliveryAddress)) { mainOrder.DeliveryAddress = (string)(_DeliveryAddress.Trim()); } if (!string.IsNullOrEmpty(_MainToAreaCode)) { mainOrder.ToAreaCode = (string)(_MainToAreaCode.Trim()); } if (!string.IsNullOrEmpty(_MainToPlaceCode)) { mainOrder.ToPlaceCode = (string)(_MainToPlaceCode.Trim()); } if (!string.IsNullOrEmpty(_MainPriority)) { if (!int.TryParse(_MainPriority, out int priority) && !string.IsNullOrEmpty(_MainPriority)) { throw Oops.Oh($"第{index}行[优先级]{_MainPriority}值不正确!"); } if (priority <= 0 && !string.IsNullOrEmpty(_MainPriority)) { throw Oops.Oh($"第{index}行[优先级]{_MainPriority}值不能小于等于0!"); } else { mainOrder.Priority = priority; } } if (!string.IsNullOrEmpty(_Remarks)) { mainOrder.OrderReason = (string)(_Remarks.Trim()); } mainOrder.OrderSocure = SourceByEnum.导入; } //明细表 //判断主表信息是否有重复 if (!string.IsNullOrEmpty(_PlannedDate)) { var plannedDate = (string)(_PlannedDate.Trim()); DateTime dateTime; // 尝试使用不同的日期时间格式解析 if (DateTime.TryParseExact(plannedDate, new string[] { "yyyyMMdd", "yyyy-MM-dd", "yyyy/MM/dd" }, null, System.Globalization.DateTimeStyles.None, out dateTime)) { if (mainOrder.PlannedDate != dateTime) { throw Oops.Oh("excel中交货日期" + (string)(_PlannedDate.Trim()) + "不一致请修改后再导入"); } } else { throw new ArgumentException($"无法将输入字符串 '{plannedDate}' 转换为 DateTime.可以尝试将日期写为“yyyyMMdd\", \"yyyy-MM-dd\", \"yyyy/MM/dd”格式的"); } } //判断单据中第一条的业务类型和后面是否存在不同的情况,如果有就报错 if (mainOrder.BusinessTypeName != _BusinessTypeName) throw Oops.Oh("请检查输入的业务类型是否一致!"); if (!string.IsNullOrEmpty(_CostCenter)) { if (mainOrder.CostCenter != (string)(_CostCenter.Trim())) throw Oops.Oh("excel中成本中心" + _CostCenter.Trim() + "不一致请修改"); } if (!string.IsNullOrEmpty(_CustName)) { if (mainOrder.CustCode != (string)(_CustName.Trim())) throw Oops.Oh("excel中客户" + _CustName.Trim() + "不一致请修改"); } if (!string.IsNullOrEmpty(_DeliveryAddress)) { if (mainOrder.DeliveryAddress != (string)(_DeliveryAddress.Trim())) throw Oops.Oh("excel中客户发往地" + _DeliveryAddress.Trim() + "不一致请修改"); } if (!string.IsNullOrEmpty(_MainToAreaCode)) { if (mainOrder.ToAreaCode != (string)(_MainToAreaCode.Trim())) throw Oops.Oh("excel中目标库区" + _MainToAreaCode.Trim() + "不一致请修改"); } if (!string.IsNullOrEmpty(_MainToPlaceCode)) { if (mainOrder.ToPlaceCode != (string)(_MainToPlaceCode.Trim())) throw Oops.Oh("excel中目标库位" + _MainToPlaceCode.Trim() + "不一致请修改"); } if (!string.IsNullOrEmpty(_MaterialCode)) { addItem.MaterialCode = (string)(_MaterialCode.Trim()); } var wmsMaterialInput = new WmsMaterialInput(); wmsMaterialInput.MaterialCode = addItem.MaterialCode; //通过物料编号去获取物料信息 //var materialInfo = await _wmsStockQuanService.Page(wmsMaterialInput); //var materialList = new List(); //foreach (var item in materialInfo.Items) //{ // materialList.Add(item); //} var materialInfo = await _wmsMaterialRep.AsQueryable().FirstAsync(p => p.MaterialCode == addItem.MaterialCode); if (materialInfo == null) throw Oops.Oh("未找到" + addItem.MaterialCode + "物料信息"); addItem.MaterialName = materialInfo.MaterialName; addItem.Unit = materialInfo.POUnit; addItem.DispenseQuantity = 0; addItem.PredetermineQuantity = 0; addItem.PickQuantity = 0; if (!string.IsNullOrEmpty(_Quantity)) { if (!decimal.TryParse(_Quantity, out decimal quantity) && !string.IsNullOrEmpty(_Quantity)) { throw Oops.Oh($"第{index}行[数量]{_Quantity}值不正确!"); } if (quantity <= 0 && !string.IsNullOrEmpty(_Quantity)) { throw Oops.Oh($"第{index}行[数量]{_Quantity}值不能小于等于0!"); } else { addItem.Quantity = quantity; } } if (!string.IsNullOrEmpty(_CustName)) { addItem.CustCode = (string)(_CustName.Trim()); } if (!string.IsNullOrEmpty(_MainToAreaCode)) { addItem.ToAreaCode = (string)(_MainToAreaCode.Trim()); } if (!string.IsNullOrEmpty(_MainToPlaceCode)) { addItem.ToPlaceCode = (string)(_MainToPlaceCode.Trim()); } details.Add(addItem); } mainOrder.orderDetails = details; //验重 return mainOrder; } /// /// 根据版本下载移动单的Excel导入模板 /// /// 下载的模板文件 [HttpGet] [ApiDescriptionSettings(Name = "DownloadExcelTemplate")] [Description("WmsOrderMovement/DownloadExcelTemplate")] public IActionResult DownloadExcelTemplate() { string _path = TemplateConst.EXCEL_TEMPLATEFILE_导入模版路径 + $"\\移动单{TemplateConst.EXCEL_TEMPLATEFILE_导入模版名称后缀}.xlsx"; var fileName = HttpUtility.UrlEncode($"导入模板(移动单).xlsx", Encoding.GetEncoding("UTF-8")); return new FileStreamResult(new FileStream(_path, FileMode.Open), "application/octet-stream") { FileDownloadName = fileName }; } #endregion #region 私有方法 /// /// 公共查询移动单条件 /// /// /// private ISugarQueryable CommonPageFilter(WmsOrderMovementInput input) { var query = _rep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u => u.OrderNo.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.OrderType.HasValue, u => u.OrderType == input.OrderType) .WhereIF(input.OrderSocure.HasValue, u => u.OrderSocure == input.OrderSocure) .WhereIF(input.BusinessType.HasValue, u => u.BusinessType == input.BusinessType) .WhereIF(input.OrderStatus.HasValue, u => u.OrderStatus == input.OrderStatus) .Select() .OrderBy(n => n.PlannedDate) .OrderBy(n => n.OrderStatus); return query; } /// /// 重复性验证 /// /// 验证对象 /// 是否是编辑 /// private async Task CheckExist(WmsOrderMovement input, bool isEdit = false) { //没有配置组合校验,不需要验重 //没有配置单独校验,不需要验重 } /// /// 根据组合校验和单独校验验证数据是否已存在-导入时验证 /// /// /// private async Task CheckExisitForImport(List inputs) { if (inputs?.Count <= 0) { throw Oops.Oh($"导入数据不能为空"); } //根据组合校验验证表格中中是否已存在相同数据 //根据单独校验验证表格中中是否已存在相同数据 } #endregion /// /// 下架单- 单主表明细导出 ---ly /// /// /// [HttpGet] [ApiDescriptionSettings(Name = "XjdOrderExcelOutting")] [Description("WmsOrderMovement/XjdOrderExcelOutting")] [AllowAnonymous] public async Task XjdOrderExcelOutting([FromQuery] WmsOrderMovementInput input) { var vs = (from p in _v_wmsOrderMovementDetailsRep.AsQueryable().ToList() join m in _rep.AsQueryable() .WhereIF(!string.IsNullOrWhiteSpace(input.SearchKey), u => u.OrderNo.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.OrderType.HasValue, u => u.OrderType == input.OrderType) .WhereIF(input.OrderSocure.HasValue, u => u.OrderSocure == input.OrderSocure) .WhereIF(input.BusinessType.HasValue, u => u.BusinessType == input.BusinessType) .WhereIF(input.OrderStatus.HasValue, u => u.OrderStatus == input.OrderStatus).ToList() on p.MovementId equals m.Id select new WmsOrderMovementExcelOutput { OrderNo = m.OrderNo, BusinessTypeName = m.BusinessTypeName, OrderSocure = m.OrderSocure, OrderStatusName = m.OrderStatusName, PlannedDate = m.PlannedDate, CreateTime = m.CreateTime, UpdateTime = m.UpdateTime, CreateUserName = m.CreateUserName, UpdateUserName = m.UpdateUserName, CostCenter = m.CostCenter, MaterialName = p.MaterialName, MaterialCode = p.MaterialCode, Quantity = p.Quantity, PredetermineQuantity = p.PredetermineQuantity, DispenseQuantity = p.DispenseQuantity, PickQuantity = p.PickQuantity, OffShelvesQuantity = p.OffShelvesQuantity, CreateWaveQuantity = p.CreateWaveQuantity, Unit = p.Unit, ErpCode = p.ErpCode, SupplierBatch = p.SupplierBatch, Batch = p.Batch, ContainerCode = p.ContainerCode, SourcePlaceCode = p.SourcePlaceCode, RelationNo = p.RelationNo, ErpOrderNo = p.ErpOrderNo, ToPlaceName = p.ToPlaceName, SourceAreaCode = p.SourceAreaCode, SupplierCode = p.SupplierCode, FinancialTypeName = m.FinancialTypeName, SourceWarehouseName = m.SourceWarehouseName, ToAreaCode = m.ToAreaCode, ToPlaceCode = m.ToPlaceCode, Priority = m.Priority, OrderReason = m.OrderReason }).ToList(); var fileName = "下架单详情"; var excelBaseResult = new Excel2003Result(vs, fileName, false, "下架单导出详情"); return new FileStreamResult(excelBaseResult.GetExcelStream(), "application/vnd.ms-excel"); } /// /// 关闭上架单 下架单-ly0708 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "CloseOrder")] [Description("WmsOrderMovement/CloseOrder")] public async Task CloseOrder(DeleteWmsOrderMovementInput input) { var entity = await _rep.GetFirstAsync(u => u.Id == input.Id) ?? throw Oops.Oh(ErrorCodeEnum.D1002); if (entity.OrderStatus == OrderStatusEnum.已完成 || entity.OrderStatus == OrderStatusEnum.已取消) { throw Oops.Oh($"单据状态{entity.OrderStatusName},不允许操作!"); } entity.OrderStatus = OrderStatusEnum.已关闭; entity.OrderStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已关闭); var OrderDetails = await _WmsOrderMovementDetailsRep.AsQueryable() .Where(x => x.MovementId == entity.Id) .Where(u => u.IsDelete == false) .Select() .ToListAsync(); //关闭明细 List deleteWareOrderDetails = new List(); var deleteList = OrderDetails.Where(x => x.IsDelete == false).ToList(); foreach (var item in deleteList) { item.OrderStatus = OrderStatusEnum.已关闭; item.OrderStatusName = GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已关闭); deleteWareOrderDetails.Add(item); } // ----------------记录操作日志 List addWareActionLogList = new List(); string actionTitle = $"{OrderTypeEnum.下架单}{entity.OrderNo}{GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已关闭)}";//操作履历标题 if (entity.OrderType == OrderTypeEnum.上架单) { actionTitle = $"{OrderTypeEnum.上架单}{entity.OrderNo}{GetEnumDescriptionUtil.GetEnumDescription(OrderStatusEnum.已关闭)}";//操作履历标题 } var idWmsLogAction = Yitter.IdGenerator.YitIdHelper.NextId(); WmsLogAction wareActionLog = CommonHelper. LogActionHelper.CreateWmsLogAction(idWmsLogAction, actionTitle); addWareActionLogList.Add(wareActionLog); // ----------------记录操作日志 try { await _rep.AsTenant().BeginTranAsync(); await _rep.UpdateAsync(entity); //更新状态 await _WmsOrderMovementDetailsRep.UpdateRangeAsync(deleteWareOrderDetails); //更新状态 await _wareActionLogRep.InsertRangeAsync(addWareActionLogList); //操作日志 await _rep.AsTenant().CommitTranAsync(); } catch { await _rep.AsTenant().RollbackTranAsync(); throw; } } /// /// 下架单绑定物料-分页查询可用库存,按照物料名称分组 /// /// /// [HttpPost] [ApiDescriptionSettings(Name = "GetKcMaterialGroup")] [Description("WmsOrderMovement/GetKcMaterialGroup")] public async Task> GetKcMaterialGroup(WmsOrderMovementKcForMaterialInput input) { throw Oops.Oh("此方法不再使用了,请调用接口 v_wms_stock_quan_group/Page!"); /* 物料编号汇总的数量 * **/ //var query = _v_wms_stock_quan_use_groupRep.AsQueryable() // //.WhereIF(!string.IsNullOrWhiteSpace(input.MaterialName), u => u.MaterialName.Contains(input.MaterialName.Trim())) // //.WhereIF(!string.IsNullOrWhiteSpace(input.SnCode), u => u.SNCode.Contains(input.SnCode.Trim())) // .WhereIF(!string.IsNullOrWhiteSpace(input.MaterialCode), u => u.MaterialCode.Contains(input.MaterialCode.Trim())) // //.Where(p => p.ContainerIsDisabled == false) // //.Where(p => p.PlaceStatus == PlaceStatusEnum.正常) // .Select(); //return await query.OrderBuilder(input, "", "MaterialCode").ToPagedListAsync(input.Page, input.PageSize); } /// /// 点到点搬运 /// /// [HttpPost] [ApiDescriptionSettings(Name = "PointToPoint")] [Description("WmsOrderMovement/PointToPoint")] [UnitOfWork] public async Task PointToPoint(PointToPointInput input) { var wmsContainerPlaceModal = new WmsContainerPlace(); if (!string.IsNullOrEmpty(input.SourcePlaceCode)) { // 校验原库位是否存在 var sourcePlaceModal = await _wmsPlaceRep.GetFirstAsync(n => n.PlaceCode == input.SourcePlaceCode && n.IsDelete == false); if (sourcePlaceModal == null) throw Oops.Oh($"扫描库位{input.SourcePlaceCode}不存在,请重新扫描!"); // 校验库位容器关系 wmsContainerPlaceModal = await _wmsContainerPlace.GetFirstAsync(n => n.PlaceId == sourcePlaceModal.Id && n.IsDelete == false); if (wmsContainerPlaceModal == null) throw Oops.Oh("来源库位不存在需搬运的容器,请重新扫描!"); } if (!string.IsNullOrEmpty(input.ContainerCode)) { // 校验容器是否存在 var containerModal = await _wmsContainerRep.GetFirstAsync(n => n.ContainerCode == input.ContainerCode && n.IsDelete == false); if (containerModal == null) throw Oops.Oh($"该容器{input.ContainerCode}不存在,请重新扫描!"); // 校验库位容器关系 wmsContainerPlaceModal = await _wmsContainerPlace.GetFirstAsync(n => n.ContainerId == containerModal.Id && n.IsDelete == false); if (wmsContainerPlaceModal == null) throw Oops.Oh($"该容器{input.ContainerCode}未绑定库位,不可搬运!请先绑定库位!"); } // 校验目标库位是否存在 var toPlaceModal = await _wmsPlaceRep.GetFirstAsync(n => n.PlaceCode == input.ToPlaceCode && n.IsDelete == false && n.IsDisabled == false); //if (toPlaceModal == null) throw Oops.Oh($"扫描目标库位{input.ToPlaceCode}不存在,请重新扫描!"); //ly0816 没找到 库位就去库区找任意一个空库位 if (toPlaceModal == null) { var toAreaModal = await _wmsAreaRep.GetFirstAsync(n => n.AreaCode == input.ToPlaceCode && n.IsDelete == false && n.IsDisabled == false); if (toAreaModal == null) throw Oops.Oh($"扫描目标库区/库位{input.ToPlaceCode}不存在,请重新扫描!"); toPlaceModal = await _wmsPlaceRep.GetFirstAsync(n => n.AreaCode == toAreaModal.AreaCode && n.IsDelete == false && n.IsDisabled == false); if (toPlaceModal == null) throw Oops.Oh($"扫描目标库位库区/库位{input.ToPlaceCode}不存在,请重新扫描!"); } var _v_wms_container = await _v_wms_containerRep.GetFirstAsync(u => u.ContainerCode == wmsContainerPlaceModal.ContainerCode); if(_v_wms_container == null) throw Oops.Oh($"容器视图{wmsContainerPlaceModal.ContainerCode}不存在!"); BusinessTypeEnum businessTypeEnum = BusinessTypeEnum.点到点移库; var businessTypeInfo = BusinessTypeHelper.GetBusinessTypeInfoFromDB((int)businessTypeEnum, _WmsBaseBusinessTypeRep); // 创建下架单 //4 创建上架单 var hearId = Yitter.IdGenerator.YitIdHelper.NextId();//上架单ID string orderNo = await OrderHelper.CreateOrderNoByRuleCommon(OrderTypeEnum.移库单, (int)businessTypeEnum, _wmsOrderMovementRep, _WmsNoCreateRuleRep, _repSNRep); WmsBaseArea toArea = await BaseInfoHelper.GetAreaByPlace(toPlaceModal, _wmsAreaRep); var addWmsOrderMovement = new WmsOrderMovement() { Id = hearId, OrderNo = orderNo, //按照单号规则生成单号-ly update by liuwq 20240725 OrderType = OrderTypeEnum.移库单, OrderTypeName = OrderTypeEnum.移库单.GetDescription(), BusinessType = (int)businessTypeEnum, BusinessTypeName = businessTypeEnum.GetDescription(), OrderStatus = OrderStatusEnum.新建, OrderStatusName = OrderStatusEnum.新建.GetDescription(), SourceWarehouseCode = _v_wms_container.WarehouseCode, SourceWarehouseName = _v_wms_container.WarehouseName, ToAreaCode = toArea.AreaCode, ToAreaName = toArea.AreaName, ToPlaceCode = toPlaceModal.PlaceCode, ToPlaceName = toPlaceModal.PlaceName, OrderSocure = SourceByEnum.系统 }; // 添加移动单 await _wmsOrderMovementRep.InsertAsync(addWmsOrderMovement); // 通过容器查询到库存 var stockList = await _v_wms_stock_quanRep.AsQueryable() .Where(n => n.ContainerCode == wmsContainerPlaceModal.ContainerCode) .ToListAsync(); List addWmsOrderMovementDetailsList = new List(); int lineNumber = 0;//移动单明细行号 foreach (var item in stockList) { if (item.LockStatus==LockStatusEnum.已锁定) { throw Oops.Oh($"容器{item.ContainerCode}上的物料{item.MaterialCode},跟踪码{item.SNCode} 已锁定!"); //ly0816-锁定 可能在分拣 } lineNumber++; //3.根据容器的库存创建上架单明细 var wmsOrderMovementDetails = new WmsOrderMovementDetails() { MovementId = hearId, MovementNo = addWmsOrderMovement.OrderNo, LineNumber = OrderHelper.AutoCompleEBELP(lineNumber.ToString(), 4), SNCode = item.SNCode, SupplierCode = item.SupplierCode, SupplierName = item.SupplierName, Batch = item.Batch, ErpOrderNo = item.ErpOrderNo, ErpCode = item.ErpCode, Unit = item.MaterialUnit, SupplierBatch = item.SupplierBatch, OrderStatus = OrderStatusEnum.新建, OrderStatusName = OrderStatusEnum.新建.GetDescription(), //ToAreaCode = input.ToAreaCode, //ToPlaceCode = input.ToPlaceCode, ContainerCode = wmsContainerPlaceModal.ContainerCode, ContainerName = wmsContainerPlaceModal.ContainerName, SourceWarehouseCode = _v_wms_container.WarehouseCode, SourceWarehouseName = _v_wms_container.WarehouseName, SourceAreaCode = _v_wms_container.AreaCode, SourceAreaName = _v_wms_container.AreaName, SourcePlaceCode = _v_wms_container.PlaceCode, SourcePlaceName = _v_wms_container.PlaceName, ToPlaceCode = toPlaceModal.PlaceCode, ToPlaceName = toPlaceModal.PlaceName, ToAreaCode = toPlaceModal.AreaCode, ToAreaName = toPlaceModal.AreaName, MaterialCode = item.MaterialCode, MaterialName = item.MaterialName, Quantity = item.Quantity, ActionRemark = "PDA点到点搬运", ActionTime = DateTime.Now }; addWmsOrderMovementDetailsList.Add(wmsOrderMovementDetails); } // 添加点到点移动单明细 if (addWmsOrderMovementDetailsList.Count > 0) await _WmsOrderMovementDetailsRep.InsertRangeAsync(addWmsOrderMovementDetailsList); var wmsTask = new WmsTask() { MoveType = businessTypeInfo.MoveType, MoveTypeName = businessTypeInfo.MoveTypeName, BusinessType = (int)businessTypeEnum, BusinessTypeName = businessTypeInfo.BusinessTypeName, ContainerCode = wmsContainerPlaceModal.ContainerCode, IsFlagFinish = false, OrderNo = addWmsOrderMovement.OrderNo, TaskDescribe = "点到点", TaskStatus = TaskStatusEnum.新建, TaskStatusName = TaskStatusEnum.新建.GetDescription(), TaskNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(), TaskPriority = 0, TaskName = businessTypeEnum.GetDescription(), SourcePlaceCode = wmsContainerPlaceModal.PlaceCode,//源库位 ToAreaCode = toArea.AreaCode, ToPlaceCode = toPlaceModal.PlaceCode }; // 添加任务 await _wmsTask.InsertAsync(wmsTask); } }