using Admin.NET.Application; using Admin.NET.Core.TaskModule.Enum; using iWareCommon; using iWareCommon.Utils; using iWareModel.Entity.MES; using iWareModel.Entity.WCS; using iWareSql.DataAccess; using iWareSql.MyDbContext; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; namespace iWareCC.Common.Helper { /// /// 下发任务帮助类 【EditBy shaocx,2022-02-05】 /// public class IssueTaskHelper { /// /// 所有巷道的出库任务 /// /// /// /// public static bool Out(MyDbContext mycontext, string WcsIp, int Lane, List wms_tasks, ref string errMsg) { // List wcsTaskInputs = new List(); // WCSTaskInput wcsTask = new WCSTaskInput(); // //State 任务状态 0 - 未下发WCS ,1 - 已下发WCS // //TaskState 任务状态 0-未执行,1-已暂停,2-执行中,3-已完成 // // TaskCategory 任务类别 1入库任务 2出库任务,3移库任务 // //出库任务查找 // //var wms_tasks = mycontext.wms_task.Where(x => x.TaskState != 3 && (x.IsDeleted ==null || x.IsDeleted == false) && x.State == 0 && x.AreaType == (int)AreaTypeEnum.立体库 && x.TaskCategory == 2 && x.Lane==Lane).OrderByDescending(x => x.TaskPriority).ToList();//查询未WCS下发未完成的任务 // if (wms_tasks == null || wms_tasks.Count <= 0) // { // SystemWarningMsg._lbl_Alert_OutPlanTaskHandler = "当前未存在出入库任务"; // return false; // } // wms_task singleTask = null; // var needFirstTask = wms_tasks.Where(x => x.MoveType == (int)MoveTypeEnum.移库&&x.BusinessType==(int)BusinessTypeEnum.销售下架).OrderByDescending(x => x.TaskPriority).FirstOrDefault(); // //这个是需要首发的 // var isInsideLocation = FindEmptyLocationHelper.IsInsideLocation(needFirstTask.SourcePlace); // if (isInsideLocation == false) // {//外侧库位 // singleTask = needFirstTask; // } // else // {//如果是内侧库位, 1排和4排,需要校验下 这个1排和4排是否有未完结的任务,如果有,就不要出 // var outsideLocation = FindEmptyLocationHelper.GetWidesideLocation(needFirstTask.FromLocationCode); // var noFinishedTask = TaskHandler.IsExistNoFinishedTask(mycontext, outsideLocation); // if (noFinishedTask == null) // {//外侧没有任何任务占用,就下发该库位 // singleTask = needFirstTask; // } // else // {//有任务占用该外侧库位 // //如果是 出库任务,则优先干 // if (noFinishedTask.TaskCategory == 2 && noFinishedTask.TaskState == 0) // { // singleTask = noFinishedTask; // } // else // { // //那么只能不处理这个任务了。不下发 // errMsg = $"准备要下发出库任务{needFirstTask.TaskNo},但是他是内侧库位,并且外侧库位{outsideLocation}有未结束的任务占用,所以无法下发这个任务{needFirstTask.TaskNo}"; // singleTask = null; // } // } // } // //原先的寻找下发逻辑 【2023-11-1】 // /* // singleTask = wms_tasks.Where(x => x.TaskCategory == 2 && (x.Row == 2 || x.Row == 3)).OrderByDescending(x => x.TaskPriority).FirstOrDefault();//出库任务先找2-3排 // if (singleTask == null) // { // singleTask = wms_tasks.Where(x => x.TaskCategory == 2 && (x.Row == 1 || x.Row == 4)).OrderByDescending(x => x.TaskPriority).FirstOrDefault(); // } // //*/ // if (singleTask != null) // { // return SingleOut(mycontext, WcsIp, singleTask, ref errMsg); // } return true; } /// /// 所有巷道的单个出库任务处理 /// /// /// /// // private static bool SingleOut(MyDbContext mycontext, string WcsIp, wms_task singleTask, ref string errMsg) //{ //List wcsTaskInputs = new List(); //WCSTaskInput wcsTask = new WCSTaskInput(); ////State 任务状态 0 - 未下发WCS ,1 - 已下发WCS ////TaskState 任务状态 0-未执行,1-已暂停,2-执行中,3-已完成 //// TaskCategory 任务类别 1入库任务 2出库任务,3移库任务 //#region 存在未下发的任务,生成WCS任务 //int Priority = int.Parse(singleTask.TaskPriority.ToString()); //bool isLane3 = false; //int palletType = MyExtendHelper.GetPalletType(mycontext, singleTask.ContainerCode, ref isLane3); //// var containers = GetWareContainerType(mycontext, singleTask.ContainerCode);//查询容器类型 //wcsTask.WmsTaskNo = singleTask.TaskNo; //wcsTask.TaskName = singleTask.TaskName; //wcsTask.TaskType = int.Parse(singleTask.TaskCategory.ToString()); //wcsTask.Container = singleTask.ContainerCode; //wcsTask.High = 1; //wcsTask.PalletType = palletType; //wcsTask.SourcePlace = singleTask.FromLocationCode; //wcsTask.ToPlace = ""; //wcsTask.Creator = "cc"; //wcsTask.Timestamp = DateTime.UtcNow.ToString(); //wcsTask.Priority = Priority; //#endregion //var arr = singleTask.FromLocationCode.Split('-'); //string needMoveWareLocationCode = string.Empty;//需要移库的库位,即外侧的库位 //if (arr[2] == "1") //{ // needMoveWareLocationCode = arr[0] + "-" + arr[1] + "-2-" + arr[3]; //} //else if (arr[2] == "4") //{ // needMoveWareLocationCode = arr[0] + "-" + arr[1] + "-3-" + arr[3]; //} ////判断箱子在里侧还是外侧(修改任务为下发状态,直接下发WCS任务)还是里侧(判断外侧是否有箱子,并判断外侧箱子是否有任务) //wms_task moveTask = null; //wms_task move_out_Task = null;//移库出库任务 //if (!string.IsNullOrEmpty(needMoveWareLocationCode)) //{ // //如果此时外面的库位有任务被占用,就暂时不处理 【Editby shaocx,2023-03-03】 // var noFinishedTask = TaskHandler.IsExistNoFinishedTask(mycontext, needMoveWareLocationCode); // if (noFinishedTask != null) // { // errMsg = $"出库任务{singleTask.FromLocationCode}的外侧库位{needMoveWareLocationCode}当前有未结束的任务,暂时不清楚是否需要移库!"; // TaskHandler.UpdateTaskMsg(singleTask.Id, errMsg);//判断如果有错误日志,就更新任务表的消息 【Editby shaocx,2023-04-08】 // return false; // } // //下面的代码注释,因为库位上有库存,目前设计是 库位就锁定,暂时不判断锁定状态 【Editby shaocx,2023-03-04】 // //var needMoveWareLocation = mycontext.ware_location.Where(x => x.Code == needMoveWareLocationCode).FirstOrDefault(); // //if (needMoveWareLocation.IsLocked == 1) // //{ // // errMsg = $"出库任务{singleTask.FromLocationCode}的外侧库位{needMoveWareLocationCode}被锁定,锁定原因:{needMoveWareLocation.LockRemark}!"; // // return false; // //} // var lvc = mycontext.ware_location_vs_container.Where(x => !string.IsNullOrEmpty(needMoveWareLocationCode) && x.WareLocationCode == needMoveWareLocationCode && (x.IsDeleted == null || x.IsDeleted == false)).FirstOrDefault();// 出库任务是1-4列判断2-3是否有容器 // if (lvc != null)//外侧存在箱子 // {//需要移库 // var moveResult = CreateMoveTask(mycontext, needMoveWareLocationCode, singleTask, lvc, Priority, ref wcsTaskInputs, ref errMsg, ref moveTask, ref move_out_Task); // if (moveResult == false) // { // TaskHandler.UpdateTaskMsg(singleTask.Id, errMsg);//判断如果有错误日志,就更新任务表的消息 【Editby shaocx,2023-04-08】 // return false; // } // } //} //wcsTaskInputs.Add(wcsTask); //bool wcsResult = CreateBatchTask(wcsTaskInputs, WcsIp, ref errMsg); //if (wcsResult) //{ // //成功后,修改任务状态 // singleTask.State = 1;//修改任务为下发状态 // singleTask.IssueTime = DateTime.Now;//增加下发时间 【Editby shaocx,2023-03-03】 // singleTask.TaskMsg = "下发成功"; // singleTask.UpdatedTime = DateTime.Now; // if (moveTask != null) // {//移库 // mycontext.wms_task.Add(moveTask); // //锁定 移库的起点和目标点 // MyExtendHelper.LockLocation(true, mycontext, moveTask.ToLocationCode, "移库操作,锁定目标库位,下发出库任务"); // MyExtendHelper.LockLocation(true, mycontext, moveTask.FromLocationCode, "移库操作,锁定开始库位,下发出库任务"); // } // if (move_out_Task != null) // {//移库出库任务 // mycontext.wms_task.Add(move_out_Task); // //锁定 移库出库的起点 // MyExtendHelper.LockLocation(true, mycontext, move_out_Task.FromLocationCode, "移库出库操作,锁定开始库位,下发出库任务"); // } //} //else //{ // singleTask.TaskMsg = "下发失败:" + errMsg; // singleTask.UpdateTime = DateTime.Now; //} //if (mycontext.SaveChanges() > 0) //{ // return true; //} //else //{ // return false; //} // } #region 移库有关 /// /// 获取库中的高度值 /// /// /// /// /// //private static int GetDetectionHeight(ware_location_vs_container move_ware_location_vs_container, int PalletType) //{ // if (move_ware_location_vs_container.DetectionHeight == null) // { // //自行计算高度 // string[] arr = move_ware_location_vs_container.WareLocationCode.Split('-'); // int layer = Convert.ToInt32(arr[3]);//层高 // //3-1-3-8 巷道-列-排-层 // /* // * 塑料托盘, 只有两个高度,1层的高度值是2, 2 3 4 的高度值是1 // * 钢制托盘,必须是高度3 的 // */ // if (PalletType == 2) // {//刚托盘库位 // return 3; // } // else if (PalletType == 1) // {//塑料托盘库位 // if (layer == 1) // { // return 2; // } // else // { // return 1; // } // } // else // { // throw new Exception("无效的PalletType值:" + PalletType); // } // } // else // { // return Convert.ToInt32(move_ware_location_vs_container.DetectionHeight); // } //} /// /// 生成移库任务 /// /// /// /// /// /// /// /// /// /// //private static bool CreateMoveTask(MyDbContext mycontext, string needMoveWareLocationCode, // wms_task model, ware_location_vs_container lvc, int Priority // , ref List wcsTaskInputs, ref string errMsg, ref wms_task moveTask, ref wms_task move_out_Task) //{ // var preTitle = ",任务起点: " + model.FromLocationCode; // var wareTask = mycontext.wms_task.Where(x => (x.IsDeleted == null || x.IsDeleted == false) && (x.FromLocationCode == needMoveWareLocationCode || x.ToLocationCode == needMoveWareLocationCode)) // .Where(TaskHandler.CommonFilterExpressionForNoFinishAndNoCancel()) // .FirstOrDefault();//查询外侧箱子是否有出库任务 // if (wareTask != null) // { // errMsg = "外侧有任务,请优先执行外侧任务,外侧库位编号:" + lvc.WareLocationCode + preTitle; // return false; // } // #region 根据箱子类型查询可用库位 // bool isLane3 = false;//是否是第3巷道 // int PalletType = 0; // PalletType = MyExtendHelper.GetPalletType(mycontext, lvc.WareContainerCode, ref isLane3); // #endregion // int _DetectionHeight = 1; // #region 移库时优先移一四列,一四列无位置时移入二三列 // CriterionContainerOutput output = null; // if (isLane3) // {//3巷道 // //获取这个库位的ware_location_vs_container对象 // var move_ware_location_vs_container_list = mycontext.ware_location_vs_container.Where(x => x.WareLocationCode == needMoveWareLocationCode // && (x.IsDeleted == null || x.IsDeleted == false) // ).ToList(); // if (move_ware_location_vs_container_list == null || move_ware_location_vs_container_list.Count == 0) // { // errMsg = $"3巷道查找库位有0条 库位和托盘绑定关系,请联系管理员!" + preTitle; // return false; // } // if (move_ware_location_vs_container_list.Count > 1) // { // errMsg = $"3巷道查找库位有{move_ware_location_vs_container_list.Count}条 库位和托盘绑定关系,请联系管理员!" + preTitle; // return false; // } // var move_ware_location_vs_container = move_ware_location_vs_container_list.FirstOrDefault(); // _DetectionHeight = GetDetectionHeight(move_ware_location_vs_container, PalletType); // output = WMSRequestHelper.FindEmptyLocationForLane3(_DetectionHeight // , move_ware_location_vs_container.WareContainerCode, 1); // } // else // {//1巷道和2巷道 // _DetectionHeight = 1; // int lane = Convert.ToInt32(lvc.WareLocationCode.Substring(0, 1));//起点所属的巷道 // FindEmptyLocationHelper.FindEmptyLocatonListForLane12(true, false, mycontext, FormCC.WcsIp, lvc.WareContainerCode, ref PalletType, ref output, lane);//说明新建任务的时候,没有获取到目标库位,需要重新找 新库位 // //output = FindCriterionContainerOutput(lane, mycontext, criterionRetionOutputs1, needMoveWareLocationCode); // } // if (output == null) // { // /* // errMsg = "移库没有找到空库位移库" + preTitle; // return false; // //*/ // //如果移库实在没有找到库位,那么就直接创建出库任务得了 【Editby shaocx,2023-12-28】 // var TaskNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(); // var wcsTask_move_out = new WCSTaskInput(); // wcsTask_move_out.WmsTaskNo = TaskNo; // wcsTask_move_out.TaskName = SystemValue.YIKU_CK_NAME; // wcsTask_move_out.TaskType = 2;//出库任务 // wcsTask_move_out.Priority = Priority + 1; // wcsTask_move_out.Container = lvc.WareContainerCode; // wcsTask_move_out.High = _DetectionHeight; // wcsTask_move_out.PalletType = PalletType; // wcsTask_move_out.SourcePlace = lvc.WareLocationCode; // wcsTask_move_out.ToPlace = ""; // wcsTask_move_out.Creator = "cc"; // wcsTask_move_out.Timestamp = DateTime.UtcNow.ToString(); // wcsTaskInputs.Add(wcsTask_move_out); // move_out_Task = new wms_task // { // Id = Yitter.IdGenerator.YitIdHelper.NextId(), // OrderNo = "", // TaskNo = wcsTask_move_out.WmsTaskNo, // TaskName = wcsTask_move_out.TaskName, // TaskCategory = wcsTask_move_out.TaskType, // TaskDescribe = "无工单", // TaskPriority = wcsTask_move_out.Priority, // AreaType = (int)AreaTypeEnum.立体库, // //TaskState = 2, // TaskState = Convert.ToInt32(WareTaskStateEnum.执行中), // TaskType = (int)WareTaskTypeEnum.移库出库, // FromLocationCode = wcsTask_move_out.SourcePlace, // ToLocationCode = wcsTask_move_out.ToPlace, // ContainerCode = wcsTask_move_out.Container, // CreatedTime = DateTime.Now, // CreatedUserId = 142307070910551, // CreatedUserName = "cc", // State = 1, // IssueTime = DateTime.Now,//增加下发时间 【Editby shaocx,2023-03-03】 // IsDeleted = false, // DetectionHeight = _DetectionHeight // }; // } // else // {//找到了移库的目标库位 // var TaskNo = Yitter.IdGenerator.YitIdHelper.NextId().ToString(); // var wcsTask1 = new WCSTaskInput(); // wcsTask1.WmsTaskNo = TaskNo; // wcsTask1.TaskName = SystemValue.YIKUNAME; // wcsTask1.TaskType = 3; // wcsTask1.Priority = Priority + 1; // wcsTask1.Container = lvc.WareContainerCode; // wcsTask1.High = _DetectionHeight; // wcsTask1.PalletType = PalletType; // wcsTask1.SourcePlace = lvc.WareLocationCode; // wcsTask1.ToPlace = output.Code; // wcsTask1.Creator = "cc"; // wcsTask1.Timestamp = DateTime.UtcNow.ToString(); // wcsTaskInputs.Add(wcsTask1); // moveTask = new wms_task // { // Id = Yitter.IdGenerator.YitIdHelper.NextId(), // OrderNo = "", // TaskNo = wcsTask1.WmsTaskNo, // TaskName = wcsTask1.TaskName, // TaskCategory = wcsTask1.TaskType, // TaskDescribe = "无工单", // TaskPriority = wcsTask1.Priority, // AreaType = (int)AreaTypeEnum.立体库, // //TaskState = 2, // TaskState = Convert.ToInt32(WareTaskStateEnum.执行中), // //TaskType = 1, // TaskType = (int)WareTaskTypeEnum.出库, // FromLocationCode = wcsTask1.SourcePlace, // ToLocationCode = wcsTask1.ToPlace, // ContainerCode = wcsTask1.Container, // CreatedTime = DateTime.Now, // CreatedUserId = 142307070910551, // CreatedUserName = "cc", // State = 1, // IssueTime = DateTime.Now,//增加下发时间 【Editby shaocx,2023-03-03】 // IsDeleted = false, // DetectionHeight = _DetectionHeight // }; // #region 验证移库任务,不能再不同巷道中移库 【Editby shaocx,2022-12-28】 // var fromLane = wcsTask1.SourcePlace.Substring(0, 1); // var toLane = wcsTask1.ToPlace.Substring(0, 1); // if (fromLane != toLane) // { // errMsg = "将要生成的移库任务,起点巷道是" + fromLane + ",目标巷道是" + toLane + ",移库任务不能在不同巷道中移库,处理的任务号是:" + model.TaskNo + preTitle; // return false; // } // #endregion // } // #endregion // return true; //} #endregion /// /// 模拟下发 /// /// /// public static int Put(MyDbContext mycontext, string WcsIp, int Lane, wms_task singleTask, ref string errMsg) { try { if (singleTask == null) { errMsg = "当前未存在 入库任务"; return 1; } //获取移动单 var moveOrder = BaseInfoHelper.GetOrderMovement(mycontext, singleTask, ref errMsg); var moveOrderDetails = BaseInfoHelper.GetMoveOrderDetails(mycontext, singleTask, moveOrder, ref errMsg); //目标库区 //var toArea = BaseInfoHelper.GetArea(mycontext, singleTask.ToAreaCode, "目标库区", ref errMsg); //目标库位校验 var toPlace = BaseInfoHelper.GetPlace(mycontext, singleTask.ToPlaceCode, "目标库位", ref errMsg); //if (toArea.AreaCode != toPlace.AreaCode) //{ // errMsg = $"目标库位{toPlace.PlaceCode}所属库区{toPlace.AreaCode}与目标库区{toArea.AreaCode}不匹配"; // return 1; //} if (toPlace.PlaceStatus != (int)PlaceStatusEnum.正常) { errMsg = $"任务下发,目标库位{singleTask.ToPlaceCode}库位属性不是{PlaceStatusEnum.正常.ToString()}"; return 1; } //源库位校验 var sourcePlace = BaseInfoHelper.GetPlace(mycontext, singleTask.SourcePlaceCode, "源库位", ref errMsg); if (sourcePlace.PlaceStatus != (int)PlaceStatusEnum.正常) { errMsg = $"任务下发,源库位{singleTask.SourcePlaceCode}库位属性不是{PlaceStatusEnum.正常.ToString()}"; return 1; } #region 锁定起始、目标库位 //锁定起始、目标库位 sourcePlace.PlaceStatus = (int)PlaceStatusEnum.锁定; sourcePlace.UpdateTime = DateTime.Now; sourcePlace.UpdateUserId = 0; sourcePlace.UpdateUserName = FormCC.WcsSysUserName; toPlace.PlaceStatus = (int)PlaceStatusEnum.锁定; toPlace.UpdateTime = DateTime.Now; toPlace.UpdateUserId = 0; toPlace.UpdateUserName = FormCC.WcsSysUserName; #endregion #region 移动单状态变更处理中 if(moveOrder.OrderStatus == (int)OrderStatusEnum.新建) { moveOrder.OrderStatus = (int)OrderStatusEnum.处理中; moveOrder.OrderStatusName = OrderStatusEnum.处理中.ToString(); } foreach (var item in moveOrderDetails) { if (item.OrderStatus == (int)OrderStatusEnum.新建) { item.OrderStatus = (int)OrderStatusEnum.处理中; item.OrderStatusName = OrderStatusEnum.处理中.ToString(); item.UpdateTime = DateTime.Now; item.UpdateUserId = 0; item.UpdateUserName = FormCC.WcsSysUserName; } } #endregion //更新调度任务状态 singleTask.TaskStatus = (int)TaskStatusEnum.已下发;//更新任务状态为 已下发 singleTask.IssueTime = DateTime.Now;//增加下发时间 singleTask.UpdateTime = DateTime.Now; singleTask.TaskMsg = "下发成功"; mycontext.SaveChanges(); return 3; } catch (Exception ex) { SystemWarningMsg._lbl_Alert_OutPlanTaskHandler = "错误信息:" + ex; return 2; } } /// /// 批量下发WCS任务 /// /// /// /// public static bool CreateBatchTask(List taskOutputs, string WcsIp, ref string errMsg) { errMsg = ""; //将任务下发给WCS var json = JsonConvert.SerializeObject(taskOutputs); if (FormCC.IsSimulationPLC) {//如果是模拟 //记录日志 Log4NetHelper.WriteInfoLog(LogType.OutPlanTask, "批量下发WCS任务[成功][注意:这是模拟测试!!!!],taskOutputs:" + json); return true; } //var utl = string.Format(WcsIp + @"CreateBatchTask"); //var result = HttpHelper.Post(utl, json); var utl = string.Format(@"CreateBatchTask"); var result = new HTTPService(WcsIp).postContentForString(utl, json, ""); if (result == null) { //记录日志 Log4NetHelper.WriteInfoLog(LogType.OutPlanTask, "批量下发WCS任务[失败],taskOutputs:" + json); SystemWarningMsg._lbl_Alert_OutPlanTaskHandler = "批量下发WCS任务失败,WCS返回NULL,托盘号:" + taskOutputs[0].Container + ",起点:" + taskOutputs[0].SourcePlace + ",目标点:" + taskOutputs[0].ToPlace; errMsg = "WCS返回结果NULL"; return false; } var data = JsonConvert.DeserializeObject(result); if (data == null || !data.Success) { //记录日志 Log4NetHelper.WriteInfoLog(LogType.OutPlanTask, "批量下发WCS任务[失败],taskOutputs:" + json); SystemWarningMsg._lbl_Alert_OutPlanTaskHandler = "批量下发WCS任务失败,WCS返回失败,托盘号:" + taskOutputs[0].Container + ",起点:" + taskOutputs[0].SourcePlace + ",目标点:" + taskOutputs[0].ToPlace + ",WCS结果:" + (string.IsNullOrEmpty(data.Message) ? "" : data.Message); errMsg = "WCS返回失败,返回消息:" + data.Message; return false; } //记录日志 Log4NetHelper.WriteInfoLog(LogType.OutPlanTask, "批量下发WCS任务[成功],taskOutputs:" + json); return true; } } }