杨前锦
2025-06-13 b7308bba3d7ffad271ce7fc7a93c8c45d76be87d
优化印尼佳通-硫化胚胎出入库逻辑策略优化
12个文件已修改
1037 ■■■■■ 已修改文件
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/Program.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/api/ApiHelper.cs 249 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/api/MoboxController.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/core/Monitor.cs 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/core/WCSCore.cs 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/models/LjLotOnhand.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/models/SideLocConfig.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/wms/LocationHelper.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/wms/WMSHelper.cs 124 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/api/ApiHelper.cs 123 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/api/WmsController.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs 345 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/Program.cs
@@ -81,8 +81,10 @@
                List<Task> tasks = new List<Task>();
                // 添加任务推送线程
                tasks.Add(GetTask(WCSCore.Dispatch));
                // 监听MES任务,下发任务
                tasks.Add(GetTask(Monitor.MonitorMesTask));
                // 监听成型机叫料任务
                tasks.Add(GetTask(Monitor.MonitorCXJCallMaterialMesTask));
                // 监听钢包满料下线任务
                tasks.Add(GetTask(Monitor.MonitorGBOffLineMesTask));
                // 监听斜裁出库任务表
                tasks.Add(GetTask(Monitor.MonitorXcOutTask));
                // 自动补充空工装任务
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/api/ApiHelper.cs
@@ -228,6 +228,10 @@
        public static ResponseResult offLineProcess(OffLineRequest model) {
            ResponseResult responseResult = new ResponseResult();
            var areaCodes = Settings.areaPropertyList.Select(a => a.areaCode).ToList();
            var isExistCntr = LocationHelper.checkAreaExistCntr(areaCodes,model.cntrNo);
            if (!isExistCntr)
            {
            // 查询起点货位是否存在已存在任务,防止任务重复发起
            var existWmsTask = WMSHelper.GetWmsTaskByStart(model.loc);
            if (existWmsTask == null)
@@ -265,6 +269,12 @@
            {
                WMSHelper.addAlarmRecord("流程异常", "低", $"下线货位:{model.loc}已有任务,请勿重复下发任务");
                throw new BusinessException($"下线货位:{model.loc}已有任务,请勿重复下发任务");
                }
            }
            else
            {
                WMSHelper.addAlarmRecord("流程异常", "高", $"工装:{model.cntrNo}已入库,请勿重复入库");
                throw new BusinessException($"工装:{model.cntrNo}已入库,请勿重复入库");
            }
            return responseResult;
        }
@@ -369,8 +379,8 @@
                        }
                        else
                        {
                            WMSHelper.addAlarmRecord("流程异常", "中", $"空工装出库站台:{logicConfig.S_LKKTJBLOC},没有空工装");
                            photoStatus = false;
                            kgzCntrCode = "虚拟容器";
                            WMSHelper.addAlarmRecord("流程异常", "低", $"空工装出库站台:{logicConfig.S_LKKTJBLOC},没有空工装");
                        }
                    }
@@ -917,7 +927,6 @@
                                // 更新出库任务中间表状态
                                WMSHelper.updateLotOutTask(cst.S_CNTR_CODE, "2");
                            }
                        }
                    }
                }
@@ -941,15 +950,15 @@
                if (mst != null && mst.N_B_STATE < 2) {
                    int emptyFlag = 0;  // 容器空满标识
                    Container cntr = ContainerHelper.GetCntr(cst.S_CNTR_CODE);
                    if (cntr != null && cntr.N_DETAIL_COUNT > 0) {
                    var cntrItemRels = ContainerHelper.GetCntrItemRel(cst.S_CNTR_CODE);
                    if (cntrItemRels.Count > 0) {
                        emptyFlag = 1;
                    }
                    // 1:堆垛机放货异常申请新终点
                    if (model.applyType == 1) {
                        // 报警:流程异常
                        WMSHelper.addAlarmRecord("流程异常", "低", $"堆垛机放货异常,异常货位:{cst.S_END_LOC}");
                        WMSHelper.addAlarmRecord("流程异常", "中", $"堆垛机放货异常,任务号:{cst.S_CODE},异常货位:{cst.S_END_LOC}");
                        // 1.将异常货位上锁,并报警
                        LocationHelper.LockLoc(cst.S_END_LOC, 3);
@@ -962,24 +971,6 @@
                        LocationHelper.LockLoc(endLoc.S_CODE, 1);
                        applyDest.destLoc = endLoc.S_CODE;
                    }
                    else if (model.applyType == 2)
                    {
                        if (cst.S_END_LOC == "虚拟库位")
                        {
                            var transfeRelevance = WMSHelper.GetTransfeRelevance(model.loc);  // 接驳位关联属性
                            if (transfeRelevance != null)
                            {
                                // 1.查询新的入库终点
                                Location endLoc = WMSHelper.getInStockEndLoc(transfeRelevance.S_RELE_AREA, emptyFlag);
                                cst.S_END_LOC = endLoc.S_CODE;
                                WCSHelper.UpdateEndLoc(cst);
                                LocationHelper.LockLoc(endLoc.S_CODE, 1);
                                applyDest.destLoc = endLoc.S_CODE;
                            }
                        }
                    }
                }
            }
            result.data = applyDest;
@@ -1066,7 +1057,10 @@
            {
                if (mst.S_TYPE == "余料/空工装入库")
                {
                    var mesTask = WMSHelper.GetLjMesTaskById(int.Parse(mst.S_OP_DEF_CODE));
                    var bo = int.TryParse(mst.S_OP_DEF_CODE, out int mesId);
                    if (bo)
                    {
                        var mesTask = WMSHelper.GetLjMesTaskById(mesId);
                    if (mesTask.QTY != 0)
                    {
                        var awaitTask = WMSHelper.GetAwaitWmsTaskByMaterialCode(mesTask.MATERIAL_CODE);
@@ -1078,6 +1072,7 @@
                            agvEndLoc = LocationHelper.GetLoc(awaitTask.S_END_LOC);
                            wmsEndLoc = agvEndLoc;
                            mst.S_TYPE = "叫料出库任务";
                            }
                        }
                    }
                }
@@ -1199,7 +1194,7 @@
                            }
                            else
                            {
                                WMSHelper.addAlarmRecord("流程异常", "高", $"AGV申请终点失败,未查询到立库接驳位");
                                WMSHelper.addAlarmRecord("流程异常", "高", $"AGV申请终点失败,立库:{wmsEndLoc.S_AREA_CODE}未配置立库接驳位");
                                return null;
                            }
                        }
@@ -1342,45 +1337,27 @@
        /// 成新机叫料
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="endLocCode"></param>
        /// <param name="jtNo"></param>
        /// <param name="mesTaskId"></param>
        public static void callMaterial(string materialCode, string endLocCode, int mesTaskId)
        public static void callMaterial(string materialCode, string jtNo, int mesTaskId)
        {
            var oldWmsTask = WMSHelper.GetWmsTaskByEnd(endLocCode);
            if (oldWmsTask == null) {
                string cntrCode = "";
                Location endLoc = LocationHelper.GetLoc(endLocCode);
            var mesTask = WMSHelper.GetLjMesTaskById(mesTaskId);
            if (mesTask != null)
            {
                Location endLoc = WMSHelper.getCallMaterialLocCode(jtNo);
                if (endLoc != null)
                {
                    Location middleLoc = null;
                    Location startLoc = WMSHelper.getOutStockStartLoc(null, materialCode);
                    if (startLoc == null)
                    {
                        var mesTask = WMSHelper.GetLjMesTaskById(mesTaskId);
                        if (mesTask != null)
                        {
                            mesTask.RECEIVE_MSG = "没有库存";
                            WMSHelper.updateLjMesTask(mesTask);
                        }
                        WMSHelper.addAlarmRecord("流程异常", "高", $"叫料失败,物料:{materialCode}没有库存");
                        return;
                    }
                    else
                    if (startLoc != null)
                    {
                        var locCntrRels = LocationHelper.GetLocCntr(startLoc.S_CODE);
                        if (locCntrRels.Count > 0)
                        {
                            cntrCode = locCntrRels[0].S_CNTR_CODE;
                        }
                        else
                        {
                            WMSHelper.addAlarmRecord("流程异常", "高", $"查询物料异常,货位:{startLoc.S_CODE}缺少容器信息");
                            return;
                        }
                    }
                    middleLoc = WMSHelper.GetTransfeRelevanceLoc(startLoc.S_AREA_CODE, 1 , 2);
                    if (middleLoc != null)
                    {
                        // 1.创建成新机叫料作业
@@ -1405,7 +1382,7 @@
                                S_OP_CODE = wmsTask.S_CODE,
                                S_CODE = WCSHelper.GenerateTaskNo(),
                                S_CNTR_CODE = wmsTask.S_CNTR_CODE,
                                S_TYPE = wmsTask.S_TYPE + "-WCS",
                                        S_TYPE = wmsTask.S_TYPE,
                                S_START_LOC = startLoc.S_CODE,
                                S_START_AREA = startLoc.S_AREA_CODE,
                                S_END_LOC = middleLoc.S_CODE,
@@ -1444,16 +1421,28 @@
                                N_B_STATE = -1
                            };
                            WCSHelper.CreateTask(twoWcsTask);
                            WMSHelper.readLjMesCallItemTask(wmsTask.S_CODE, mesTaskId);
                        }
                    }
                    else 
                    {
                        WMSHelper.addAlarmRecord("流程异常", "高", $"库区{startLoc.S_AREA_CODE}未查询到可用的接驳位");
                                WMSHelper.addAlarmRecord("流程异常", "高", $"成型机叫料失败,库区{startLoc.S_AREA_CODE}未查询到可用的接驳位");
                            }
                        }
                        else
                        {
                            WMSHelper.addAlarmRecord("流程异常", "高", $"成型机叫料失败,开始货位:{startLoc.S_CODE}异常,缺少容器信息");
                        }
                    }
                    else
                    {
                        mesTask.AWAIT_MSG = "库存不足";
                        WMSHelper.updateLjMesTask(mesTask);
                        WMSHelper.addAlarmRecord("流程异常", "高", $"成型机叫料失败,物料:{materialCode}库存不足");
                    }
                }
            }
        }
        
        /// <summary>
@@ -1465,14 +1454,142 @@
        /// <param name="materialCode"></param>
        /// <param name="endLocCode"></param>
        /// <param name="mesTaskId"></param>
        public static void callMaterialHDK(string materialCode, string endLocCode, int mesTaskId)
        public static void callMaterialXC(string materialCode, string endLocCode, int mesTaskId)
        {
            // 1.查询环带库物料库存
            DateTime inStockTimeXc = DateTime.MinValue;
            List<CntrItemRel> cntrItemRelsXc = new List<CntrItemRel>();
            if (cntrItemRelsXc.Count > 0)
            {
                inStockTimeXc = cntrItemRelsXc[0].T_INBOUND_TIME;
            }
            // 2.查询中转库库存,根据入库时间 进行先入先出
            // 2.查询中转库库存
            DateTime inStockTime = DateTime.MinValue;
            var cntrItemRels = WMSHelper.getZZKInventoryInfo(materialCode);
            if (cntrItemRels.Count > 0)
            {
                inStockTime = cntrItemRels[0].T_INBOUND_TIME;
            }
            // 3.将MES任务写入环带库任务中间表
            WMSHelper.addLjXcTask(mesTaskId);
            // 3.根据先进先出计算出库的物料是环带库 还是中转库
            var mesTask = WMSHelper.GetLjMesTaskById(mesTaskId);
            if (inStockTime >= inStockTimeXc)
            {
                //斜裁物料出库
                if (cntrItemRelsXc.Count > 0)
                {
                    // 4.将MES任务写入环带库任务中间表
                    WMSHelper.addLjXcTask(mesTask);
                }
            }
            else
            {
                //中转库物料出库
                if (cntrItemRels.Count > 0)
                {
                    var cntrItemRel = cntrItemRels[0];
                    var locCntrRel = LocationHelper.GetLocCntrByCntr(cntrItemRel.S_CNTR_CODE);
                    if (locCntrRel != null)
                    {
                      var endLoc = LocationHelper.GetLoc(locCntrRel.S_LOC_CODE);
                        if (endLoc != null)
                        {
                            Location middleLoc = null;
                            Location startLoc = WMSHelper.getOutStockStartLoc(null, materialCode);
                            if (startLoc != null)
                            {
                                var locCntrRels = LocationHelper.GetLocCntr(startLoc.S_CODE);
                                if (locCntrRels.Count > 0)
                                {
                                    var cntrCode = cntrItemRel.S_CNTR_CODE;
                                    middleLoc = WMSHelper.GetTransfeRelevanceLoc(startLoc.S_AREA_CODE, 1, 2);
                                    if (middleLoc != null)
                                    {
                                        // 1.创建成新机叫料作业
                                        var wmsTask = new WMSTask()
                                        {
                                            S_CNTR_CODE = cntrCode,
                                            S_CODE = WMSHelper.GenerateTaskNo(),
                                            S_START_LOC = startLoc.S_CODE,
                                            S_START_AREA = startLoc.S_AREA_CODE,
                                            S_END_LOC = endLoc.S_CODE,
                                            S_END_AREA = endLoc.S_AREA_CODE,
                                            S_TYPE = "叫料出库任务",
                                            S_OP_DEF_CODE = mesTaskId.ToString(),
                                            S_OP_DEF_NAME = "成型机叫料出库任务",
                                            T_START_TIME = DateTime.Now,
                                        };
                                        if (WMSHelper.CreateWmsTask(wmsTask))
                                        {
                                            WCSTask wcsTask = new WCSTask()
                                            {
                                                S_OP_NAME = wmsTask.S_OP_DEF_NAME,
                                                S_OP_CODE = wmsTask.S_CODE,
                                                S_CODE = WCSHelper.GenerateTaskNo(),
                                                S_CNTR_CODE = wmsTask.S_CNTR_CODE,
                                                S_TYPE = wmsTask.S_TYPE,
                                                S_START_LOC = startLoc.S_CODE,
                                                S_START_AREA = startLoc.S_AREA_CODE,
                                                S_END_LOC = middleLoc.S_CODE,
                                                S_END_AREA = middleLoc.S_AREA_CODE,
                                                S_SCHEDULE_TYPE = "WCS",
                                                N_PRIORITY = 10,
                                                T_START_TIME = DateTime.Now,
                                            };
                                            if (WCSHelper.CreateTask(wcsTask))
                                            {
                                                // 起点、终点加锁
                                                LocationHelper.LockLoc(wcsTask.S_START_LOC, 2);
                                                LocationHelper.LockLoc(wcsTask.S_END_LOC, 1);
                                                // 更新作业任务状态
                                                wmsTask.N_B_STATE = 1;
                                                WMSHelper.UpdateTaskState(wmsTask);
                                            }
                                            // 预创建二段任务
                                            WCSTask twoWcsTask = new WCSTask()
                                            {
                                                S_OP_NAME = wmsTask.S_OP_DEF_NAME,
                                                S_OP_CODE = wmsTask.S_CODE,
                                                S_CODE = WCSHelper.GenerateTaskNo(),
                                                S_CNTR_CODE = wmsTask.S_CNTR_CODE,
                                                S_TYPE = wmsTask.S_TYPE,
                                                S_START_LOC = middleLoc.S_CODE,
                                                S_START_AREA = middleLoc.S_AREA_CODE,
                                                S_END_LOC = endLoc.S_CODE,
                                                S_END_AREA = endLoc.S_AREA_CODE,
                                                S_SCHEDULE_TYPE = "AGV",
                                                N_PRIORITY = 10,
                                                T_START_TIME = DateTime.Now,
                                                N_B_STATE = -1
                                            };
                                            WCSHelper.CreateTask(twoWcsTask);
                                            WMSHelper.readLjMesCallItemTask(wmsTask.S_CODE, mesTaskId);
                                        }
                                    }
                                    else
                                    {
                                        WMSHelper.addAlarmRecord("流程异常", "高", $"成型机叫料失败,库区{startLoc.S_AREA_CODE}未查询到可用的接驳位");
                                    }
                                }
                                else
                                {
                                    WMSHelper.addAlarmRecord("流程异常", "高", $"成型机叫料失败,开始货位:{startLoc.S_CODE}异常,缺少容器信息");
                                }
                            }
                            else
                            {
                                mesTask.AWAIT_MSG = "库存不足";
                                WMSHelper.updateLjMesTask(mesTask);
                                WMSHelper.addAlarmRecord("流程异常", "高", $"成型机叫料失败,物料:{materialCode}库存不足");
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
@@ -1483,12 +1600,12 @@
        /// 3.创建余料回库作业,创建agv搬运任务,虚拟终点
        /// </summary>
        /// <param name="locCode">成型机叫料终点</param>
        public static void returnMaterialOrEmptyTray(string locCode)
        /// <param name="jtNo">成型机叫料终点</param>
        public static void returnMaterialOrEmptyTray(string locCode ,string jtNo)
        {
            if (locCode != null)
            {
                // 2.查询mes任务中间表
                var mesTask = WMSHelper.getLjMesTaskByLoc(locCode);
                var mesTask = WMSHelper.getLjMesTaskByJtNo(jtNo);
                if (mesTask != null)
                {
                    createReturnTask(locCode, mesTask);
@@ -1665,9 +1782,10 @@
                    }
                }
                if (cst.S_TYPE == "叫料出库任务")
                var bo = int.TryParse(mst.S_OP_DEF_CODE, out int mesId);
                if (bo)
                {
                    var mesTask = WMSHelper.GetLjMesTaskByAgvorderId(mst.S_CODE);
                    var mesTask = WMSHelper.GetLjMesTaskById(mesId);
                    callMaterial( mesTask.MATERIAL_CODE, mesTask.POSITION_ID, mesTask.ID);
                }
            }
@@ -2019,7 +2137,8 @@
        //----------------------------------------------------------------------------------------------------------------------------
        public class LocModel
        {
            public string locCode { get; set; }
            public string locCode { get; set; }  // 返料货位编号
            public string jtNo { get; set; } // 机台号
        }
        public class ApplyDest {
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/api/MoboxController.cs
@@ -70,7 +70,7 @@
        {
            LogHelper.Info("余料/空工装返回-returnMaterialAndPallet 入参:" + JsonConvert.SerializeObject(model), "Mobox");
            ResponseResult responseResult = new ResponseResult();
            ApiHelper.returnMaterialOrEmptyTray(model.locCode);
            ApiHelper.returnMaterialOrEmptyTray(model.locCode ,model.jtNo);
            LogHelper.Info("余料/空工装返回-returnMaterialAndPallet 出参:" + JsonConvert.SerializeObject(responseResult), "Mobox");
            return responseResult;
        }
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/core/Monitor.cs
@@ -25,32 +25,43 @@
    {
       
        /// <summary>
        /// 监听MES任务中间表
        /// 1.钢包满料下线
        /// 2.成型机叫料
        /// 监听钢包满料下线MES任务
        /// </summary>
        public static void MonitorMesTask() {
            LogHelper.Info("监听MES任务中间表", "WMS");
            var mesTaskList = WMSHelper.GetLjMesTaskList("PENDING");
            foreach (var mesTask in mesTaskList)
        public static void MonitorGBOffLineMesTask()
            {
                // 1.钢包满料下线
                List<string> lineLoclist = new List<string>() { };
                lineLoclist.Add("GBJTW-01");
                lineLoclist.Add("GBJTW-02");
                if (mesTask.MSG_TYPE == "1" && mesTask.PALLET_TYPE == "7" && lineLoclist.Contains(mesTask.PALLET_ID))
            var mesTaskList = WMSHelper.GetLjMesTaskList("PENDING");
            if (mesTaskList.Count > 0)
            {
                mesTaskList = mesTaskList.Where(a => a.MSG_TYPE == "1" && a.PALLET_TYPE == "7").ToList();
                if (mesTaskList.Count > 0)
                {
                    foreach (var mesTask in mesTaskList)
                {
                    LogHelper.Info("MES钢包满料下线任务", "WMS");
                    OffLineRequest request = new OffLineRequest(){ loc = mesTask.POSITION_ID, cntrNo = mesTask.PALLET_ID};
                    ApiHelper.offLineProcess(request);
                }
                }
            }
        }
                // 2.成新机叫料
                if (mesTask.MSG_TYPE == "0") {
                    var lineSideLoc = WMSHelper.GetLineSideLoc(mesTask.POSITION_ID);
        /// <summary>
        /// 监听成型机叫料MES任务
        /// </summary>
        public static void MonitorCXJCallMaterialMesTask()
        {
            var mesTaskList = WMSHelper.GetLjMesTaskList("PENDING");
            if (mesTaskList.Count > 0)
            {
                mesTaskList = mesTaskList.Where(a => a.MSG_TYPE == "0").ToList();
                if (mesTaskList.Count > 0)
                {
                    foreach (var mesTask in mesTaskList)
                    {
                        var lineSideLoc = WMSHelper.GetLineSideLoc(mesTask.EQP);
                    if (lineSideLoc != null ) 
                    {
                        LogHelper.Info("MES成新机叫料任务", "WMS");
                            LogHelper.Info($"成型机叫料任务,MES任务ID:{mesTask.ID}", "WMS");
                        // 2.1成新机叫料(斜裁)
                        if (mesTask.PALLET_TYPE == "5" || mesTask.PALLET_TYPE == "6")
@@ -58,7 +69,7 @@
                            var xcTask = WMSHelper.GetLjXcTaskById(mesTask.ID);
                            if (xcTask == null)
                            {
                                ApiHelper.callMaterialHDK(mesTask.MATERIAL_CODE, mesTask.POSITION_ID, mesTask.ID);
                                    ApiHelper.callMaterialXC(mesTask.MATERIAL_CODE, mesTask.POSITION_ID, mesTask.ID);
                            }
                            else
                            {
@@ -71,7 +82,8 @@
                        else
                        {
                            // 2.2 成新机叫料
                            ApiHelper.callMaterial(mesTask.MATERIAL_CODE, mesTask.POSITION_ID, mesTask.ID);
                                ApiHelper.callMaterial(mesTask.MATERIAL_CODE, mesTask.EQP, mesTask.ID);
                            }
                        }
                    }
                }
@@ -91,12 +103,15 @@
                if (mesTask != null && mesTask.RETURN_CODE == "2")
                {
                    Location startLoc = LocationHelper.GetLoc(outTask.POSITION_ID);
                    Location endLoc = LocationHelper.GetLoc(mesTask.POSITION_ID);
                    if (startLoc == null)
                    {
                        WMSHelper.addAlarmRecord("流程异常", "高", $"成型机叫料出库(斜裁),起点:{outTask.POSITION_ID}在WMS系统中不存在");
                    }
                    Location endLoc = WMSHelper.getCallMaterialLocCode(mesTask.EQP);
                    if (endLoc != null)
                    {
                    var wmsTask = WMSHelper.GetWmsTaskByCntr(outTask.PALLET_ID);
                    if (wmsTask == null)
                    {
                        if (startLoc.N_LOCK_STATE == 0 && endLoc.N_LOCK_STATE == 0)
                        {
                            // 1.创建斜裁-成新机叫料作业
                            wmsTask = new WMSTask()
@@ -141,39 +156,6 @@
                                    WMSHelper.UpdateTaskState(wmsTask);
                                }
                            }
                        }
                        else
                        {
                            LogHelper.Info($"XC出库任务ID:{mesTask.ID},无法生成叫料任务,起点或终点上锁", "斜裁");
                        }
                    }
                    else
                    {
                        WCSTask wcsTask = new WCSTask()
                        {
                            S_OP_NAME = wmsTask.S_OP_DEF_NAME,
                            S_OP_CODE = wmsTask.S_CODE,
                            S_CODE = WCSHelper.GenerateTaskNo(),
                            S_CNTR_CODE = wmsTask.S_CNTR_CODE,
                            S_TYPE = wmsTask.S_TYPE,
                            S_START_LOC = startLoc.S_CODE,
                            S_START_AREA = startLoc.S_AREA_CODE,
                            S_END_LOC = endLoc.S_CODE,
                            S_END_AREA = endLoc.S_AREA_CODE,
                            S_SCHEDULE_TYPE = "AGV",
                            N_PRIORITY = 10,
                            T_START_TIME = DateTime.Now,
                        };
                        if (WCSHelper.CreateTask(wcsTask))
                        {
                            // 起点、终点加锁
                            LocationHelper.LockLoc(wcsTask.S_START_LOC, 2);
                            LocationHelper.LockLoc(wcsTask.S_END_LOC, 1);
                            // 更新作业任务状态
                            wmsTask.N_B_STATE = 1;
                            WMSHelper.UpdateTaskState(wmsTask);
                        }
                    }
                }
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/core/WCSCore.cs
@@ -90,9 +90,9 @@
                                WMSHelper.addRfidAnomalyRecord(cst.S_CNTR_CODE, 2, cst.S_START_LOC, null);
                                // 查询扫描的RFID
                                // 发送 00 04 71 02到扫码器 ,接受返回数据并解析
                                byte[] bytes = new byte[] { 00, 04, 71, 02 };
                                /*    byte[] bytes = new byte[] { 00, 04, 71, 02 };
                                var plc = Settings.carDeviceInfos.Where(a => a.deviceNo == model.ForkliftNo && a.enable == 1).FirstOrDefault();
                                TcpServer.TcpServerSend(plc.address, bytes);
                                    TcpServer.TcpServerSend(plc.address, bytes);*/
                            }
                            else if (model.State == 1002)
                            {
@@ -136,39 +136,9 @@
                            // AGV任务完成
                            if (model.State == 2)
                            {
                                // 检测物料是否合格,如不合格,
                                // 判断物料是否是环带库物料,是则回环带库,并让环带下发新的物料
                                // 非环带库物料,则退出立库,同时下发新的物料出库任务
                                if (cst.S_TYPE.Contains("叫料出库任务"))
                                {
                                    var cntrItemRels = ContainerHelper.GetCntrItemRel(cst.S_CNTR_CODE);
                                    if (cntrItemRels != null && cntrItemRels.Count > 0)
                                    {
                                        if (cntrItemRels[0].S_ITEM_STATE == "2")
                                        {
                                            // 不合格品回库
                                            ApiHelper.rejectReturnStock(mst, cst);
                                        }
                                    }
                                }
                                // 检测是否是读码位,非读码位,可以激活预创建任务
                                var transfe = WMSHelper.GetTransfeRelevance(cst.S_END_LOC);  // 接驳位属性
                                if (transfe != null && transfe.N_READ_LOC == 1)
                                {
                                // 激活预创建任务
                                // 场景:1.读码位激活预创建任务 2.空工装出库激活满料下线任务(非直连)
                                    WCSHelper.ActivatePreCreateTask(mst.S_CODE);
                                }
                                else if ( transfe.N_READ_LOC == 0)
                                {
                                    if (cst.S_TYPE.Contains("【异常】"))
                                    {
                                        WCSHelper.ActivatePreCreateTask(mst.S_CODE,1);
                                    }
                                    else
                                    {
                                        WCSHelper.ActivatePreCreateTask(mst.S_CODE);
                                    }
                                }
                                // 查询是否有未完成的任务
                                if (WMSHelper.isFinishTask(mst.S_CODE))
@@ -180,10 +150,36 @@
                                    // 更新任务中间表状态
                                    WMSHelper.updateMesTaskStatus(mst.S_CODE, "3");
                                }
                                // 检测物料是否合格,如不合格,
                                // 判断物料是否是环带库物料,是则回环带库,并让环带下发新的物料
                                // 非环带库物料,则退出立库,同时下发新的物料出库任务
                                if (cst.S_TYPE.Contains("叫料出库任务"))
                                {
                                    var bo = int.TryParse(mst.S_OP_DEF_CODE, out int mesId);
                                    if (bo)
                                    {
                                        var mesTask = WMSHelper.GetLjMesTaskById(mesId);
                                        var cntrItemRels = ContainerHelper.GetCntrItemRel(cst.S_CNTR_CODE);
                                        if (cntrItemRels != null && cntrItemRels.Count > 0)
                                        {
                                            if (cntrItemRels[0].S_ITEM_STATE == "2")
                                            {
                                                mesTask.AWAIT_MSG = "物料检验状态为不合格,重新叫料中";
                                                WMSHelper.updateLjMesTask(mesTask);
                                                // 不合格品回库
                                                ApiHelper.rejectReturnStock(mst, cst);
                                            }
                                            else
                                            {
                                    // 如果作业名称为成型机叫料出库任务,则触发余料/空托搬运任务
                                    string locCode = WMSHelper.getReturnMaterialLocCode(mst.S_END_LOC);
                                    ApiHelper.returnMaterialOrEmptyTray(locCode);
                                                var sideLocConfig = WMSHelper.getReturnMaterialLocCode(mst.S_END_LOC);
                                                ApiHelper.returnMaterialOrEmptyTray(sideLocConfig.S_RETURN_LOC_CODE, sideLocConfig.EQP);
                                            }
                                        }
                                    }
                                }   
                            }
                        }
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/models/LjLotOnhand.cs
@@ -24,5 +24,6 @@
        public float QTY { get; set; } //数量
        public DateTime IN_DATE { get; set; } //入库时间
        public DateTime CREATION_DATE { get; set; } //创建日期
        public string WAREHOUSE_TYPE { get; set; } //区分不同厂家(1/思尔特,2/杭叉)
    }
}
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/models/SideLocConfig.cs
@@ -14,6 +14,7 @@
    [SugarTable("TN_Side_Loc_Config")]
    internal class SideLocConfig : BaseModel
    {
        public string EQP { get; set; } // 机台号
        public string S_LOC_CODE { get; set; }  // 线边叫料货位
        public string S_RETURN_LOC_CODE { get; set; } // 对应返料货位
    }
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/wms/LocationHelper.cs
@@ -112,6 +112,19 @@
            return db.Queryable<Location>().Where(a => a.S_AREA_CODE.Trim() == areaCode && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
        }
        internal static bool checkAreaExistCntr(List<string> areaCodes ,string cntrCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<Location>()
                    .LeftJoin<LocCntrRel>((a,b) => a.S_CODE == b.S_LOC_CODE)
                    .Where((a, b) => areaCodes.Contains(a.S_AREA_CODE.Trim())
                                && a.N_CURRENT_NUM == 0
                                && a.N_LOCK_STATE == 0
                                && a.C_ENABLE == "Y"
                                && b.S_CNTR_CODE == cntrCode
                                ).Count() > 0;
        }
        /// <summary>
        ///获取所有货位扩展信息 
        /// </summary>
@@ -150,8 +163,16 @@
                });
            }
            return result;
        }
        internal static LocCntrRel GetLocCntrByCntr(string cntrCode)
        {
            var result = new List<LocCntrRel>();
            //1.0 查货位容器表
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<LocCntrRel>().Where(a => a.S_CNTR_CODE.Trim() == cntrCode).OrderBy(a => a.T_CREATE).First();
        }
        internal static List<LocCntrRel> GetLocCntrRel(string loc) {
            //1.0 查货位容器表
            var db = new SqlHelper<object>().GetInstance();
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/wms/WMSHelper.cs
@@ -165,18 +165,39 @@
        }
        /// <summary>
        ///
        /// 查询成型机返料货位
        /// </summary>
        /// <param name="locCode"></param>
        /// <returns></returns>
        public static string getReturnMaterialLocCode(string locCode)
        public static SideLocConfig getReturnMaterialLocCode(string locCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            var returnMaterialLoc = db.Queryable<SideLocConfig>().Where(a => a.S_LOC_CODE.Trim() == locCode).First();
            if (returnMaterialLoc != null) {
                return returnMaterialLoc.S_RETURN_LOC_CODE;
            return db.Queryable<SideLocConfig>().Where(a => a.S_LOC_CODE.Trim() == locCode).First();
            }
            return null;
        /// <summary>
        /// 查询成型机叫料位
        /// </summary>
        /// <param name="jtNo"></param>
        /// <returns></returns>
        public static Location getCallMaterialLocCode(string jtNo)
        {
            var db = new SqlHelper<object>().GetInstance();
            Location loc = null;
            var returnMaterialLocs = db.Queryable<SideLocConfig>().Where(a => a.EQP.Trim() == jtNo).ToList();
            if (returnMaterialLocs.Count > 0)
            {
                foreach (var item in returnMaterialLocs)
                {
                    loc = LocationHelper.GetLoc(item.S_LOC_CODE);
                    if (loc.N_CURRENT_NUM == 0 && loc.N_LOCK_STATE == 0)
                    {
                        break;
                    }
                }
            }
            return loc;
        }
        // --------------------------------------------------------福建佳通-----------------------------------------
@@ -239,6 +260,34 @@
                .OrderBy(a => a.S_PRI)
                .First();
            return logicConfig;
        }
        /// <summary>
        /// 查询某个物料在中转库的库存信息
        /// </summary>
        /// <param name="itemCode"></param>
        /// <returns></returns>
        public static List<CntrItemRel> getZZKInventoryInfo(string itemCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            List < CntrItemRel > cntrItemRels = new List<CntrItemRel>();
            string areaCode = Settings.areaPropertyList.Where(a => a.areaName.Contains("中转库")).Select(a => a.areaCode).FirstOrDefault();
            if (areaCode != null)
            {
                cntrItemRels = db.Queryable<CntrItemRel>()
                    .LeftJoin<LocCntrRel>((a, b) => a.S_CNTR_CODE == b.S_CNTR_CODE)
                    .LeftJoin<Location>((a, b, c) => b.S_LOC_CODE == c.S_CODE)
                    .LeftJoin<Container>((a, b, c, d) => a.S_CNTR_CODE == d.S_CODE)
                    .Where((a, b, c, d) => c.S_AREA_CODE == areaCode
                                            && c.N_CURRENT_NUM == 1
                                            && c.N_LOCK_STATE == 0
                                            && a.S_ITEM_CODE == itemCode
                                            && d.N_E_STATE == 0             // 托盘正常
                    )
                    .OrderBy((a, b, c, d) => a.T_INBOUND_TIME)
                    .ToList();
            }
            return cntrItemRels;
        }
        /// <summary>
@@ -392,6 +441,11 @@
                };
                result = db.Insertable<AlarmRecord>(alarmRecord).ExecuteCommand() > 0;
            }
            else
            {
                alarmRecord.T_MODIFY = DateTime.Now;
                result = db.Updateable<AlarmRecord>(alarmRecord).ExecuteCommand() > 0;
            }
            return result;
        }
@@ -412,12 +466,12 @@
        /// <summary>
        /// 查询成型机线边
        /// </summary>
        /// <param name="locCode"></param>
        /// <param name="jtNo"></param>
        /// <returns></returns>
        public static SideLocConfig GetLineSideLoc(string locCode)
        public static SideLocConfig GetLineSideLoc(string jtNo)
        {
            var db = new SqlHelper<object>().GetInstance();
            return db.Queryable<SideLocConfig>().Where(a => a.S_LOC_CODE.Trim() == locCode).First();
            return db.Queryable<SideLocConfig>().Where(a => a.EQP.Trim() == jtNo).First();
        }
        /// <summary>
@@ -701,7 +755,20 @@
        }
        /// <summary>
        /// 查询MES叫料任务
        /// 根据机台号查询MES任务
        /// </summary>
        /// <param name="jtNo"></param>
        /// <returns></returns>
        internal static LjMesTask getLjMesTaskByJtNo(string jtNo)
        {
            // 1.查询MES任务表
            var db = new SqlHelper<object>().GetInstance();
            var mesTask = db.Queryable<LjMesTask>().Where(a => a.EQP.Trim() == jtNo && a.RECEIVE_FLAG.Trim() == "PENDING").OrderByDescending(a => a.T_CREATE).First();
            return mesTask;
        }
        /// <summary>
        /// 根据点位编号查询MES叫料任务
        /// </summary>
        /// <param name="positionId"></param>
        /// <returns></returns>
@@ -722,8 +789,6 @@
        {
            bool result = false;
            var db = new SqlHelper<object>().GetInstance();
            mesTask.RECEIVE_FLAG = "COMPLETE";
            mesTask.RECEIVE_DATE = DateTime.Now.ToString("yyyy-MM-dd");
            result = db.Updateable(mesTask).ExecuteCommand() > 0;
            return result;
        }
@@ -898,30 +963,29 @@
        /// <summary>
        /// 下发XC任务
        /// </summary>
        /// <param name="mesTaksId"></param>
        /// <param name="mesTask"></param>
        /// <returns></returns>
        public static bool addLjXcTask(int mesTaksId)
        public static bool addLjXcTask(LjMesTask mesTask)
        {
            bool result = false;
            var db = new SqlHelper<object>().GetInstance();
            var ljMesTask = GetLjMesTaskById(mesTaksId);
            if (ljMesTask != null) {
            if (mesTask != null) {
                LjXcTask ljXcTask = new LjXcTask() { 
                    ID = ljMesTask.ID,
                    POSITION_ID = ljMesTask.POSITION_ID,
                    RETURN_CODE = ljMesTask.RETURN_CODE,
                    MSG_TYPE = ljMesTask.MSG_TYPE,
                    PALLET_TYPE = ljMesTask.PALLET_TYPE,
                    MATERIAL_NAME = ljMesTask.MATERIAL_NAME,
                    MATERIAL_CODE = ljMesTask.MATERIAL_CODE,
                    QTY = ljMesTask.QTY,
                    YCL_BATCH = ljMesTask.YCL_BATCH,
                    PALLET_ID = ljMesTask.PALLET_ID,
                    AGVORDER_ID = ljMesTask.AGVORDER_ID,
                    ID = mesTask.ID,
                    POSITION_ID = mesTask.POSITION_ID,
                    RETURN_CODE = mesTask.RETURN_CODE,
                    MSG_TYPE = mesTask.MSG_TYPE,
                    PALLET_TYPE = mesTask.PALLET_TYPE,
                    MATERIAL_NAME = mesTask.MATERIAL_NAME,
                    MATERIAL_CODE = mesTask.MATERIAL_CODE,
                    QTY = mesTask.QTY,
                    YCL_BATCH = mesTask.YCL_BATCH,
                    PALLET_ID = mesTask.PALLET_ID,
                    AGVORDER_ID = mesTask.AGVORDER_ID,
                    CREATION_DATE = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                    RECEIVE_FLAG = ljMesTask.RECEIVE_FLAG,
                    EQP = ljMesTask.EQP,
                    PLAN_ID = ljMesTask.PLAN_ID
                    RECEIVE_FLAG = mesTask.RECEIVE_FLAG,
                    EQP = mesTask.EQP,
                    PLAN_ID = mesTask.PLAN_ID
                };
                result = db.Insertable<LjXcTask>(ljXcTask).ExecuteCommand() > 0;
            }
HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/api/ApiHelper.cs
@@ -134,7 +134,13 @@
                            EndLocGroup endLocGroup = null;
                            if (barcodeList.Count > 0) 
                            {
                               endLocGroup = WMSHelper.getInStockEndLoc(barcodeList.Count);
                               string itemCode = null;
                               var cntrItemRels = ContainerHelper.GetCntrItemRel(barcodeList[0].rfid);
                               if (cntrItemRels.Count > 0)
                               {
                                    itemCode = cntrItemRels[0].S_ITEM_CODE;
                               }
                               endLocGroup = WMSHelper.getInStockEndLoc(barcodeList.Count, itemCode);
                            }
                            foreach (var ext in extData)
@@ -365,49 +371,66 @@
        {
            ResponseResult response = new ResponseResult();
            //参数校验
            if (model.locCodes.Count == 0)
            int locNum = model.locCodes.Count;
            if (locNum > 0)
            {
                string msg = $"硫化机:{model.mcn}呼叫胚胎出库,参数校验失败,缺少货位信息";
                LogHelper.Info(msg, "WMS");
                response.code = 1;
                response.msg = msg;
                return response;
            }
                Location prevLoc = null;
                Dictionary<string,Location> outLocDic = new Dictionary<string,Location>();
                foreach (var mcn in model.locCodes)
                {
            // 1.一个硫化机工位只能同时存在一个正在执行中的任务
            WCSTask existTask = WCSHelper.GetTaskByEqNo(model.mcn);
            if (existTask == null)
                    var existTask = WCSHelper.GetTaskByEnd(mcn);
                    if (existTask.Count == 0)
            {
                // 2.根据当前时间,判断班次日期和班次
                var currentTime = DateTime.Now;
                var shift = getShift(currentTime.TimeOfDay);
                var dateShift = DateTime.Now.ToString("dd/MM/yyyy");
                        var shift = getShift(currentTime.TimeOfDay);  // 班次
                        var dateShift = currentTime.ToString("dd/MM/yyyy");
                TimeSpan shiftIII_Start = new TimeSpan(7, 00, 0); // 7:00:00
                if (shift == "III" && currentTime.TimeOfDay < shiftIII_Start)
                {
                    dateShift = DateTime.Now.AddDays(-1).ToString("dd/MM/yyyy");
                }
                // 3.根据班次日期+班次+硫化机工位号查询呼叫的物料编码、预计生产数量
                var productionShedule = WMSHelper.getProductionShedule(dateShift, model.mcn, shift);
                        // 3.根据班次日期+班次+硫化机工位号查询 硫化机工单 中的物料编码、预计生产数量
                        var productionShedule = WMSHelper.getProductionShedule(dateShift, mcn, shift);
                if (productionShedule != null && productionShedule.QTY != 0)
                {
                    // 4.查询【胚胎已完成的条码中间表】并计算当前班次的已完成数量
                    int finishNum = WMSHelper.getEmbryoFinishNum(dateShift, model.mcn, shift);
                            // 4查询【胚胎已完成的条码中间表】并计算当前班次的已完成数量
                            int finishNum = WMSHelper.getEmbryoFinishNum(dateShift, mcn, shift);
                    if (productionShedule.QTY > finishNum)
                    {
                        // 5.计算(1.巷道不报警、2.物料状态OK、3.小于失效时间 大于等于生效时间 4.加急料先出、5.先入先出(生产时间))出库物料,生成任务
                        int locNum = model.locCodes.Count;
                        var startLocData = WMSHelper.getOutStockStartLoc(productionShedule.ITEMCODE,locNum);
                        if (startLocData.startLocList != null && startLocData.startLocList.Count == locNum)
                                // 5.出库策略 1.优先查询前一拖货位的左右两边是否满足条件  2.计算(1.巷道不报警、2.物料状态OK、3.小于失效时间 大于等于生效时间 4.加急料先出、5.先入先出(生产时间))出库物料,生成任务
                                var startLoc = WMSHelper.getOutStockStartLoc(productionShedule.ITEMCODE, prevLoc);
                                if (startLoc != null)
                        {
                            var startLocList = startLocData.startLocList;
                            for (int i = 0; i < locNum; i++)
                                    outLocDic.Add(mcn, startLoc);
                                    prevLoc = startLoc;
                                }
                            }
                        }
                    }
                }
                // 6.判断出库货位是否是同一巷道,同一巷道生成任务组号
                string groupNo = null;
                if (outLocDic.Count > 1)
                            {
                                Location startLoc = startLocList[i];
                                Location endLoc =  LocationHelper.GetLoc(model.locCodes[i]);
                    var groupNum = outLocDic.Select(a => a.Value).ToList().GroupBy(a => a.N_ROADWAY).Count();
                    if (groupNum == 1)
                    {
                        groupNo = GenerateTaskGroupNo();
                    }
                }
                // 7.生成出库任务
                if (outLocDic.Count > 0)
                {
                    foreach (var item in outLocDic)
                    {
                        Location endLoc = LocationHelper.GetLoc(item.Key);
                        Location startLoc = item.Value;
                                if (endLoc != null) 
                                {
                                    var locCntrRels = LocationHelper.GetLocCntr(startLoc.S_CODE);
@@ -426,7 +449,7 @@
                                            S_OP_DEF_NAME = "成型机满料下线入库",
                                            N_PRIORITY = 1,
                                            T_START_TIME = DateTime.Now,
                                            S_GROUP_NO = startLocData.groupNo,
                                    S_GROUP_NO = groupNo,
                                        };
                                        if (WMSHelper.CreateWmsTask(wmsTask))
                                        {
@@ -462,29 +485,6 @@
                                }
                            }
                        }
                        else
                        {
                            string msg = $"库内没有满足条件的物料";
                            LogHelper.Info(msg, "WMS");
                            response.code = 1;
                            response.msg = msg;
                        }
                    }
                    else
                    {
                        string msg = $"硫化机:{model.mcn}的当前班次任务已完成,停止叫料";
                        LogHelper.Info(msg, "WMS");
                        response.code = 1;
                        response.msg = msg;
                    }
                }
            }
            else
            {
                string msg = $"硫化机:{model.mcn}的存在正在执行中的任务,请勿重复叫料";
                LogHelper.Info(msg, "WMS");
                response.code = 1;
                response.msg = msg;
            }
            return response;
        }
@@ -498,7 +498,7 @@
        {
            ResponseResult response = new ResponseResult();
            Location startLoc = LocationHelper.GetLoc(model.startLoc);
            var endLocGroup = WMSHelper.getInStockEndLoc(1);
            var endLocGroup = WMSHelper.getInStockEndLoc(1,null);
            if (endLocGroup.endLocList.Count == 1)
            {
                Location endLoc = endLocGroup.endLocList[0];
@@ -562,11 +562,10 @@
        public static ResponseResult callEmptyTrayOutStock(CallEmptyTrayOutStockModel model) 
        {
            ResponseResult responseResult = new ResponseResult();
            Location endLoc = LocationHelper.GetLoc(model.endLoc);
            var startLocData = WMSHelper.getOutStockStartLoc(null, 1);
            if (startLocData.startLocList != null && startLocData.startLocList.Count == 1)
            Location startLoc = WMSHelper.getOutStockStartLoc(null);
            if (startLoc != null)
            {
                Location startLoc = startLocData.startLocList[0];
                Location endLoc = LocationHelper.GetLoc(model.endLoc);
                if (endLoc != null)
                {
                    var locCntrRels = LocationHelper.GetLocCntr(startLoc.S_CODE);
@@ -584,8 +583,7 @@
                            S_OP_DEF_CODE = model.reqId,
                            S_OP_DEF_NAME = "呼叫空托出库",
                            N_PRIORITY = 1,
                            T_START_TIME = DateTime.Now,
                            S_GROUP_NO = startLocData.groupNo,
                            T_START_TIME = DateTime.Now
                        };
                        if (WMSHelper.CreateWmsTask(wmsTask))
                        {
@@ -619,13 +617,16 @@
                        }
                    }
                }
                else
                {
                    responseResult.code = 1;
                    responseResult.msg = $"终点货位:{model.endLoc}在WMS系统中不存在";
                }
            }
            else
            {
                string msg = $"库内没有满足条件的物料";
                LogHelper.Info(msg, "WMS");
                responseResult.code = 1;
                responseResult.msg = msg;
                responseResult.msg = "库内空托不足";
            }
            return responseResult;
        }
HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/api/WmsController.cs
@@ -230,8 +230,7 @@
        {
            public string reqId { get; set; }
            public string reqTime { get; set; }
            public string mcn { get; set; }
            public List<string> locCodes { get; set; }
            public List<string> locCodes { get; set; }  // 硫化机工位
        }
        public class NotifyDeviceSignalModel 
HH.WCS.Mobox3/HH.WCS.Mobox3.YNJT_PT/wms/WMSHelper.cs
@@ -384,63 +384,53 @@
            return greenTireInformation;
        }
        /// <summary>
        /*/// <summary>
        /// 查询入库终点货位
        /// 入库策略:
        /// 巷道内同规格数量 小于 10(暂定),按物料均衡计算,如果所有的巷道内同规格数量都大于10,则按照巷道均衡计算
        /// </summary>
        /// <param name="locNum">1.单货位 2.双货位</param>
        /// <returns></returns>
        public static EndLocGroup getInStockEndLoc(int locNum)
        public static EndLocGroup getInStockEndLoc(int locNum , string itemCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            EndLocGroup endLocGroup = new EndLocGroup();
            List<Location> locations = new List<Location>();
            // 1.按容积率从大到小,对巷道进行排序
            var roadwayOrderList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y")
            List<int> roadwayList = new List<int>();
            // 1.按巷道进行分组,查询每个巷道内同规格物料的数量,并从小到大排序
            var roadwayItemNumOrderGroup = db.Queryable<Location>()
                .LeftJoin<LocCntrRel>((a,b) => a.S_CODE == b.S_LOC_CODE)
                .LeftJoin<CntrItemRel>((a,b,c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
                .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y" && c.S_ITEM_CODE == itemCode)
                .GroupBy((a, b, c) => a.N_ROADWAY)
                .Select((a, b, c) => new { roadway = a.N_ROADWAY, num = SqlFunc.AggregateCount(a.S_CODE) })
                .OrderBy(a => a.num)
                .ToList();
            roadwayList = roadwayItemNumOrderGroup.Where(a => a.num < 10).OrderBy(a => a.num).Select(a => a.roadway).ToList();
            // 2.按巷道进行分组,查询每个巷道空货位数量,并从大到小排序
            if (roadwayList.Count == 0)
            {
                var roadwayEmptyNumOrderGroup = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y")
                .GroupBy(a => a.N_ROADWAY)
                .Select(a => new { roadway = a.N_ROADWAY ,  num = SqlFunc.AggregateCount(a.S_CODE)})
                .OrderByDescending(a => a.num)
                .ToList();
                roadwayList = roadwayEmptyNumOrderGroup.Select(a => a.roadway).ToList();
            }
            if (roadwayList.Count > 0)
            {
            // 查询单货位
            foreach (var order in roadwayOrderList)
                foreach (var roadway in roadwayList)
            {
                if (locNum == 1) 
                {
                    /*// 查询所有相同物料货位
                    var sameItemLocList = db.Queryable<Location>()
                       .LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
                       .LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
                       .Where((a, b, c) => a.S_AREA_CODE == Settings.stockArea
                                       && a.N_ROADWAY == order.roadway
                                       && a.N_CURRENT_NUM == 1
                                       && a.N_LOCK_STATE == 0
                                       && a.C_ENABLE == "Y"
                                       && b.S_CNTR_CODE != null
                                       && c.S_ITEM_CODE == itemCode
                                       )
                       .OrderBy((a, b, c) => new { a.N_LAYER, a.N_COL })
                       .ToList();
                    // 查询相同物料的左右是否有空货位
                    foreach (var loc in sameItemLocList)
                    {
                        var leftLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                        if (leftLoc != null)
                        {
                            locations.Add(leftLoc);
                            break;
                        }
                        var rightLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                        if (rightLoc != null)
                        {
                            locations.Add(leftLoc);
                            break;
                        }
                    }*/
                    // 查询空货位
                    var emptyLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).First();
                        var emptyLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).First();
                    if (emptyLoc != null) 
                    {
                        locations.Add(emptyLoc);
@@ -451,16 +441,16 @@
                if (locNum == 2) 
                {
                    var emptyLocList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).ToList();
                        var emptyLocList = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").OrderBy(a => new { a.N_LAYER, a.N_COL }).ToList();
                    if (emptyLocList.Count > 0)
                    {
                        // 查询双拖空货位
                            // 优先查询相邻双拖空货位
                        if (locations.Count == 0) 
                        {
                            foreach (var loc in emptyLocList)
                            {
                                var leftLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                    // 查询相邻左侧是否有空货位
                                    var leftLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                if (leftLoc != null)
                                {
                                    locations.Add(loc);
@@ -468,30 +458,39 @@
                                    break;
                                }
                                var rightLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == order.roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                    // 查询相邻右侧是否有空货位
                                    var rightLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == roadway && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 0 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                                if (rightLoc != null)
                                {
                                    locations.Add(loc);
                                    locations.Add(leftLoc);
                                        locations.Add(rightLoc);
                                    break;
                                }
                            }
                            }
                            if (locations.Count == locNum)
                            if (locations.Count < locNum)
                            {
                                endLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
                                endLocGroup.endLocList = locations;
                                return endLocGroup;
                            }
                        }
                        // 查询单拖货位
                                // 查询不相邻的单拖货位
                        foreach (var loc in emptyLocList)
                        {
                            locations.Add(loc);
                            if (locations.Count == locNum)
                            {
                                        break;
                                    }
                                }
                            }
                            if (locations.Count == locNum)
                            {
                                endLocGroup.endLocList = locations;
                                // 校验货位是否是同巷道,是则生成任务组号
                                var groupNum = locations.GroupBy(a => a.N_ROADWAY).Count();
                                if (groupNum == 1)
                                {
                                    endLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
                                }
                                return endLocGroup;
                            }
                        }
@@ -499,6 +498,195 @@
                } 
            }
            return endLocGroup;
        }*/
        /// <summary>
        /// 查询入库终点货位
        /// 入库策略:
        /// 巷道内同规格数量 小于 10(暂定),按物料均衡计算,如果所有的巷道内同规格数量都大于10,则按照巷道均衡计算
        /// </summary>
        /// <param name="locNum"></param>
        /// <param name="itemCode"></param>
        /// <returns></returns>
        public static EndLocGroup getInStockEndLoc(int locNum, string itemCode)
        {
            var db = new SqlHelper<object>().GetInstance();
            EndLocGroup endLocGroup = new EndLocGroup { endLocList = new List<Location>() };
            // 1. 获取候选巷道列表(物料均衡或巷道均衡)
            var candidateRoadways = GetCandidateRoadways(db, itemCode);
            if (candidateRoadways.Count == 0) return endLocGroup;
            // 2. 处理单货位入库
            if (locNum == 1)
            {
                return FindSingleLocation(db, candidateRoadways);
            }
            // 3. 处理双货位入库
            return FindDoubleLocations(db, candidateRoadways);
        }
        /// <summary>
        /// 获取候选巷道列表(按策略排序)
        /// </summary>
        private static List<int> GetCandidateRoadways(SqlSugarClient db, string itemCode)
        {
            // 策略1:巷道内同规格物料 < 10 的巷道(按数量升序)
            var materialRoadways = db.Queryable<Location>()
                .LeftJoin<LocCntrRel>((a, b) => a.S_CODE == b.S_LOC_CODE)
                .LeftJoin<CntrItemRel>((a, b, c) => b.S_CNTR_CODE == c.S_CNTR_CODE)
                .Where((a, b, c) =>
                    a.S_AREA_CODE == Settings.stockArea &&
                    a.N_CURRENT_NUM == 1 &&
                    a.N_LOCK_STATE == 0 &&
                    a.C_ENABLE == "Y" &&
                    b.S_CNTR_CODE != null &&
                    c.S_ITEM_CODE == itemCode)
                .GroupBy(a => a.N_ROADWAY)
                .Having(a => SqlFunc.AggregateCount(a.S_CODE) < 10)
                .Select(a => new { Roadway = a.N_ROADWAY, Count = SqlFunc.AggregateCount(a.S_CODE) })
                .OrderBy(a => a.Count)
                .Select(a => a.Roadway)
                .ToList();
            if (materialRoadways.Count > 0) return materialRoadways;
            // 策略2:所有巷道按空货位数降序排序
            return db.Queryable<Location>()
                .Where(a =>
                    a.S_AREA_CODE == Settings.stockArea &&
                    a.N_CURRENT_NUM == 0 &&
                    a.N_LOCK_STATE == 0 &&
                    a.C_ENABLE == "Y")
                .GroupBy(a => a.N_ROADWAY)
                .Select(a => new { Roadway = a.N_ROADWAY, Count = SqlFunc.AggregateCount(a.S_CODE) })
                .OrderByDescending(a => a.Count)
                .Select(a => a.Roadway)
                .ToList();
        }
        /// <summary>
        /// 查找单货位
        /// </summary>
        private static EndLocGroup FindSingleLocation(SqlSugarClient db, List<int> candidateRoadways)
        {
            foreach (var roadway in candidateRoadways)
            {
                var location = db.Queryable<Location>()
                    .Where(a =>
                        a.S_AREA_CODE == Settings.stockArea &&
                        a.N_ROADWAY == roadway &&
                        a.N_CURRENT_NUM == 0 &&
                        a.N_LOCK_STATE == 0 &&
                        a.C_ENABLE == "Y")
                    .OrderBy(a => a.N_LAYER)
                    .OrderBy(a => a.N_COL)
                    .First();
                if (location != null)
                {
                    return new EndLocGroup
                    {
                        endLocList = new List<Location> { location }
                    };
                }
            }
            return new EndLocGroup();
        }
        /// <summary>
        /// 查找双货位(优化相邻货位查找)
        /// </summary>
        private static EndLocGroup FindDoubleLocations(SqlSugarClient db, List<int> candidateRoadways)
        {
            // 先尝试找相邻货位
            foreach (var roadway in candidateRoadways)
            {
                // 一次性获取巷道所有空货位(减少DB查询)
                var emptyLocs = db.Queryable<Location>()
                    .Where(a =>
                        a.S_AREA_CODE == Settings.stockArea &&
                        a.N_ROADWAY == roadway &&
                        a.N_CURRENT_NUM == 0 &&
                        a.N_LOCK_STATE == 0 &&
                        a.C_ENABLE == "Y")
                    .OrderBy(a => a.N_LAYER)
                    .OrderBy(a => a.N_COL)
                    .ToList();
                if (emptyLocs.Count < 2) continue;
                // 在内存中查找相邻货位(高性能)
                var adjacentPair = FindAdjacentLocations(emptyLocs);
                if (adjacentPair != null)
                {
                    return CreateDoubleLocGroup(adjacentPair);
                }
            }
            // 没有相邻货位时,取任意两个货位
            foreach (var roadway in candidateRoadways)
            {
                var emptyLocs = db.Queryable<Location>()
                    .Where(a =>
                        a.S_AREA_CODE == Settings.stockArea &&
                        a.N_ROADWAY == roadway &&
                        a.N_CURRENT_NUM == 0 &&
                        a.N_LOCK_STATE == 0 &&
                        a.C_ENABLE == "Y")
                    .OrderBy(a => a.N_LAYER)
                    .OrderBy(a => a.N_COL)
                    .Take(2)
                    .ToList();
                if (emptyLocs.Count == 2)
                {
                    return CreateDoubleLocGroup(emptyLocs);
                }
            }
            return new EndLocGroup();
        }
        /// <summary>
        /// 在内存中查找相邻货位(高效算法)
        /// </summary>
        private static List<Location> FindAdjacentLocations(List<Location> locations)
        {
            // 按层->列排序,便于查找相邻
            var sorted = locations
                .OrderBy(l => l.N_LAYER)
                .ThenBy(l => l.N_COL)
                .ToList();
            for (int i = 0; i < sorted.Count - 1; i++)
            {
                var current = sorted[i];
                var next = sorted[i + 1];
                // 判断是否同一层且相邻列
                if (current.N_LAYER == next.N_LAYER &&
                    current.N_COL + 1 == next.N_COL)
                {
                    return new List<Location> { current, next };
                }
            }
            return null;
        }
        /// <summary>
        /// 创建双货位返回结果
        /// </summary>
        private static EndLocGroup CreateDoubleLocGroup(List<Location> locations)
        {
            return new EndLocGroup
            {
                endLocList = locations,
                groupNo = locations.GroupBy(a => a.N_ROADWAY).Count() == 1
                    ? WMSHelper.GenerateTaskGroupNo()
                    : null
            };
        }
        public class EndLocGroup
@@ -509,14 +697,15 @@
        /// <summary>
        /// 查询出库开始货位
        /// 计算(1.巷道不报警、2.物料状态OK、3.小于失效时间 大于等于生效时间 4.加急料先出、5.先入先出(生产时间))出库物料
        /// 1.计算(1.巷道不报警、2.物料状态OK、3.小于失效时间 大于等于生效时间 4.加急料先出、5.先入先出(生产时间))出库物料
        /// 2.同等条件下,优先取前一托货的相邻货位(暂时不做考虑,需确定先入先出(生产时间)是按天算,还是精确到时分秒)
        /// </summary>
        /// <param name="itemCode"></param>
        /// <param name="locNum"></param>
        public static StartLocGroup getOutStockStartLoc(string itemCode, int locNum )
        /// <param name="prevLoc"></param>
        public static Location getOutStockStartLoc(string itemCode, Location prevLoc = null)
        {
            var db = new SqlHelper<object>().GetInstance();
            StartLocGroup startLocGroup = new StartLocGroup();
            Location startLoc = null;
            // 1.查询(物料状态OK ,且小于失效时间,大于等于生效时间)出库物料,并按加急料先出,先入先出(生产时间)的原则进行排序
            var query = db.Queryable<Location>()
@@ -557,48 +746,10 @@
                        continue;
                    }
                    var cntrItemRel = db.Queryable<CntrItemRel>().LeftJoin<LocCntrRel>((a, b) => a.S_CNTR_CODE == b.S_CNTR_CODE).Where((a, b) => b.S_LOC_CODE == loc.S_CODE).First();
                    if (cntrItemRel != null)
                    {
                        startLocGroup.startLocList.Add(loc);
                        if (locNum == startLocGroup.startLocList.Count)
                        {
                            break;
                        }
                        var leftLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == loc.N_ROADWAY && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL - 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                        if (leftLoc != null)
                        {
                            var locCntrRel = db.Queryable<LocCntrRel>()
                               .LeftJoin<CntrItemRel>((a, b) => a.S_CNTR_CODE == b.S_CNTR_CODE)
                               .Where((a, b) => a.S_LOC_CODE == leftLoc.S_CODE && b.S_ITEM_CODE == itemCode)
                               .First();
                            if (locCntrRel != null)
                            {
                                startLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
                                startLocGroup.startLocList.Add(leftLoc);
                                break;
                    startLoc = loc;
                            }
                        }
                        var rightLoc = db.Queryable<Location>().Where(a => a.S_AREA_CODE == Settings.stockArea && a.N_ROADWAY == loc.N_ROADWAY && a.N_ROW == loc.N_ROW && a.N_COL == loc.N_COL + 1 && a.N_LAYER == loc.N_LAYER && a.N_CURRENT_NUM == 1 && a.N_LOCK_STATE == 0 && a.C_ENABLE == "Y").First();
                        if (rightLoc != null && startLocGroup.startLocList.Count == 0)
                        {
                            var locCntrRel = db.Queryable<LocCntrRel>()
                                .LeftJoin<CntrItemRel>((a, b) => a.S_CNTR_CODE == b.S_CNTR_CODE)
                                .Where((a, b) => a.S_LOC_CODE == rightLoc.S_CODE && b.S_ITEM_CODE == itemCode)
                                .First();
                            if (locCntrRel != null)
                            {
                                startLocGroup.groupNo = WMSHelper.GenerateTaskGroupNo();
                                startLocGroup.startLocList.Add(rightLoc);
                                break;
                            }
                        }
                    }
                }
            }
            return startLocGroup;
            return startLoc;
        }