using MailKit.Search; using Masuit.Tools; using System.Linq.Expressions; using WIDESEA_Common; using WIDESEA_Core; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.BaseServices; using WIDESEA_Core.Enums; using WIDESEA_Core.Helper; using WIDESEA_DTO; using WIDESEA_DTO.Order; using WIDESEA_DTO.Stock; using WIDESEA_DTO.WMS; using WIDESEA_IBusinessesRepository; using WIDESEA_IOrderRepository; using WIDESEA_IOrderServices; using WIDESEA_IStorageBasicRepository; using WIDESEA_IStorageBasicService; using WIDESEA_IStorageTaskRepository; using WIDESEA_IStorageTaskServices; using WIDESEA_Model.Models; using WIDESEA_Model.Models.ERP; using WIDESEA_Model.Models.Order; using WIDESEA_OrderRepository; using WIDESEA_StorageTaskRepository; using WIDESEA_StorageTaskServices; namespace WIDESEA_OrderServices { public class Dt_AllocateOutboundOrderService : ServiceBase, IDt_AllocateOutboundOrderService { private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IDt_AllocateOutboundOrderDetailRepository _allocateoutboundOrderDetailRepository; private readonly IStockInfoDetailRepository _stockInfoDetailRepository; private readonly IStockInfoRepository _stockInfoRepository; private readonly IStockInfoService _stockInfoService; private readonly IDt_TaskService _taskService; private readonly ILocationInfoRepository _locationRepository; private readonly IDt_TaskRepository _taskRepository; private readonly ILocationStatusChangeRecordRepository _locationStatusChangeRecordRepository; private readonly IDt_OrderOutDetailsRepository _outDetailsRepository; private readonly IDt_AreaInfoRepository _areaInfoRepository; public Dt_AllocateOutboundOrderService(IDt_AllocateOutboundOrderRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IDt_AllocateOutboundOrderDetailRepository allocateoutboundOrderDetailRepository, IStockInfoDetailRepository stockInfoDetailRepository, IStockInfoRepository stockInfoRepository, IStockInfoService stockInfoService, IDt_TaskService taskService, ILocationInfoRepository locationRepository, IDt_TaskRepository taskRepository, ILocationStatusChangeRecordRepository locationStatusChangeRecordRepository, IDt_OrderOutDetailsRepository outDetailsRepository, IDt_AreaInfoRepository areaInfoRepository) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _allocateoutboundOrderDetailRepository = allocateoutboundOrderDetailRepository; _stockInfoDetailRepository = stockInfoDetailRepository; _stockInfoRepository = stockInfoRepository; _stockInfoService = stockInfoService; _taskService = taskService; _locationRepository = locationRepository; _taskRepository = taskRepository; _locationStatusChangeRecordRepository = locationStatusChangeRecordRepository; _outDetailsRepository = outDetailsRepository; _areaInfoRepository = areaInfoRepository; } public WebResponseContent GetAllocateOutboundOrder(OutboundOrderGetDTO outboundOrderGetDTO) { WebResponseContent content = new WebResponseContent(); try { Expression> expressionOrder = x => true; if (!string.IsNullOrEmpty(outboundOrderGetDTO.OrderNo)) { expressionOrder = x => x.UpperOrderNo.Contains(outboundOrderGetDTO.OrderNo); } int count = 0; if (outboundOrderGetDTO.OrderNo == "") { count = BaseDal.QueryData(x => x.OrderStatus != (int)OrderStateEmun.已完成).ToList().Count(); } else { count = BaseDal.QueryData(x => x.OrderStatus != (int)OrderStateEmun.已完成 && x.UpperOrderNo == outboundOrderGetDTO.OrderNo).ToList().Count(); } int maxPage = Convert.ToInt32(Math.Ceiling(count / 10.0)); if (outboundOrderGetDTO.pageNo <= maxPage) { var outboundOrder = BaseDal.Db.Queryable().Where(expressionOrder).OrderByDescending(x => x.CreateDate).Skip((outboundOrderGetDTO.pageNo - 1) * 10).Take(10).Select(x => new Dt_AllocateOutboundOrder { OrderNo = x.OrderNo, Id = x.Id, UpperOrderNo = x.UpperOrderNo, CreateDate = x.CreateDate, Creater = x.Creater }).ToList(); content = WebResponseContent.Instance.OK(data: outboundOrder); } else { var outboundOrder = BaseDal.Db.Queryable().Where(expressionOrder).OrderByDescending(x => x.CreateDate).Skip(0 * 10).Take(10).Select(x => new Dt_AllocateOutboundOrder { OrderNo = x.OrderNo, Id = x.Id, UpperOrderNo = x.UpperOrderNo, CreateDate = x.CreateDate, Creater = x.Creater }).ToList(); content = WebResponseContent.Instance.OK(data: outboundOrder); } } catch (Exception ex) { content = WebResponseContent.Instance.Error($"查询出库单据错误,错误信息:{ex.Message}"); } return content; } public WebResponseContent GetAllocateOutboundOrderDetail(OutboundOrderGetDTO outboundOrderGetDTO) { WebResponseContent content = new WebResponseContent(); try { var otheroutboundOrder = BaseDal.QueryFirst(x => x.Id == outboundOrderGetDTO.id); Expression> expression = x => x.OrderId == otheroutboundOrder.Id; if (!string.IsNullOrEmpty(outboundOrderGetDTO.searchValue)) { expression = x => x.OrderId == otheroutboundOrder.Id && x.MaterielCode.Contains(outboundOrderGetDTO.searchValue); } var outboundOrderdetail = _allocateoutboundOrderDetailRepository.Db.Queryable().Where(expression).Where(x => x.OrderQuantity > x.OverOutQuantity).Select(x => new Dt_AllocateOutboundOrderDetail { MaterielCode = x.MaterielCode, MaterielName = x.MaterielName, OrderQuantity = x.OrderQuantity, OverOutQuantity = x.OverOutQuantity, Id = x.Id }).ToList(); content = WebResponseContent.Instance.OK(data: outboundOrderdetail); } catch (Exception ex) { content = WebResponseContent.Instance.Error($"查询出库单据错误,错误信息:{ex.Message}"); } return content; } #region 根据单据明细生成出库任务 public async Task GenerateAllocateOutboundTask(GenerateOutTaskDto requestOut) { WebResponseContent content = new WebResponseContent(); try { foreach (var orderId in requestOut.orderIds) { Dt_AreaInfo areaInfo = null; if (requestOut.AreaId != null) areaInfo = _areaInfoRepository.QueryFirst(x => x.AreaID == Convert.ToInt32(requestOut.AreaId)); List taskDtos = new List(); Dt_AllocateOutboundOrderDetail allocateoutboundOrderdetail = _allocateoutboundOrderDetailRepository.QueryFirst(x => x.Id == orderId); Dt_AllocateOutboundOrder outboundOrder = BaseDal.QueryFirst(x => x.Id == allocateoutboundOrderdetail.OrderId); (bool, string) checkResult = CheckSelectStockDeital(allocateoutboundOrderdetail, requestOut.stockViews, requestOut); if (!checkResult.Item1) throw new Exception(checkResult.Item2); else { var result = AssignStockOutbound(allocateoutboundOrderdetail, requestOut.stockViews); if (result.Item1.Count <= 0) { return content.Error($"订单{outboundOrder.UpperOrderNo}物料编码{allocateoutboundOrderdetail.MaterielCode}未找到库存分配,请确认是否存在库存或单据数量已出完"); } List outDetails = new List(); result.Item1.Distinct().ForEach(item => { RequestTaskDto task = new RequestTaskDto { TaskType = outboundOrder.OrderType, OrderNo = outboundOrder.OrderNo, MaterielCode = allocateoutboundOrderdetail.MaterielCode, Position = item.LocationCode, PalletCode = item.PalletCode, AreaId = Convert.ToInt32(requestOut.AreaId), }; taskDtos.Add(task); item.StockInfoDetails.Where(x => x.MaterielCode == allocateoutboundOrderdetail.MaterielCode).FirstOrDefault().Status = (int)StockStateEmun.出库锁定; item.StockStatus = (int)StockStateEmun.出库锁定; item.Remark = requestOut.Warehouse; item.OrderNo = outboundOrder.UpperOrderNo; item.StockInfoDetails.Where(x => x.OutboundQuantity > 0 && x.MaterielCode == allocateoutboundOrderdetail.MaterielCode).ForEach(x => { outDetails.Add(new Dt_OrderOutDetails() { OrderNo = outboundOrder.UpperOrderNo, PalletCode = item.PalletCode, OrderType = outboundOrder.OrderType, ERPOrderId = allocateoutboundOrderdetail.ERPOrderId, MaterielCode = allocateoutboundOrderdetail.MaterielCode, MaterielName = allocateoutboundOrderdetail.MaterielName, AllocateWarehouse = areaInfo == null ? item.StockInfoDetails.Where(x => x.MaterielCode == allocateoutboundOrderdetail.MaterielCode).FirstOrDefault().Warehouse : areaInfo.AreaName, AllocateWarehouseId = areaInfo == null ? item.StockInfoDetails.Where(x => x.MaterielCode == allocateoutboundOrderdetail.MaterielCode).FirstOrDefault().WareHouseId : areaInfo.AreaCode, Warehouse = "智能立库", WareHouseId = "107", OutboundQuantity = item.StockInfoDetails.Where(x => x.MaterielCode == allocateoutboundOrderdetail.MaterielCode).Sum(x => x.Quantity), }); }); item.StockInfoDetails.Where(x => x.OutboundQuantity == 0 || (x.Quantity - x.OutboundQuantity) > 0).ForEach(x => { if (x.MaterielCode == allocateoutboundOrderdetail.MaterielCode) { outDetails.Add(new Dt_OrderOutDetails() { OrderNo = "", PalletCode = item.PalletCode, OrderType = (int)OrderTypeEmun.调拨出库单, ERPOrderId = "", MaterielCode = x.MaterielCode, MaterielName = x.MaterielName, AllocateWarehouse = "WMS出库缓存区", Warehouse = "智能立库", WareHouseId = "107", AllocateWarehouseId = "205", OutboundQuantity = x.Quantity - x.OutboundQuantity, }); } else { outDetails.Add(new Dt_OrderOutDetails() { OrderNo = "", PalletCode = item.PalletCode, OrderType = (int)OrderTypeEmun.调拨出库单, ERPOrderId = "", MaterielCode = x.MaterielCode, MaterielName = x.MaterielName, AllocateWarehouse = "WMS出库缓存区", Warehouse = "智能立库", WareHouseId = "107", AllocateWarehouseId = "205", OutboundQuantity = x.Quantity, }); } }); }); List taskNews = new List(); List taskDTOs = new List(); foreach (var item in taskDtos) { taskNews.Add(await _taskService.RequestOutboundTaskAsync(item)); } List locationStatusChangeRecords = new List(); List locations = new List(); if(taskNews.Count <= 0) { throw new Exception($"{allocateoutboundOrderdetail.MaterielCode}未找到可出库托盘"); } foreach (var item in taskNews) { taskDTOs.Add(CreateTaskDTO(item)); var result1 = _taskService.UpdateLocationStatus(item.SourceAddress, LocationEnum.InStockDisable, item.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticOutbound); var result2 = _taskService.UpdateLocationStatus(item.TargetAddress, LocationEnum.Lock, item.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticOutbound); locationStatusChangeRecords.AddRange(result1.Item1); locationStatusChangeRecords.AddRange(result2.Item1); locations.AddRange(result1.Item2); locations.AddRange(result2.Item2); } await _unitOfWorkManage.UseTranAsync(async () => { _taskRepository.AddData(taskNews); _stockInfoRepository.UpdateDataNav(result.Item1); await _locationStatusChangeRecordRepository.AddDataAsync(locationStatusChangeRecords); await _locationRepository.UpdateDataAsync(locations); _allocateoutboundOrderDetailRepository.UpdateData(result.Item2); _outDetailsRepository.AddData(outDetails); }); content = await _taskService.SendWCSTask(taskDTOs); } } return content; } catch (Exception ex) { return content.Error(ex.Message); } } private WMSTaskDTO CreateTaskDTO(Dt_Task task) { return new WMSTaskDTO { TaskNum = task.TaskNum.Value, Grade = task.Grade.Value, PalletCode = task.PalletCode, RoadWay = task.Roadway, SourceAddress = task.SourceAddress, TargetAddress = task.TargetAddress, TaskState = task.TaskState, Id = 0, TaskType = task.TaskType, AGVTaskNum = task.AGVTaskNum, Remark = task.Remark }; } public (List, Dt_AllocateOutboundOrderDetail) AssignStockOutbound(Dt_AllocateOutboundOrderDetail allocateoutboundOrderdetail, List stockSelectViews) { decimal originalNeedQuantity = allocateoutboundOrderdetail.OrderQuantity - allocateoutboundOrderdetail.OverOutQuantity; decimal needQuantity = originalNeedQuantity; List outStocks = new List(); if (stockSelectViews != null && stockSelectViews.Count > 0) { outStocks = BaseDal.Db.Queryable().Where(x => stockSelectViews.Select(x => x.PalletCode).ToList().Contains(x.PalletCode)).Includes(x => x.StockInfoDetails).ToList(); } else { outStocks = GetStockInfos(allocateoutboundOrderdetail.MaterielCode); } List outStockNews = new List(); foreach (var item in outStocks) { var stockDetail = item.StockInfoDetails .Where(d => d.MaterielCode == allocateoutboundOrderdetail.MaterielCode && d.Quantity > 0); if (needQuantity <= 0) { continue; } foreach (var detail in stockDetail) { if (detail != null) { if (needQuantity >= detail.Quantity) { if (detail.Quantity <= detail.OutboundQuantity) { continue; } needQuantity -= detail.Quantity; detail.OutboundQuantity = detail.Quantity; } else { if (detail.Quantity <= detail.OutboundQuantity) { continue; } detail.OutboundQuantity = needQuantity; needQuantity = 0; } outStockNews.Add(item); } } } allocateoutboundOrderdetail.OverOutQuantity = allocateoutboundOrderdetail.OrderQuantity - needQuantity; if (allocateoutboundOrderdetail.OverOutQuantity != 0) { allocateoutboundOrderdetail.OrderDetailStatus = (int)OrderStateEmun.开始; } return (outStockNews, allocateoutboundOrderdetail); } private (bool, string) CheckSelectStockDeital(Dt_AllocateOutboundOrderDetail allocateoutboundOrderdetail, List stockSelectViews, GenerateOutTaskDto requestOut) { if (allocateoutboundOrderdetail == null) { return (false, "未找到出库单信息"); } if (allocateoutboundOrderdetail.OrderDetailStatus == (int)OrderStateEmun.已完成) { return (false, "该明细不可操作"); } if (stockSelectViews != null && stockSelectViews.Sum(x => x.UseableQuantity) > allocateoutboundOrderdetail.OrderQuantity - allocateoutboundOrderdetail.OverOutQuantity) { return (false, "选择数量超出单据数量"); } if (allocateoutboundOrderdetail.OrderQuantity <= allocateoutboundOrderdetail.OverOutQuantity) { return (false, "单据数量已出库完成"); } return (true, "成功"); } public List GetStockInfos(string materielCode) { var stocks = BaseDal.Db.Queryable() .Includes(x => x.StockInfoDetails) .Includes(x => x.LocationInfo) .Where(x => x.LocationInfo.LocationStatus == (int)LocationEnum.InStock && x.LocationInfo.EnalbeStatus == (int)EnableEnum.Enable) .Where(x => x.StockInfoDetails.Any(d => d.MaterielCode == materielCode && d.Quantity > 0)).ToList().OrderBy(x => x.CreateDate).ToList(); if (stocks == null || stocks.Count() <= 0) { return stocks; } var locations = stocks.Select(s => s.LocationInfo).ToList(); List locationInfos = _stockInfoService.GetStockLocations(locations).Distinct().ToList(); stocks = stocks.Where(s => s.LocationInfo != null && locationInfos.Contains(s.LocationInfo)).ToList(); return stocks; } #endregion 根据单据明细生成出库任务 } }