using AngleSharp.Dom; using log4net.Core; using Mapster; using Masuit.Tools; using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal; using NewLife; using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; using OfficeOpenXml.Table.PivotTable; using SixLabors.Fonts.Tables.AdvancedTypographic; using SqlSugar; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Metadata; using System.Security.Policy; using System.Text.RegularExpressions; using System.Threading.Tasks; using WIDESEA_Cache; using WIDESEA_Common; using WIDESEA_Core.BaseRepository; using WIDESEA_Core.Const; using WIDESEA_Core.Enums; using WIDESEA_DTO.ERP; using WIDESEA_DTO.Location; using WIDESEA_DTO.Stock; using WIDESEA_DTO.WMS; using WIDESEA_IOrderRepository; using WIDESEA_IServices; using WIDESEA_Model.Models; using WIDESEA_Model.Models.Basic; using WIDESEA_Model.Models.ERP; using WIDESEA_Model.Models.Order; using WIDESEA_OrderRepository; using WIDESEA_StorageTaskRepository; using WIDESEAWCS_BasicInfoRepository; using WIDESEAWCS_QuartzJob.Models; using static System.Collections.Specialized.BitVector32; namespace WIDESEA_StorageTaskServices; public partial class Dt_TaskService : ServiceBase, IDt_TaskService { private readonly LogFactory LogFactory = new LogFactory(); private readonly IUnitOfWorkManage _unitOfWorkManage; private readonly IStockInfoRepository _stockInfoRepository; private readonly IStockInfoDetailRepository _stockInfoDetailRepository; private readonly IDt_Task_HtyRepository _task_HtyRepository; private readonly IMapper _mapper; private readonly ILocationInfoRepository _locationRepository; private readonly ITaskExecuteDetailRepository _taskExecuteDetailRepository; private readonly ILocationStatusChangeRecordRepository _locationStatusChangeRecordRepository; private readonly IBoxingInfoRepository _boxingInfoRepository; //组盘 private readonly IDt_AreaInfoRepository _areaInfoRepository; //区域 private readonly IDt_StationManagerRepository _stationManagerRepository; private readonly ISys_ConfigService _configService; private readonly IDt_OrderOutDetailsRepository _orderOutDetailsRepository; public Dt_TaskService(IDt_TaskRepository BaseDal, IUnitOfWorkManage unitOfWorkManage, IStockInfoRepository stockInfoRepository, IDt_Task_HtyRepository task_HtyRepository, IMapper mapper, ILocationInfoRepository locationRepository, ITaskExecuteDetailRepository taskExecuteDetailRepository, ILocationStatusChangeRecordRepository locationStatusChangeRecordRepository, IBoxingInfoRepository boxingInfoRepository, IDt_AreaInfoRepository areaInfoRepository, IStockInfoDetailRepository stockInfoDetailRepository, IDt_StationManagerRepository stationManagerRepository, ISys_ConfigService configService, IDt_OrderOutDetailsRepository orderOutDetailsRepository) : base(BaseDal) { _unitOfWorkManage = unitOfWorkManage; _stockInfoRepository = stockInfoRepository; _task_HtyRepository = task_HtyRepository; _mapper = mapper; _locationRepository = locationRepository; _taskExecuteDetailRepository = taskExecuteDetailRepository; _locationStatusChangeRecordRepository = locationStatusChangeRecordRepository; _boxingInfoRepository = boxingInfoRepository; _areaInfoRepository = areaInfoRepository; _stockInfoDetailRepository = stockInfoDetailRepository; _stationManagerRepository = stationManagerRepository; _configService = configService; _orderOutDetailsRepository = orderOutDetailsRepository; } #region 外部接口方法 #region 出库任务完成 public async Task CompleteOutboundTaskAsync(Dt_Task task, DtStockInfo stock) { WebResponseContent content = new WebResponseContent(); try { var locationStart = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.SourceAddress); var locationEnd = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.TargetAddress); task.TaskState = (int)TaskOutStatusEnum.OutFinish; var taskHty = task.Adapt(); taskHty.FinishTime = DateTime.Now; taskHty.OperateType = App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成; taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System"; stock.ModifyDate = DateTime.Now; stock.LocationCode = task.TargetAddress; var result1 = UpdateLocationStatus(locationStart, LocationEnum.Free, task.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticOutbound); var result2 = UpdateLocationStatus(locationEnd, LocationEnum.InStock, task.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticOutbound); DtStockInfo_Hty stockInfo_Hty = stock.Adapt(); var orderDetails = _orderOutDetailsRepository.QueryData(x => x.PalletCode == task.PalletCode); List orderdetailshtys = new List(); orderDetails.ForEach(item => { orderdetailshtys.Add(item.Adapt()); }); var allocateOrderdetail = orderDetails.Where(x => true).ToList(); await ERPAllocateOut(stock); //调拨出库 if (task.TaskType == (int)TaskOutboundTypeEnum.OutAllocate) { if (orderDetails.Count > 0) await ERPAllocate(orderDetails.Where(x => x.OrderType == (int)OrderTypeEmun.调拨出库单).ToList()); } //其他出库 else if (task.TaskType == (int)TaskOutboundTypeEnum.OutOther) { if (orderDetails.Count > 0) { await ERPMixedSend(orderDetails.Where(x => x.OrderType == (int)OrderTypeEmun.其他出库单).ToList()); } } //生产领料出库 else if (task.TaskType == (int)TaskOutboundTypeEnum.MaterialRequisition) { if (orderDetails.Count > 0) { content = await ERPProduction(orderDetails.Where(x => x.OrderType == (int)OrderTypeEmun.生产领料单).ToList()); } } List boxingInfos = new List(); foreach (var item in allocateOrderdetail) { var boxingInfo = await _boxingInfoRepository.QueryFirstNavAsync(x => x.PalletCode == item.PalletCode); if (boxingInfo == null) { continue; } var boxingdetail = boxingInfo.BoxingInfoDetails.Where(x => x.MaterielCode == item.MaterielCode).ToList(); if (boxingdetail.Count() > 0) { foreach (var detail in boxingdetail) { //detail.Quantity = detail.Quantity - item.OutboundQuantity; detail.Warehouse = "WMS出库缓存区"; detail.WareHouseId = "205"; //if (detail.Quantity <= 0) //{ // boxingInfo.BoxingInfoDetails.Remove(detail); //} } } boxingInfos.Add(boxingInfo); } await _unitOfWorkManage.UseTranAsync(async () => { await DeleteStockInfoAsync(stock.Id); _boxingInfoRepository.UpdateDataNav(boxingInfos); await DeleteStockInfoDetailsAsync(stock.StockInfoDetails); await AddStockInfoHtyAsync(stockInfo_Hty); await _locationStatusChangeRecordRepository.AddDataAsync(result1.Item1); await _locationStatusChangeRecordRepository.AddDataAsync(result2.Item1); await _locationRepository.UpdateDataAsync(result1.Item2); await _locationRepository.UpdateDataAsync(result2.Item2); await _orderOutDetailsRepository.DeleteDataAsync(orderDetails); await SqlSugarHelper.DbWMS.Insertable(orderdetailshtys).ExecuteCommandAsync(); await DeleteTaskAsync(task.TaskId); await AddTaskHtyAsync(taskHty); }); content.OK("出库完成"); } catch (Exception ex) { task.ErrorMessage = ex.Message; await BaseDal.UpdateDataAsync(task); return content.Error(ex.Message); } return content; } #endregion 出库任务完成 #region 移库任务完成 /// /// 移库任务完成 /// /// 任务数据合集 /// 返回结果集 public async Task CompleteTransferTaskAsync(Dt_Task task, DtStockInfo stock) { WebResponseContent content = new WebResponseContent(); try { var locationStart = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.SourceAddress); var locationEnd = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.TargetAddress); task.TaskState = (int)TaskRelocationStatusEnum.AGV_RelocationFinish; var taskHty = task.Adapt(); taskHty.FinishTime = DateTime.Now; taskHty.OperateType = App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成; taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System"; stock.ModifyDate = DateTime.Now; stock.LocationCode = task.TargetAddress; var result = UpdateLocationStatus(locationEnd, LocationEnum.InStock, task.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticRelocation); await _unitOfWorkManage.UseTranAsync(async () => { await _locationStatusChangeRecordRepository.AddDataAsync(result.Item1); await _locationRepository.UpdateDataAsync(result.Item2); _stockInfoRepository.UpdateData(stock); await DeleteTaskAsync(task.TaskId); await AddTaskHtyAsync(taskHty); }); content.OK("移库完成"); } catch (Exception err) { Console.WriteLine(err.Message.ToString()); } return content; } #endregion 移库任务完成 #region 入库任务完成 /// /// 完成入库任务 /// /// 任务数据合集 /// 返回结果集 public async Task CompleteInboundTaskAsync(Dt_Task task) { WebResponseContent content = new WebResponseContent(); try { var boxinfo = await _boxingInfoRepository.QueryFirstNavAsync(x => x.PalletCode == task.PalletCode); var locationStart = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.SourceAddress); var locationEnd = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.TargetAddress); if (boxinfo == null) { return content.Error("未找到组盘数据"); } var stock = CreateStock(boxinfo, task); task.TaskState = (int)TaskInStatusEnum.InFinish; var taskHty = task.Adapt(); taskHty.FinishTime = DateTime.Now; taskHty.OperateType = App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成; taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System"; var result1 = UpdateLocationStatus(task.SourceAddress, LocationEnum.Free, task.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticInbound); var result2 = UpdateLocationStatus(task.TargetAddress, LocationEnum.InStock, task.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticInbound); await ERPAllocate(stock); await _unitOfWorkManage.UseTranAsync(async () => { await _stockInfoRepository.AddDataNavAsync(stock); await DeleteTaskAsync(task.TaskId); await AddTaskHtyAsync(taskHty); await _locationStatusChangeRecordRepository.AddDataAsync(result2.Item1); await _locationStatusChangeRecordRepository.AddDataAsync(result1.Item1); await _locationRepository.UpdateDataAsync(result2.Item2); await _locationRepository.UpdateDataAsync(result1.Item2); }); content.OK("入库完成"); } catch (Exception ex) { task.ErrorMessage = ex.Message; await BaseDal.UpdateDataAsync(task); return content.Error(ex.Message); } return content; } public DtStockInfo CreateStock(DtBoxingInfo boxingInfo,Dt_Task task) { var boxDetail = boxingInfo.BoxingInfoDetails.Adapt>(); boxDetail.ForEach(x => { x.Status = (int)StockStateEmun.已入库; }); return new DtStockInfo() { PalletCode = task.PalletCode, LocationCode = task.TargetAddress, CreateDate = DateTime.Now, Creater = "system", IsFullExit = boxingInfo.IsFullExit, StockInfoDetails = boxDetail, StockStatus = (int)StockStateEmun.已入库 }; } #endregion 入库任务完成 #region AGV搬运任务完成 public async Task CompleteCarryTaskAsync(Dt_Task task,DtStockInfo stockInfo) { WebResponseContent content = new WebResponseContent(); try { var Sourcelocation = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.SourceAddress); var Targetlocation = await _locationRepository.QueryFirstAsync(x => x.LocationCode == task.TargetAddress); //UpdateLocationStatus(Sourcelocation, LocationEnum.Free); //UpdateLocationStatus(Targetlocation, LocationEnum.InStock); task.TaskState = (int)TaskAGVCarryStatusEnum.CarryFinish; var taskHty = task.Adapt(); taskHty.FinishTime = DateTime.Now; taskHty.OperateType = App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成; taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System"; await _unitOfWorkManage.UseTranAsync(async () => { await DeleteTaskAsync(task.TaskId); await AddTaskHtyAsync(taskHty); }); } catch (Exception ex) { return content.Error(ex.Message); } return content; } #endregion #region AGV跨楼层任务完成 public async Task CompleteAcrossFloorTaskAsync(Dt_Task task, DtStockInfo stockInfo) { WebResponseContent content = new WebResponseContent(); try { task.TaskState = (int)TaskAcrossFloorStatusEnum.CarryFinish; var taskHty = task.Adapt(); taskHty.FinishTime = DateTime.Now; taskHty.OperateType = App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成; taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System"; await _unitOfWorkManage.UseTranAsync(async () => { await DeleteTaskAsync(task.TaskId); await AddTaskHtyAsync(taskHty); }); } catch (Exception ex) { return content.Error(ex.Message); } return content; } #endregion #region 任务完成 /// /// 完成任务 /// /// 任务编号 /// 返回结果集 public async Task CompleteAsync(int taskNum) { // 初始化响应内容 WebResponseContent content = new WebResponseContent(); // 提取任务数据 LogFactory.GetLog("任务完成").InfoFormat(true, "提取任务数据", $"任务号:{taskNum}"); // 验证任务是否存在 var task = await GetByTaskNum(taskNum); if (task == null) { return content.Error("任务不存在"); } LogFactory.GetLog("任务完成").InfoFormat(true, "验证任务是否存在", JsonConvert.SerializeObject(task)); // 验证库存是否存在 var stock = await _stockInfoRepository.QueryFirstNavAsync(x => x.PalletCode == task.PalletCode); if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.OutbondGroup) { return await CompleteOutboundTaskAsync(task, stock); } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.InboundGroup) { return await CompleteInboundTaskAsync(task); } else if (task.TaskType.GetTaskTypeGroup() == TaskTypeGroup.RelocationGroup) { return await CompleteTransferTaskAsync(task, stock); } else { return content.Error("未找到任务类型"); } } #endregion 任务完成 #region 取消任务 public WebResponseContent TaskCancel(int taskNum) { WebResponseContent content = new WebResponseContent(); try { Dt_Task task = BaseDal.QueryFirst(x => x.TaskNum == taskNum); if (task == null) { return content = WebResponseContent.Instance.Error("未找到任务信息"); } _unitOfWorkManage.BeginTran(); MethodInfo? methodInfo = GetType().GetMethod(((TaskTypeEnum)task.TaskType) + "TaskCancel"); if (methodInfo != null) { WebResponseContent? responseContent = (WebResponseContent?)methodInfo.Invoke(this, new object[] { task }); if (responseContent != null) { if (responseContent != null) { } } } return content = WebResponseContent.Instance.Error("未找到任务类型对应业务处理逻辑"); } catch (Exception ex) { _unitOfWorkManage.RollbackTran(); return content = WebResponseContent.Instance.Error(ex.Message); } } #endregion #region 请求任务入库 public async Task RequestInboundTaskAsync(RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); try { var boxingInfo = await _boxingInfoRepository.QueryFirstNavAsync(x => x.PalletCode == taskDto.PalletCode && x.StockStatus == (int)StockStateEmun.组盘暂存); if (boxingInfo == null) { return content.Error("托盘信息不存在,请确认托盘已组盘成功"); } foreach (var item in boxingInfo.BoxingInfoDetails) { var ERPStock = SqlSugarHelper.DBERPtext.Queryable<用友即时库存_ST>().Where(x => x.存储地点名称 == item.Warehouse && x.料号 == item.MaterielCode && x.品名 == item.MaterielName && x.库存数量 >= item.Quantity).ToList().FirstOrDefault(); if (ERPStock == null) { return content.Error($"组盘数据未在ERP库存数据中,请人工确认数据是否正确"); } } var StartAddress = await _locationRepository.QueryFirstAsync(x => x.LocationCode == taskDto.Position); if (StartAddress == null) { return content.Error("起点库位未找到"); } if (!LocationIsOutBound(StartAddress)) { return content.Error($"起点库位{StartAddress.LocationCode}搬运路径被占用,请人工确认再下发任务"); } Dt_Task taskNew = new Dt_Task(); DtLocationInfo Endlocation= new DtLocationInfo(); if (taskDto.AreaId != 0) { switch (taskDto.AreaId) { case 1: Endlocation = await GetEmptyLocation("SC1"); taskNew = InboundStakerArea(taskDto, StartAddress, Endlocation); break; case 2: case 3: case 4: case 5: case 6: Endlocation = await GetAGVEmptyCacheLocation(taskDto.AreaId, StartAddress); taskNew = InboundAGVCacheArea(taskDto, StartAddress, Endlocation); break; default: return content.Error("请选择正确的区域信息"); } } else if (taskDto.TargetAddress != null) { Endlocation = _locationRepository.QueryFirst(x => x.LocationCode == taskDto.TargetAddress); if (Endlocation != null && Endlocation.LocationStatus == (int)LocationEnum.Free && Endlocation.EnalbeStatus == 1) { switch (Endlocation.AreaId) { case 1: taskNew = InboundStakerArea(taskDto, StartAddress, Endlocation); break; case 2: case 3: case 4: case 5: case 6: taskNew = InboundAGVCacheArea(taskDto, StartAddress, Endlocation); break; default: return content.Error("货位区域未找到"); } } else { return content.OK("目标库位不可用"); } } else { return content.Error("请选择入库区域或终点地址"); } var taskDTO = CreateListTaskDTO(taskNew); var result1 = UpdateLocationStatus(StartAddress, LocationEnum.InStockDisable, taskNew.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticInbound); var result2 = UpdateLocationStatus(Endlocation, LocationEnum.Lock, taskNew.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticInbound); await _unitOfWorkManage.UseTranAsync(async () => { await _locationStatusChangeRecordRepository.AddDataAsync(result1.Item1); await _locationStatusChangeRecordRepository.AddDataAsync(result2.Item1); await _locationRepository.UpdateDataAsync(result1.Item2); await _locationRepository.UpdateDataAsync(result2.Item2); BaseDal.AddData(taskNew); }); return content = await SendWCSTask(taskDTO); //return content.OK("成功"); } catch (Exception err) { return content.Error(err.Message); } } public Dt_Task InboundStakerArea(RequestTaskDto taskDto, DtLocationInfo StartAddress,DtLocationInfo EndLocation) { var station = _stationManagerRepository.QueryFirst(x => x.stationType == 1 && x.Roadway == "SC1"); if (EndLocation == null) { throw new Exception("无法获取货位信息"); } return new Dt_Task { Grade = 1, Roadway = "SC1", TargetAddress = EndLocation.LocationCode, Dispatchertime = DateTime.Now, MaterialNo = "", NextAddress = station.stationChildCode, OrderNo = null, PalletCode = taskDto.PalletCode, SourceAddress = taskDto.Position, CurrentAddress = taskDto.Position, TaskState = (int)TaskInStatusEnum.InNew, TaskType = (int)TaskInboundTypeEnum.Inbound, TaskNum = BaseDal.GetTaskNo().Result, CreateDate = DateTime.Now, TaskId = 0, AGVTaskNum = GenerateUniqueId(), Floor = "1F", }; } public Dt_Task InboundAGVCacheArea(RequestTaskDto taskDto, DtLocationInfo StartAddress, DtLocationInfo location) { WebResponseContent content = new WebResponseContent(); if (location == null) { throw new Exception("无法获取货位信息"); } Dt_Task taskNew = new Dt_Task(); if (StartAddress.Floor != location.Floor) { taskNew = RequestAcrossFloorTask(StartAddress, location, (int)TaskInboundTypeEnum.Inbound, taskDto); } else { taskNew = RequestAGVCarryTask(StartAddress, location, (int)TaskInboundTypeEnum.Inbound, taskDto); } return taskNew; } #endregion 请求任务入库 #region 更新任务状态 /// /// 更新任务货位 /// /// /// public async Task UpdateTaskStatus(int taskNum, int taskState) { WebResponseContent content = new WebResponseContent(); try { var task = await BaseDal.QueryFirstAsync(x => x.TaskNum == taskNum); if (task == null) return content.Error("未找到任务"); task.TaskState = taskState; var asb = await BaseDal.UpdateDataAsync(task); if (asb) content.OK(); else content.Error(); } catch (Exception ex) { content.Error(ex.Message); } return content; } public async Task RequestLocationAsync(RequestTaskDto input) { await _semaphoreUpdate.WaitAsync(); WebResponseContent content = new WebResponseContent(); try { Dt_Task task = BaseDal.QueryFirst(x => x.PalletCode == input.PalletCode); if (task == null) { return content.Error("任务对象为空"); } task.TaskState = (int)TaskInStatusEnum.Line_InFinish; var location = await GetEmptyLocation(task.Roadway); if (location == null) { return content.Error("无法获取货位信息"); } int beforeStatus = location.LocationStatus; location.LocationStatus = (int)LocationEnum.Lock; task.CurrentAddress = input.Position; task.TargetAddress = location.LocationCode; task.NextAddress = location.LocationCode; task.TaskState = (int)TaskInStatusEnum.Line_InFinish; // 开始事务 var isResult = await UpdateTaskAsync(task, location, beforeStatus); if (!isResult) { _unitOfWorkManage.RollbackTran(); return content.Error("更新任务失败"); } return content.OK(data: task); } catch (Exception) { throw; } finally { _semaphoreUpdate.Release(); } } #endregion #region 请求出库 /// /// 手动出库至缓存区域 /// /// /// public async Task OutBoundTaskAsync(string palletCode) { WebResponseContent content = new WebResponseContent(); try { DtStockInfo stcok = await _stockInfoRepository.QueryFirstNavAsync(x => x.PalletCode == palletCode); if (stcok == null) { return content.Error("托盘信息不存在,请确认托盘已入库成功"); } if (stcok.LocationInfo.LocationStatus != (int)LocationEnum.InStock) { return content.Error("请确认库存货位状态是否为有货"); } var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == palletCode); if (task != null) { return content.Error("该托盘已存在任务"); } var location = await _locationRepository.QueryFirstAsync(x => x.LocationCode == stcok.LocationCode); if (location.AreaId == 2) { return content.Error("该托盘库存已在出库缓存区"); } Dt_Task taskNew = await RequestOutboundTaskAsync(new RequestTaskDto { PalletCode = palletCode, AreaId = 2, Position = stcok.LocationCode, TaskType = (int)TaskOutboundTypeEnum.Outbound }); var taskDto = CreateListTaskDTO(taskNew); var result = GetlcoationState(taskNew, (int)StatusChangeTypeEnum.AutomaticOutbound); await _unitOfWorkManage.UseTranAsync(async () => { BaseDal.AddData(taskNew); _stockInfoRepository.UpdateData(stcok); await _locationStatusChangeRecordRepository.AddDataAsync(result.Item1); await _locationRepository.UpdateDataAsync(result.Item2); }); return content = await SendWCSTask(taskDto); } catch (Exception ex) { return content.Error(ex.Message); } } public async Task OtherOutBoundTaskAsync(List details) { WebResponseContent content = new WebResponseContent(); try { var stock = await _stockInfoRepository.QueryFirstNavAsync(x => x.Id == details[0].StockId); if (stock == null) { return content.Error("未找到库存表头信息"); } if (stock.LocationInfo.LocationStatus != (int)LocationEnum.InStock) { return content.Error("请确认库存货位状态是否为有货"); } var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == stock.PalletCode); if (task != null) { return content.Error("该托盘已存在任务"); } if (stock.LocationInfo.AreaId == 2) { return content.Error("该托盘库存已在出库缓存区"); } Dt_Task taskNew = await RequestOutboundTaskAsync(new RequestTaskDto { PalletCode = stock.PalletCode, AreaId = 2, Position = stock.LocationCode, TaskType = (int)TaskOutboundTypeEnum.OutOther }); List outDetails = new List(); details.Where(x => x.OutboundQuantity > 0).ForEach(x => { if (x.Quantity < x.OutboundQuantity) { throw new Exception($"{x.MaterielName}{x.MaterielCode}出库数量不可大于库存数量"); } outDetails.Add(new Dt_OrderOutDetails() { OrderNo = "", PalletCode = stock.PalletCode, OrderType = (int)OrderTypeEmun.其他出库单, ERPOrderId = "", MaterielCode = x.MaterielCode, MaterielName = x.MaterielName, AllocateWarehouse = "", Warehouse = "智能立库", WareHouseId = "107", AllocateWarehouseId = "", OutboundQuantity = x.OutboundQuantity, }); }); stock.StockInfoDetails = details; var taskDto = CreateListTaskDTO(taskNew); var result = GetlcoationState(taskNew, (int)StatusChangeTypeEnum.AutomaticOutbound); await _unitOfWorkManage.UseTranAsync(async () => { await BaseDal.AddDataAsync(taskNew); await _stockInfoRepository.UpdateDataNavAsync(stock); await _locationStatusChangeRecordRepository.AddDataAsync(result.Item1); await _locationRepository.UpdateDataAsync(result.Item2); await _orderOutDetailsRepository.AddDataAsync(outDetails); }); return content = await SendWCSTask(taskDto); } catch (Exception ex) { return content.Error(ex.Message); } } /// /// 手动调拨 /// /// /// public async Task HandAllocateOutBoundTaskAsync(List details) { WebResponseContent content = new WebResponseContent(); try { var stock = await _stockInfoRepository.QueryFirstNavAsync(x => x.Id == details[0].StockId); if (stock == null) { return content.Error("未找到库存表头信息"); } if (stock.LocationInfo.LocationStatus != (int)LocationEnum.InStock) { return content.Error("请确认库存货位状态是否为有货"); } var task = await BaseDal.QueryFirstAsync(x => x.PalletCode == stock.PalletCode); if (task != null) { return content.Error("该托盘已存在任务"); } if (stock.LocationInfo.AreaId == 2) { return content.Error("该托盘库存已在出库缓存区"); } Dt_Task taskNew = await RequestOutboundTaskAsync(new RequestTaskDto { PalletCode = stock.PalletCode, AreaId = 2, Position = stock.LocationCode, TaskType = (int)TaskOutboundTypeEnum.OutOther }); List outDetails = new List(); details.Where(x => x.OutboundQuantity > 0).ForEach(x => { var areaName = _areaInfoRepository.QueryFirst(y => y.AreaName == x.Remark); if (areaName == null) { throw new Exception($"未找到调拨仓库{x.Remark}数据"); } if (x.Quantity < x.OutboundQuantity) { throw new Exception($"{x.MaterielName}{x.MaterielCode}出库数量不可大于库存数量"); } outDetails.Add(new Dt_OrderOutDetails() { OrderNo = "", PalletCode = stock.PalletCode, OrderType = (int)OrderTypeEmun.调拨出库单, ERPOrderId = "", MaterielCode = x.MaterielCode, MaterielName = x.MaterielName, AllocateWarehouse = x.Remark, Warehouse = "智能立库", WareHouseId = "107", AllocateWarehouseId = areaName.AreaName, OutboundQuantity = x.OutboundQuantity, }); }); stock.StockInfoDetails = details; var taskDto = CreateListTaskDTO(taskNew); var result = GetlcoationState(taskNew, (int)StatusChangeTypeEnum.AutomaticOutbound); await _unitOfWorkManage.UseTranAsync(async () => { await BaseDal.AddDataAsync(taskNew); await _stockInfoRepository.UpdateDataNavAsync(stock); await _locationStatusChangeRecordRepository.AddDataAsync(result.Item1); await _locationRepository.UpdateDataAsync(result.Item2); await _orderOutDetailsRepository.AddDataAsync(outDetails); }); return content = await SendWCSTask(taskDto); } catch (Exception ex) { return content.Error(); } } public (List,List) GetlcoationState(Dt_Task task,int StatusChangeTypeEnum) { List locationStatusChangeRecords = new List(); List locations = new List(); var result1 = UpdateLocationStatus(task.SourceAddress, LocationEnum.InStockDisable, task.TaskNum.Value, StatusChangeTypeEnum); var result2 = UpdateLocationStatus(task.TargetAddress, LocationEnum.Lock, task.TaskNum.Value, StatusChangeTypeEnum); locationStatusChangeRecords.AddRange(result1.Item1); locationStatusChangeRecords.AddRange(result2.Item1); locations.AddRange(result1.Item2); locations.AddRange(result2.Item2); return (locationStatusChangeRecords,locations); } public (List, List) GetlcoationState(List tasks, int StatusChangeTypeEnum) { List locationStatusChangeRecords = new List(); List locations = new List(); foreach (var item in tasks) { var result1 = UpdateLocationStatus(item.SourceAddress, LocationEnum.InStockDisable, item.TaskNum.Value, StatusChangeTypeEnum); var result2 = UpdateLocationStatus(item.TargetAddress, LocationEnum.Lock, item.TaskNum.Value, StatusChangeTypeEnum); locationStatusChangeRecords.AddRange(result1.Item1); locationStatusChangeRecords.AddRange(result2.Item1); locations.AddRange(result1.Item2); locations.AddRange(result2.Item2); } return (locationStatusChangeRecords, locations); } /// /// 请求出库任务 /// /// /// public async Task RequestOutboundTaskAsync(RequestTaskDto taskDto) { DtStockInfo stcok = await _stockInfoRepository.QueryFirstAsync(x => x.PalletCode == taskDto.PalletCode); if (stcok == null) { throw new Exception("托盘信息不存在,请确认托盘已入库成功"); } var StartAddress = await _locationRepository.QueryFirstAsync(x => x.LocationCode == taskDto.Position); if (StartAddress == null) { throw new Exception("起点库位未找到"); } if (!LocationIsOutBound(StartAddress)) { throw new Exception($"起点库位{StartAddress.LocationCode}出库路径被占用,请人工确认再下发任务"); } DtLocationInfo location = null; if (taskDto.AreaId != 0) { if (taskDto.AreaId == 1) { location = await GetEmptyLocation("SC1"); } else { location = await GetAGVEmptyCacheLocation(taskDto.AreaId, StartAddress); } } else if (taskDto.TargetAddress != null) { location = _locationRepository.QueryFirst(x => x.LocationCode == taskDto.TargetAddress); if (location != null && location.LocationStatus != (int)LocationEnum.Free && location.EnalbeStatus == 1) { throw new Exception("目标库位不可用"); } } else { throw new Exception("请选择入库区域或终点地址"); } switch (StartAddress.AreaId) { case 1: return OutboundStakerArea(taskDto, StartAddress, location); case 2: case 3: case 4: case 5: case 6: return OutboundAGVCacheArea(taskDto, StartAddress, location); default: throw new Exception("请选择正确的区域信息"); } } public Dt_Task OutboundStakerArea(RequestTaskDto taskDto, DtLocationInfo StartAddress, DtLocationInfo location) { var station = _stationManagerRepository.QueryFirst(x => x.stationType == 1 && x.Roadway == "SC1"); if (location == null) { throw new Exception("终点区域未找到空闲库位"); } if (location.AreaId == 5 || location.AreaId == 6) { throw new Exception("当前区域不可出库,请联系管理员"); } return new Dt_Task { Grade = Convert.ToInt32(StartAddress.Remark), Roadway = "SC1", TargetAddress = location.LocationCode, Dispatchertime = DateTime.Now, MaterialNo = taskDto.MaterielCode, NextAddress = station.stationChildCode, OrderNo = taskDto.OrderNo, PalletCode = taskDto.PalletCode, SourceAddress = taskDto.Position, CurrentAddress = taskDto.Position, TaskState = (int)TaskOutStatusEnum.OutNew, TaskType = taskDto.TaskType, TaskNum = BaseDal.GetTaskNo().Result, CreateDate = DateTime.Now, TaskId = 0, AGVTaskNum = GenerateUniqueId(), Floor = "1F", }; } public Dt_Task OutboundAGVCacheArea(RequestTaskDto taskDto, DtLocationInfo StartAddress, DtLocationInfo location) { if (location == null) { throw new Exception("起点未定义或终点区域未找到空闲库位"); } Dt_Task taskNew = new Dt_Task(); if (StartAddress.Floor != location.Floor) { taskNew = RequestAcrossFloorTask(StartAddress, location, taskDto.TaskType, taskDto); } else { taskNew = RequestAGVCarryTask(StartAddress, location, taskDto.TaskType, taskDto); } return taskNew; } #endregion 请求出库(实盘&空盘) #region 请求跨楼层2任务 /// /// 请求跨楼层2任务 /// /// /// public async Task AcrossFloorTaskAsync(RequestAcrossFloorTaskDto taskDto) { WebResponseContent content=new WebResponseContent(); try { var task = BaseDal.QueryFirst(x => x.TaskNum == Convert.ToInt32(taskDto.TaskNum) && x.PalletCode == taskDto.PalletCode); if(task == null) return content.Error("未找到任务"); Dt_StationManager stationManager = new Dt_StationManager(); if (task.Floor == "1F") { stationManager = _stationManagerRepository.QueryFirst(x => x.stationType == 5 && x.stationFloor == "2F"); } else { stationManager = _stationManagerRepository.QueryFirst(x => x.stationType == 5 && x.stationFloor == "1F"); } Dt_Task taskNew = new Dt_Task { Grade = 1, Roadway = "AGV", TargetAddress = task.TargetAddress, Dispatchertime = DateTime.Now, MaterialNo = "", NextAddress = task.TargetAddress, OrderNo = null, PalletCode = task.PalletCode, SourceAddress = task.SourceAddress, CurrentAddress = stationManager.stationChildCode, TaskState = (int)TaskAcrossFloorStatusEnum.SecondCarry, TaskType = task.TaskType, TaskNum = BaseDal.GetTaskNo().Result, CreateDate = DateTime.Now, TaskId = 0, AGVTaskNum = GenerateUniqueId(), Floor = stationManager.stationFloor, }; var taskDTO = CreateTaskDTO(taskNew); task.TaskState = (int)TaskAcrossFloorStatusEnum.FirstCarryFinish; var taskHty = task.Adapt(); taskHty.FinishTime = DateTime.Now; taskHty.OperateType = App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成; taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System"; await _unitOfWorkManage.UseTranAsync(async () => { await DeleteTaskAsync(task.TaskId); await AddTaskHtyAsync(taskHty); BaseDal.AddData(taskNew); }); return content.OK(data: taskDTO); } catch (Exception ex) { return content.Error(ex.Message); } } #endregion #region 请求跨楼层任务 public Dt_Task RequestAcrossFloorTask(DtLocationInfo StartAddress, DtLocationInfo EndAddress, int TaskType, RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); var next = _stationManagerRepository.QueryFirst(x => x.stationType == 5 && x.stationFloor == StartAddress.Floor); return new Dt_Task { Grade = StartAddress.Column, Roadway = "AGV", TargetAddress = EndAddress.LocationCode, Dispatchertime = DateTime.Now, MaterialNo = taskDto.MaterielCode, NextAddress = next.stationChildCode, OrderNo = taskDto.OrderNo, PalletCode = taskDto.PalletCode, SourceAddress = StartAddress.LocationCode, CurrentAddress = StartAddress.LocationCode, TaskState = (int)TaskAcrossFloorStatusEnum.CarryNew, TaskType = TaskType, TaskNum = BaseDal.GetTaskNo().Result, CreateDate = DateTime.Now, TaskId = 0, Remark = StartAddress.AreaId.ToString(), AGVTaskNum = GenerateUniqueId(), Floor = StartAddress.Floor, }; } #endregion #region 请求AGV搬运任务 public Dt_Task RequestAGVCarryTask(DtLocationInfo StartAddress, DtLocationInfo EndAddress, int TaskType, RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); return new Dt_Task { Grade = StartAddress.Column, Roadway = "AGV", TargetAddress = EndAddress.LocationCode, Dispatchertime = DateTime.Now, MaterialNo = taskDto.MaterielCode, NextAddress = EndAddress.LocationCode, OrderNo = taskDto.OrderNo, PalletCode = taskDto.PalletCode, SourceAddress = StartAddress.LocationCode, CurrentAddress = StartAddress.LocationCode, TaskState = (int)TaskAGVCarryStatusEnum.CarryNew, TaskType = TaskType, TaskNum = BaseDal.GetTaskNo().Result, CreateDate = DateTime.Now, TaskId = 0, Remark = StartAddress.AreaId.ToString(), AGVTaskNum = GenerateUniqueId(), Floor = StartAddress.Floor, }; } #endregion #region 判断是否需要移库 /// /// 判断堆垛机出库是否需要移库 /// /// /// public async Task StackerIsNeedRelocationAsync(RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); try { var task = BaseDal.QueryFirst(x => x.PalletCode == taskDto.PalletCode && x.TaskNum == taskDto.TaskNum); if (task == null) { return content.Error("未找到任务"); } var location = await _locationRepository.QueryFirstAsync(x => x.LocationCode == taskDto.Position); if (location == null || location.Depth != 2) { return content.OK(data: _mapper.Map(task)); } var locationLateral = _locationRepository.QueryFirst(x => x.RoadwayNo == location.RoadwayNo && x.Row == 1 && x.Layer == location.Layer && x.Column == location.Column); if (locationLateral != null && (locationLateral.LocationStatus == (int)LocationEnum.FreeDisable || locationLateral.LocationStatus == (int)LocationEnum.Free) && locationLateral.EnalbeStatus == 1) { return content.OK(data: _mapper.Map(task)); } else if (locationLateral != null && locationLateral.LocationStatus == 1 && locationLateral.EnalbeStatus == 1) { return content.Error($"一深位异常锁定暂不可出库"); } else if (locationLateral != null && locationLateral.LocationStatus == (int)LocationEnum.InStockDisable && locationLateral.EnalbeStatus == 1) { var TargetAddress = await GetEmptyLocation("SC1"); if (TargetAddress == null) { return content.Error($"未找到可分配货位,请查看是否还有空闲可使用货位"); } //todo查询内侧库存信息 var stock = await _stockInfoRepository.QueryFirstAsync(x => x.LocationCode == locationLateral.LocationCode); Dt_Task taskNew = new Dt_Task { Grade = 1, Roadway = "SC1", TargetAddress = TargetAddress.LocationCode, Dispatchertime = DateTime.Now, MaterialNo = "", NextAddress = TargetAddress.LocationCode, OrderNo = null, PalletCode = stock.PalletCode, SourceAddress = locationLateral.LocationCode, CurrentAddress = locationLateral.LocationCode, TaskState = (int)TaskRelocationStatusEnum.RelocationNew, TaskType = (int)TaskRelocationTypeEnum.Relocation, TaskNum = BaseDal.GetTaskNo().Result, CreateDate = DateTime.Now, TaskId = 0, Floor = "1F", }; var taskDTO = CreateListTaskDTO(taskNew); var isResult = await AddTaskAsync(taskNew, locationLateral, TargetAddress); //UpdateLocationStatus(TargetAddress, LocationEnum.Lock); UpdateLocationStatus(TargetAddress, LocationEnum.Lock, taskNew.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticRelocation); if (!isResult) { _unitOfWorkManage.RollbackTran(); return content.Error("新增任务失败"); } return content.OK(data: taskDTO); } else { return content.Error("货位异常需人工确认才可出库"); } } catch (Exception ex) { return content.Error(ex.Message); } } public async Task AGVIsNeedRelocationAsync(RequestTaskDto taskDto) { WebResponseContent content = new WebResponseContent(); try { var task = BaseDal.QueryFirst(x => x.PalletCode == taskDto.PalletCode && x.TaskNum == taskDto.TaskNum); if (task == null) { return content.Error("未找到任务"); } var location = await _locationRepository.QueryFirstAsync(x => x.LocationCode == taskDto.Position); if (location == null) { return content.Error("未找到货位或者该库位不是二深货位"); } List locationInfos = new List(); switch (location.AreaId) { case 2: locationInfos = _locationRepository.QueryData(x => x.Row == location.Row && x.Column > location.Column && x.Remark == location.Remark && x.AreaId == location.AreaId); break; case 5: case 6: locationInfos = _locationRepository.QueryData(x => x.Row == location.Row && x.Column < location.Column && x.Remark == location.Remark && x.AreaId == location.AreaId); break; default: break; } if (locationInfos.Count == 0) { return content.OK(data: new List { _mapper.Map(task) }); } List taskDTO = new List(); foreach (var item in locationInfos) { if ((item.LocationStatus == 0 || item.LocationStatus == (int)LocationEnum.FreeDisable) && item.EnalbeStatus == 1) { continue; } else { DtLocationInfo Targetlocation = await GetAGVEmptyCacheLocation(item.AreaId, item); if (Targetlocation == null) { return content.Error("起点未定义或终点区域未找到空闲库位"); } //todo查询移库库存信息 Dt_Task taskNew = new Dt_Task { Grade = item.Column, Roadway = "AGV", TargetAddress = Targetlocation.LocationCode, Dispatchertime = DateTime.Now, MaterialNo = "", NextAddress = Targetlocation.LocationCode, OrderNo = null, PalletCode = _random.Next(0, 10000).ToString(), SourceAddress = item.LocationCode, CurrentAddress = item.LocationCode, TaskState = (int)TaskAGVCarryStatusEnum.CarryNew, TaskType = (int)TaskRelocationTypeEnum.Relocation, TaskNum = BaseDal.GetTaskNo().Result, CreateDate = DateTime.Now, TaskId = 0, AGVTaskNum = GenerateUniqueId(), Floor = item.Floor, Remark = item.AreaId.ToString(), }; taskDTO.Add(CreateTaskDTO(taskNew)); var isResult = await AddTaskAsync(taskNew, item, Targetlocation); UpdateLocationStatus(Targetlocation, LocationEnum.Lock, taskNew.TaskNum.Value, (int)StatusChangeTypeEnum.AutomaticRelocation); if (!isResult) { _unitOfWorkManage.RollbackTran(); return content.Error("新增任务失败"); } } } return content.OK(data: taskDTO); } catch (Exception ex) { return content.Error(ex.Message); } } #endregion #region 获取AGV任务号 private static readonly Random _random = new Random(); public static string GenerateUniqueId() { // 获取当前毫秒级时间戳 long timestamp = DateTimeOffset.Now.ToUnixTimeMilliseconds(); // 生成4位随机数(0000-9999) int randomNumber = _random.Next(0, 10000); string randomPart = randomNumber.ToString("D4"); // 补零到4位 return $"{timestamp}{randomPart}"; } #endregion #region 获取任务信息 public WebResponseContent GetTaskInfo() { WebResponseContent content = new WebResponseContent(); try { Expression> expression = x => true; if (!App.User.IsSuperAdmin) { expression = x => x.Creater == App.User.UserName; } var task = BaseDal.Db.Queryable().OrderByDescending(x => x.CreateDate).Take(100).Select(x => new Dt_Task { TaskNum = x.TaskNum, PalletCode = x.PalletCode, TaskType = x.TaskType, SourceAddress = x.SourceAddress, TargetAddress = x.TargetAddress }).ToList(); content = WebResponseContent.Instance.OK(data: task); } catch (Exception ex) { content = WebResponseContent.Instance.Error(ex.Message); } return content; } #endregion #region 获取任务数据 public async Task GetTaskData() { WebResponseContent content = new WebResponseContent(); try { var task = BaseDal.QueryData(x => true); Dictionary obj=new Dictionary() { {"name","已完成"}, }; return content.OK(data:obj); } catch (Exception ex) { return content.Error(ex.Message); } } #endregion #endregion 外部接口方法 #region 调用WCS接口 private string GetWCSIPAddress(string baseIp, string name) { var configz = _configService.GetConfigsByCategory(CateGoryConst.CONFIG_SYS_IPAddress); var wcsBasez = configz.Where(x => x.ConfigKey == baseIp).FirstOrDefault()?.ConfigValue; var address = configz.Where(x => x.ConfigKey == name).FirstOrDefault()?.ConfigValue; if (wcsBasez == null || address == null) { throw new InvalidOperationException("WMS IP 未配置"); } return wcsBasez + address; } public async Task SendWCSTask(List taskDTO) { WebResponseContent content = new WebResponseContent(); var AgvSendTaskAddrss = GetWCSIPAddress(SysConfigConst.WCSIPAddress, SysConfigConst.ReceiveTask); // 发送请求并等待响应 var result = await HttpHelper.PostAsync(AgvSendTaskAddrss, taskDTO.ToJsonString()); content = JsonConvert.DeserializeObject(result.ToString()); return content; } #endregion #region ERP接口调用 public string GetERPIPAddress(string baseIp, string name) { var configz = _configService.GetConfigsByCategory(CateGoryConst.CONFIG_SYS_IPAddress); var wcsBasez = configz.Where(x => x.ConfigKey == baseIp).FirstOrDefault()?.ConfigValue; var address = configz.Where(x => x.ConfigKey == name).FirstOrDefault()?.ConfigValue; if (wcsBasez == null || address == null) { throw new InvalidOperationException("WMS IP 未配置"); } return wcsBasez + address; } /// /// 生产领料 /// /// /// public async Task ERPProduction(List orderOutDetails) { WebResponseContent content = new WebResponseContent(); try { MaterialRequisition materialRequisition = new MaterialRequisition { context = new Context { CultureName = "zh-CN", EntCode = "001", OrgCode = "102", UserCode = "MH0551" }, documentTypeCode = "LL20", businessDate = DateTime.Now.ToString("yyyy-MM-dd"), isApproved = true, issueList = orderOutDetails.Select(item => new issueList { PickListID = item.ERPOrderId, //存储地点 WhCode = "205", //领料数量 IssueQty = item.OutboundQuantity, }).ToList() }; var ERPProduction = GetERPIPAddress(SysConfigConst.ERPIPAddress, SysConfigConst.MaterialRequisition); // 发送请求并等待响应 var result = await HttpsClient.PostAsync(ERPProduction, materialRequisition.ToJsonString()); var respone = JsonConvert.DeserializeObject(result.ToString()); if (respone.d.ResultStatus) { return content.OK(); } return content.Error(respone.d.ResultMsg); } catch (Exception ex) { return content.Error(ex.Message); } } /// /// 调拨 /// /// /// /// public async Task ERPAllocate(DtStockInfo stock) { try { if (stock == null) { throw new Exception("未找到库存信息"); } Allocate allocate = new Allocate { context = new Context { CultureName = "zh-CN", EntCode = "001", OrgCode = "102", UserCode = "MH0551" }, documentTypeCode = "TransIn002", businessDate = DateTime.Now.ToString("yyyy-MM-dd"), isApproved = true, transferInList = stock.StockInfoDetails.Select(item => new transferInList { //物料编码 ItemCode = item.MaterielCode, //调入仓库地址 TransInWHCode = "107", //调入数量 TransInQty = item.Quantity, // 调出仓库编码 TransOutWHCode = item.WareHouseId, }).ToList() }; var Allocate = GetERPIPAddress(SysConfigConst.ERPIPAddress, SysConfigConst.Allocate); // 发送请求并等待响应 var result = await HttpsClient.PostAsync(Allocate, allocate.ToJsonString()); var respone = JsonConvert.DeserializeObject(result.ToString()); if (!respone.d.ResultStatus) { throw new Exception(respone.d.ResultMsg); } } catch (Exception ex) { throw new Exception(ex.Message); } } public async Task ERPAllocateOut(DtStockInfo stock) { try { if (stock == null) { throw new Exception("未找到库存信息"); } Allocate allocate = new Allocate { context = new Context { CultureName = "zh-CN", EntCode = "001", OrgCode = "102", UserCode = "MH0551" }, documentTypeCode = "TransIn002", businessDate = DateTime.Now.ToString("yyyy-MM-dd"), isApproved = true, transferInList = stock.StockInfoDetails.Select(item => new transferInList { //物料编码 ItemCode = item.MaterielCode, //调入仓库地址 TransInWHCode = "205", //调入数量 TransInQty = item.Quantity, // 调出仓库编码 TransOutWHCode = "107", }).ToList() }; var Allocate = GetERPIPAddress(SysConfigConst.ERPIPAddress, SysConfigConst.Allocate); // 发送请求并等待响应 var result = await HttpsClient.PostAsync(Allocate, allocate.ToJsonString()); var respone = JsonConvert.DeserializeObject(result.ToString()); if (!respone.d.ResultStatus) { throw new Exception(respone.d.ResultMsg); } } catch (Exception ex) { throw new Exception(ex.Message); } } public async Task ERPAllocate(List orderOutDetails) { try { if (orderOutDetails.Count <= 0) { throw new Exception($"未找到调拨出库数据"); } List transferInList=new List(); orderOutDetails.ForEach(x => { transferInList.Add(new transferInList { //物料编码 ItemCode = x.MaterielCode, //调入仓库地址 TransInWHCode = x.AllocateWarehouseId, //调入数量 TransInQty = x.OutboundQuantity, // 调出仓库编码 TransOutWHCode = "205", }); }); Allocate allocate = new Allocate { context = new Context { CultureName = "zh-CN", EntCode = "001", OrgCode = "102", UserCode = "MH0551" }, documentTypeCode = "TransIn002", businessDate = DateTime.Now.ToString("yyyy-MM-dd"), isApproved = true, transferInList = transferInList, }; var Allocate = GetERPIPAddress(SysConfigConst.ERPIPAddress, SysConfigConst.Allocate); // 发送请求并等待响应 var result = await HttpsClient.PostAsync(Allocate, allocate.ToJsonString()); var respone = JsonConvert.DeserializeObject(result.ToString()); if (!respone.d.ResultStatus) { throw new Exception($"ERP调拨出库{respone.d.ResultMsg}"); } } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 杂发 /// /// /// public async Task ERPMixedSend(List orderOutDetails) { try { if (orderOutDetails.Count <= 0) { throw new Exception($"未找到调拨出库数据"); } MixedSend send = new MixedSend { context = new Context { CultureName = "zh-CN", EntCode = "001", OrgCode = "102", UserCode = "MH0551" }, documentTypeCode = "MiscShip001", businessDate = DateTime.Now.ToString("yyyy-MM-dd"), isApproved = true, miscShipList = orderOutDetails.Select(item => new miscShipList { //物料编码 ItemCode = item.MaterielCode, //存储地点编号 WhCode = "205", //杂发数量 Qty = item.OutboundQuantity, BenefitDeptCode = "0505", }).ToList() }; var ERPMixedSend = GetERPIPAddress(SysConfigConst.ERPIPAddress, SysConfigConst.MixedSend); // 发送请求并等待响应 var result = await HttpsClient.PostAsync(ERPMixedSend, send.ToJsonString()); var respone = JsonConvert.DeserializeObject(result.ToString()); if (!respone.d.ResultStatus) { throw new Exception($"ERP其他出库{respone.d.ResultMsg}"); } } catch (Exception ex) { throw new Exception(ex.Message); } } /// /// 杂收 /// /// /// public async Task ERPMixedReceive(string palletCode) { WebResponseContent content = new WebResponseContent(); try { DtStockInfo stock = await _stockInfoRepository.QueryFirstNavAsync(x => x.PalletCode == palletCode); MixedReceive allocate = new MixedReceive { context = new Context { CultureName = "zh-CN", EntCode = "001", OrgCode = "102", UserCode = "MH0551" }, documentTypeCode = "TransIn002", businessDate = DateTime.Now.ToString("yyyy-MM-dd"), isApproved = true, miscRcvList = stock.StockInfoDetails.Where(x => x.OutboundQuantity > 0).Select(item => new miscRcvList { ItemCode = item.MaterielCode, WhCode = item.Warehouse, Qty = item.OutboundQuantity, CostPrice = 0, }).ToList() }; return content.OK(data: allocate); } catch (Exception ex) { return content.Error(ex.Message); } } /// /// 退料 /// /// /// public async Task ERPreturnMaterialList(string palletCode) { WebResponseContent content = new WebResponseContent(); try { DtStockInfo stock = await _stockInfoRepository.QueryFirstNavAsync(x => x.PalletCode == palletCode); ReturnMaterials allocate = new ReturnMaterials { context = new Context { CultureName = "zh-CN", EntCode = "001", OrgCode = "102", UserCode = "MH0551" }, documentTypeCode = "TransIn002", businessDate = DateTime.Now.ToString("yyyy-MM-dd"), isApproved = true, returnMaterialList = stock.StockInfoDetails.Select(item => new returnMaterialList { PickListID = item.MaterielCode, WhCode = item.Warehouse, RecedeQty = item.OutboundQuantity, RecedeReason = 1, }).ToList() }; return content.OK(data: allocate); } catch (Exception ex) { return content.Error(ex.Message); } } #endregion #region 内部调用方法 public (List,List) UpdateLocationStatus(DtLocationInfo location, LocationEnum locationStatus, int taskNum, int StatusChangeType) { List locations = GetGroupLocations(location); List Beforelocation = locations.Select(x => new DtLocationInfo { Id = x.Id, LocationCode = x.LocationCode, LocationStatus = x.LocationStatus }).ToList(); foreach (var item in locations) { if (locationStatus == LocationEnum.Lock) { if (item.LocationCode == location.LocationCode) { item.LocationStatus = (int)LocationEnum.Lock; } else if (item.LocationStatus == (int)LocationEnum.Free) { item.LocationStatus = (int)LocationEnum.FreeDisable; } } else if (locationStatus == LocationEnum.InStock) { if (item.LocationCode == location.LocationCode) { item.LocationStatus = (int)LocationEnum.InStock; } else if (item.LocationStatus == (int)LocationEnum.FreeDisable) { item.LocationStatus = (int)LocationEnum.Free; } } else if (locationStatus == LocationEnum.InStockDisable) { if (item.LocationStatus == (int)LocationEnum.InStock) { item.LocationStatus = (int)LocationEnum.InStockDisable; } else if (item.LocationStatus == (int)LocationEnum.Free) { item.LocationStatus = (int)LocationEnum.FreeDisable; } } else if (locationStatus == LocationEnum.Free) { if (item.LocationCode == location.LocationCode) { item.LocationStatus = (int)LocationEnum.Free; } else if (item.LocationStatus == (int)LocationEnum.FreeDisable || item.LocationStatus == (int)LocationEnum.InStockDisable) { item.LocationStatus = (int)LocationEnum.Free; } } } List changeRecordDto = new List(); foreach (var item in Beforelocation) { var loc = locations.Where(x => x.LocationCode == item.LocationCode).FirstOrDefault(); if (loc != null) { DtLocationStatusChangeRecord dtLocationStatusChangeRecord = new DtLocationStatusChangeRecord() { ChangeType = StatusChangeType, LocationCode = item.LocationCode, LocationId = loc.Id, Creater = "System", TaskNum = taskNum, AfterStatus = loc.LocationStatus, BeforeStatus = item.LocationStatus, }; changeRecordDto.Add(dtLocationStatusChangeRecord); } } //_locationStatusChangeRecordRepository.AddStatusChangeRecord(changeRecordDto); //_locationRepository.UpdateData(locations); return (changeRecordDto,locations); } public (List, List) UpdateLocationStatus(string locationCode, LocationEnum locationStatus, int taskNum, int StatusChangeType) { var location = _locationRepository.QueryFirst(x => x.LocationCode == locationCode); List locations = GetGroupLocations(location); List Beforelocation = locations.Select(x => new DtLocationInfo { Id = x.Id, LocationCode = x.LocationCode, LocationStatus = x.LocationStatus }).ToList(); foreach (var item in locations) { if (locationStatus == LocationEnum.Lock) { if (item.LocationCode == location.LocationCode) { item.LocationStatus = (int)LocationEnum.Lock; } else if (item.LocationStatus == (int)LocationEnum.Free) { item.LocationStatus = (int)LocationEnum.FreeDisable; } } else if (locationStatus == LocationEnum.InStock) { if (item.LocationCode == location.LocationCode) { item.LocationStatus = (int)LocationEnum.InStock; } else if (item.LocationStatus == (int)LocationEnum.FreeDisable) { item.LocationStatus = (int)LocationEnum.Free; } } else if (locationStatus == LocationEnum.InStockDisable) { if (item.LocationStatus == (int)LocationEnum.InStock) { item.LocationStatus = (int)LocationEnum.InStockDisable; } else if (item.LocationStatus == (int)LocationEnum.Free) { item.LocationStatus = (int)LocationEnum.FreeDisable; } } else if (locationStatus == LocationEnum.Free) { if (item.LocationCode == location.LocationCode) { item.LocationStatus = (int)LocationEnum.Free; } else if (item.LocationStatus == (int)LocationEnum.FreeDisable || item.LocationStatus == (int)LocationEnum.InStockDisable) { item.LocationStatus = (int)LocationEnum.Free; } } } List changeRecordDto = new List(); foreach (var item in Beforelocation) { var loc = locations.Where(x => x.LocationCode == item.LocationCode).FirstOrDefault(); if (loc != null) { DtLocationStatusChangeRecord dtLocationStatusChangeRecord = new DtLocationStatusChangeRecord() { ChangeType = StatusChangeType, LocationCode = item.LocationCode, LocationId = loc.Id, Creater = "System", TaskNum = taskNum, AfterStatus = loc.LocationStatus, BeforeStatus = item.LocationStatus, }; changeRecordDto.Add(dtLocationStatusChangeRecord); } } //_locationStatusChangeRecordRepository.AddStatusChangeRecord(changeRecordDto); //_locationRepository.UpdateData(locations); return (changeRecordDto, locations); } public List GetGroupLocations(DtLocationInfo location) { List locationInfos = _locationRepository.QueryData(x => x.AreaId == location.AreaId); List locations = new List() { location }; if (location.AreaId == 1) { if (location.Depth == 2) { DtLocationInfo? locationInfo = locationInfos.FirstOrDefault(x => x.Depth == 1 && x.Column == location.Column && x.Layer == location.Layer && x.Row == 1); if (locationInfo != null) { locations.Add(locationInfo); } } } else if (location.AreaId == 2) { var locationLateral = _locationRepository.QueryData(x => x.Row == location.Row && x.Column > location.Column && x.Remark == location.Remark); if (locationLateral.Count > 0) { locations.AddRange(locationLateral); } } else if (location.AreaId == 5 || location.AreaId == 6) { var locationLateral = _locationRepository.QueryData(x => x.Row == location.Row && x.Column < location.Column && x.Remark == location.Remark); if (locationLateral.Count > 0) { locations.AddRange(locationLateral); } } return locations; } /// /// 创建任务DTO /// private List CreateListTaskDTO(Dt_Task task) { return new List { 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, } }; } 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 }; } private async Task DeleteStockInfoAsync(int stockId) { var isStockUpdated = await _stockInfoRepository.DeleteDataByIdAsync(stockId); if (!isStockUpdated) { throw new Exception("库存信息更新失败"); } } private async Task AddStockInfoHtyAsync(DtStockInfo_Hty dtStock) { var isStockAdd = await SqlSugarHelper.DbWMS.InsertNav(dtStock).IncludesAllFirstLayer().ExecuteCommandAsync(); if (!isStockAdd) { throw new Exception("库存历史信息添加失败"); } } private async Task DeleteBoxingInfoAsync(int boxingId) { var isStockUpdated = await _stockInfoRepository.DeleteDataByIdAsync(boxingId); if (!isStockUpdated) { throw new Exception("库存信息更新失败"); } } private async Task AddBoxingHtyAsync(DtBoxingInfo_Hty boxingInfo) { var isStockAdd = await SqlSugarHelper.DbWMS.InsertNav(boxingInfo).IncludesAllFirstLayer().ExecuteCommandAsync(); if (!isStockAdd) { throw new Exception("组盘历史信息添加失败"); } } private async Task DeleteStockInfoDetailsAsync(IEnumerable details) { var ids = details.Select(x => (object)x.Id).ToArray(); var isStockDetailUpdated = await _stockInfoDetailRepository.DeleteDataByIdsAsync(ids); if (!isStockDetailUpdated) { throw new Exception("库存详情信息更新失败"); } } private async Task DeleteTaskAsync(int taskId) { var isTaskUpdated = await BaseDal.DeleteDataByIdAsync(taskId); if (!isTaskUpdated) { throw new Exception("任务信息更新失败"); } } private async Task AddTaskHtyAsync(Dt_Task_Hty taskHty) { var isTaskAdd = await _task_HtyRepository.AddDataAsync(taskHty) > 0; if (!isTaskAdd) { throw new Exception("历史任务信息添加失败"); } } public override WebResponseContent DeleteData(object[] key) { WebResponseContent content = new WebResponseContent(); // 创建历史任务实例模型 try { foreach (var item in key) { Dt_Task task = BaseDal.QueryFirst(x => x.TaskId == Convert.ToInt32(key)); if (task == null) { return content.Error("未找到任务信息!"); } var taskHtyNG = CreateHistoricalTask(task, true); // 添加历史任务 var isTaskHtyAdd = _task_HtyRepository.AddData(taskHtyNG) > 0; // 删除任务数据 var isTaskDelete = BaseDal.Delete(task.TaskId); } return content.OK("删除成功!"); } catch (Exception ex) { return content.Error("删除任务异常:" + ex.Message); } } /// /// 根据任务号获取任务 /// /// /// public async Task GetByTaskNum(int taskNum) { return await BaseDal.QueryFirstAsync(x => x.TaskNum == taskNum); } public async Task GetByTaskAddress(string SourceAddress, string TargetAddress) { return await BaseDal.QueryFirstAsync(x => x.SourceAddress == SourceAddress|| x.TargetAddress== TargetAddress); } #endregion 内部调用方法 #region private 内部方法 /// /// 创建历史任务记录 /// /// /// private Dt_Task_Hty CreateHistoricalTask(Dt_Task task, bool isHand = false) { // 更新任务状态 task.TaskState = task.TaskType > 199 ? (int)TaskInStatusEnum.InFinish : (int)TaskOutStatusEnum.OutFinish; task.CurrentAddress = task.NextAddress; // 创建历史任务 var taskHty = _mapper.Map(task); taskHty.FinishTime = DateTime.Now; taskHty.TaskId = 0; taskHty.OperateType = isHand ? (int)OperateTypeEnum.人工删除 : App.User.UserName != null ? (int)OperateTypeEnum.人工完成 : (int)OperateTypeEnum.自动完成; taskHty.SourceId = task.TaskId; if (isHand) { taskHty.Creater = App.User.UserName != null ? App.User.UserName : "System"; } return taskHty; } #region 任务请求方法 private static readonly SemaphoreSlim _semaphoreUpdate = new SemaphoreSlim(1, 1); // 更新任务货位 // 修改任务 private async Task UpdateTaskAsync(Dt_Task task, DtLocationInfo location, int beforeStatus) { bool isResult = await BaseDal.UpdateDataAsync(task); LocationChangeRecordDto changeRecordDto = new LocationChangeRecordDto() { AfterStatus = location.LocationStatus, BeforeStatus = beforeStatus, TaskNum = task.TaskNum.Value, LocationId = location.Id, LocationCode = location.LocationCode, ChangeType = (int)StatusChangeTypeEnum.AutomaticInbound, }; bool isUpdateChange = _locationStatusChangeRecordRepository.AddStatusChangeRecord(changeRecordDto); bool isUpdateLo = await _locationRepository.UpdateDataAsync(location); return isResult && isUpdateLo; } private async Task AddTaskAsync(Dt_Task task, DtLocationInfo StartAddress, DtLocationInfo EndAddress) { //UpdateLocationStatus bool isResult = await BaseDal.AddDataAsync(task) > 0; int SourcebeforeStatus = StartAddress.LocationStatus; int TargetbeforeStatus = EndAddress.LocationStatus; StartAddress.LocationStatus = (int)LocationEnum.InStockDisable; EndAddress.LocationStatus = (int)LocationEnum.Lock; List changeRecordDto = new List() { new LocationChangeRecordDto() { AfterStatus = StartAddress.LocationStatus, BeforeStatus = SourcebeforeStatus, TaskNum = task.TaskNum.Value, LocationId = StartAddress.Id, LocationCode = StartAddress.LocationCode, ChangeType = (int)StatusChangeTypeEnum.AutomaticInbound, }, new LocationChangeRecordDto() { AfterStatus = EndAddress.LocationStatus, BeforeStatus = TargetbeforeStatus, TaskNum = task.TaskNum.Value, LocationId = EndAddress.Id, LocationCode = EndAddress.LocationCode, ChangeType = (int)StatusChangeTypeEnum.AutomaticInbound, }, }; bool isUpdateChange = _locationStatusChangeRecordRepository.AddStatusChangeRecord(changeRecordDto); bool Source = await _locationRepository.UpdateDataAsync(StartAddress); bool Target = await _locationRepository.UpdateDataAsync(EndAddress); return isResult && Source && Target; } /// /// 获取货位号 /// /// public async Task GetEmptyLocation(string roadWay) { List locations = await _locationRepository.QueryDataAsync(x => x.RoadwayNo == "SC1" && x.LocationStatus == (int)LocationEnum.Free && x.EnalbeStatus == 1); if (locations.Count < 2) { return null; } List locationInfos = new List(); var locationInside = locations.Where(x => x.Row == 3).ToList(); if (locations.Where(x => x.Row == 2).OrderBy(x => x.Layer).ThenBy(x => x.Column).FirstOrDefault() != null) { return locations.Where(x => x.Row == 2).ToList().OrderBy(x => x.Layer).ThenBy(x => x.Column).FirstOrDefault(); } else if (locationInside.Count > 0) { foreach (var item in locationInside) { var locationLateral = _locationRepository.QueryFirst(x => x.Row == 1 && x.Layer == item.Layer && x.Column == item.Column); if (locationLateral.LocationStatus == (int)LocationEnum.Free && locationLateral.EnalbeStatus == 1) { locationInfos.Add(item); } } return locationInfos.Distinct().OrderBy(x => x.Layer).ThenBy(x => x.Column).FirstOrDefault(); } else if (locations.Where(x => x.Row == 1).OrderBy(x => x.Layer).ThenBy(x => x.Column).FirstOrDefault() != null) { return locations.Where(x => x.Row == 1).OrderBy(x => x.Layer).ThenBy(x => x.Column).FirstOrDefault(); } else { return null; } } public async Task GetAGVEmptyCacheLocation(int AreaId, DtLocationInfo loc) { if (loc == null) { return null; } switch (AreaId) { case 2: return await FromShallowToDeep(AreaId, loc); case 3: return await AGVLIKU(AreaId); case 5: case 6: return await FromDeepToShallow(AreaId, loc); default: return null; } } /// /// 由深到浅 /// /// /// public async Task FromDeepToShallow(int AreaId, DtLocationInfo loc) { List locations = new List(); if (AreaId == loc.AreaId) { locations = await _locationRepository.QueryDataAsync(x => x.AreaId == AreaId && x.LocationStatus == (int)LocationEnum.Free && x.EnalbeStatus == 1 && x.Row != loc.Row); } else { locations = await _locationRepository.QueryDataAsync(x => x.AreaId == AreaId && x.LocationStatus == (int)LocationEnum.Free && x.EnalbeStatus == 1); } if (locations.Count == 0) { return null; } List locationInfos = new List(); foreach (var item in locations) { var locationLateral = _locationRepository.QueryData(x => x.Row == item.Row && x.Column < item.Column && x.Remark == item.Remark); bool Isavailable = true; foreach (var lateral in locationLateral) { if (lateral.LocationStatus != (int)LocationEnum.Free && lateral.EnalbeStatus == 1) { Isavailable = false; continue; } } if (Isavailable) locationInfos.Add(item); } return locationInfos.Distinct().OrderByDescending(x => x.Column).ThenBy(x => x.Row).FirstOrDefault(); } /// /// 由浅到深 /// /// /// public async Task FromShallowToDeep(int AreaId, DtLocationInfo loc) { List locations = new List(); if (AreaId == loc.AreaId) { locations = await _locationRepository.QueryDataAsync(x => x.AreaId == AreaId && x.LocationStatus == (int)LocationEnum.Free && x.EnalbeStatus == 1 && x.Row != loc.Row); } else { locations = await _locationRepository.QueryDataAsync(x => x.AreaId == AreaId && x.LocationStatus == (int)LocationEnum.Free && x.EnalbeStatus == 1); } if (locations.Count == 0) { return null; } List locationInfos = new List(); foreach (var item in locations) { var locationLateral = _locationRepository.QueryData(x => x.Row == item.Row && x.Column > item.Column && x.Remark == item.Remark); if (locationLateral.Count == 0) { locationInfos.Add(item); continue; } foreach (var Lateral in locationLateral) { if (locationInfos.Contains(Lateral)) continue; if (Lateral.LocationStatus == (int)LocationEnum.Free && Lateral.EnalbeStatus == 1) { locationInfos.Add(item); } } } return locationInfos.Distinct().OrderBy(x => x.Column).ThenBy(x => x.Row).FirstOrDefault(); } public async Task AGVLIKU(int AreaId) { WebResponseContent content = new WebResponseContent(); List locations = await _locationRepository.QueryDataAsync(x => x.AreaId == AreaId && x.LocationStatus == 0 && x.EnalbeStatus == 1); var location = locations.OrderBy(x => x.Layer).ThenBy(x => x.Column).FirstOrDefault(); return location; } public bool LocationIsOutBound(DtLocationInfo location) { int sum = 0; if (location.AreaId == 1) { if (location.Depth == 2) { var locationLateral = _locationRepository.QueryFirst(x => x.Row == 1 && x.Column == location.Column && x.Layer == location.Layer); if (locationLateral.LocationStatus == (int)LocationEnum.Lock && locationLateral.EnalbeStatus == 1) { return false; } } } else if (location.AreaId == 2) { var locationLateral = _locationRepository.QueryData(x => x.Row == location.Row && x.Column > location.Column && x.Remark == location.Remark); foreach (var Lateral in locationLateral) { if (Lateral.LocationStatus == (int)LocationEnum.Lock && Lateral.EnalbeStatus == 1) { return false; } } } else if (location.AreaId == 5 || location.AreaId == 6) { var locationLateral = _locationRepository.QueryData(x => x.Row == location.Row && x.Column < location.Column && x.Remark == location.Remark); foreach (var lateral in locationLateral) { if (lateral.LocationStatus == (int)LocationEnum.Lock && lateral.EnalbeStatus == 1) { return false; } } } return true; } #endregion 任务请求方法 #endregion private 内部方法 }