杨前锦
2025-06-11 e0d89637030791ce1e7dd46ca5fdec9979977960
HH.WCS.Mobox3/HH.WCS.Mobox3.FJJT/api/ApiHelper.cs
New file
@@ -0,0 +1,2201 @@
using HH.WCS.Mobox3.FJJF.models;
using HH.WCS.Mobox3.FJJT.device;
using HH.WCS.Mobox3.FJJT.dispatch;
using HH.WCS.Mobox3.FJJT.models;
using HH.WCS.Mobox3.FJJT.process;
using HH.WCS.Mobox3.FJJT.util;
using HH.WCS.Mobox3.FJJT.wms;
using Newtonsoft.Json;
using NLog;
using NLog.Fluent;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Threading;
using static HH.WCS.Mobox3.FJJT.api.ApiModel;
using static HH.WCS.Mobox3.FJJT.api.OtherModel;
using static HH.WCS.Mobox3.FJJT.api.WmsController;
using static HH.WCS.Mobox3.FJJT.util.ExcetionHelper;
using static HH.WCS.Mobox3.FJJT.util.Settings;
using static System.Net.Mime.MediaTypeNames;
namespace HH.WCS.Mobox3.FJJT.api {
    /// <summary>
    /// api接口辅助类
    /// </summary>
    public class ApiHelper {
        static ApiHelper() {
        }
        /// <summary>
        /// 空工装出库
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult emptyPalletOutStock(OutStockModel model) {
            ResponseResult result = new ResponseResult();
            Location endLoc = LocationHelper.GetLoc(model.endLocCode);
            if (endLoc == null)
            {
                WMSHelper.addAlarmRecord("流程异常", "低", $"空工装出库,WMS系统未查询到终点货位:{model.endLocCode}");
                throw new BusinessException($"空工装出库,WMS系统未查询到终点货位:{model.endLocCode},请检查终点货位编码是否正确");
            }
            else if (endLoc.N_LOCK_STATE != 0)
            {
                WMSHelper.addAlarmRecord("流程异常", "低", $"空工装出库,终点货位:{model.endLocCode}处于锁定状态");
                throw new BusinessException($"空工装出库,终点货位:{model.endLocCode}处于锁定状态");
            }
            var areaCodes = Settings.getRelAreaCodes(endLoc.S_AREA_CODE);
            if (areaCodes.Count == 0)
            {
                WMSHelper.addAlarmRecord("流程异常", "低", $"空工装出库,未配置库区:{endLoc.S_AREA_CODE}的关联关系");
                throw new BusinessException($"空工装出库,未配置库区:{endLoc.S_AREA_CODE}的关联关系");
            }
            Location startLoc = WMSHelper.getOutStockStartLoc(areaCodes[0], null);
            if (startLoc == null)
            {
                WMSHelper.addAlarmRecord("流程异常", "低", $"空工装出库,库区:{areaCodes[0]}未查询到空工装");
                throw new BusinessException($"空工装出库,未查询到空工装,立库可能缺少空工装");
            }
            var locCntrRels = LocationHelper.GetLocCntr(startLoc.S_CODE);
            if (locCntrRels.Count > 0)
            {
                string cntrCode = locCntrRels[0].S_CNTR_CODE;
                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_NAME = "空工装出库",
                    N_PRIORITY = 10,
                    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 = endLoc.S_CODE,
                        S_END_AREA = endLoc.S_AREA_CODE,
                        S_SCHEDULE_TYPE = "WCS",
                        N_PRIORITY = wmsTask.N_PRIORITY,
                        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);
                    }
                }
            }
            else
            {
                WMSHelper.addAlarmRecord("流程异常", "中", $"查询的空工装有误,错误原因:未查询到货位容器的绑定关系");
                throw new BusinessException($"查询空工装错误,未查询到货位容器的绑定关系,请联系开发人员排查");
            }
            return result;
        }
        /// <summary>
        /// WCS读码请求流程
        /// 业务场景:读码入库、读码出库
        /// 1.判断RFID是否存在WMS系统中,否,则默认为RFID无法识别
        /// 2.判断RFID是否与任务RFID是否一致
        /// 3.记录RFID异常信息
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public static ResponseResult readCodeProcess(ReadCodeRequest request) {
            ResponseResult responseResult = new ResponseResult();
            Location loc = LocationHelper.GetLoc(request.loc);
            if (loc != null)
            {
                var cst = WCSHelper.GetTask(request.taskNo);
                if (cst != null)
                {
                    var container = ContainerHelper.GetCntr(request.cntrNo);
                    if (container != null)
                    {
                        if (cst.S_CNTR_CODE != request.cntrNo)
                        {
                            ContainerHelper.UpdateCntrState(cst.S_CNTR_CODE, 1);
                            WMSHelper.addRfidAnomalyRecord(cst.S_CNTR_CODE, 2, request.loc, cst.S_CODE);
                        }
                    }
                    else
                    {
                        ContainerHelper.UpdateCntrState(cst.S_CNTR_CODE, 1);
                        WMSHelper.addRfidAnomalyRecord(cst.S_CNTR_CODE, 1, request.loc, cst.S_CODE);
                    }
                    /*WCSHelper.ActivatePreCreateTask(cst.S_OP_CODE);*/
                    // 方案2 4.如果读取不成功,查看异常区是否有空货位
                    /* var agvEndLoc = WMSHelper.GetTransfeRelevanceLoc(loc.S_AREA_CODE, "4");
                     if (agvEndLoc != null)
                     {
                         // 4.1 有,则创建搬运异常区任务
                         WCSTask wcsTask = new WCSTask()
                         {
                             S_OP_NAME = cst.S_OP_NAME,
                             S_OP_CODE = cst.S_OP_CODE,
                             S_CODE = WCSHelper.GenerateTaskNo(),
                             S_CNTR_CODE = cst.S_CNTR_CODE,
                             S_TYPE = "异常工装移库异常区",
                             S_START_LOC = loc.S_CODE,
                             S_START_AREA = loc.S_AREA_CODE,
                             S_END_LOC = agvEndLoc.S_CODE,
                             S_END_AREA = agvEndLoc.S_AREA_CODE,
                             S_SCHEDULE_TYPE = "AGV",
                             N_PRIORITY = 99,
                             T_START_TIME = DateTime.Now,
                         };
                         if (WCSHelper.CreateTask(wcsTask))
                         {
                             // 起点、接驳点、终点加锁
                             LocationHelper.LockLoc(wcsTask.S_START_LOC, 1);
                             LocationHelper.LockLoc(wcsTask.S_END_LOC, 1);
                             WCSHelper.CancelPreCreateTask(cst.S_OP_CODE);
                         }
                     }
                     else
                     {
                         // 4.2 无,则记录异常激活预创建任务
                         WCSHelper.ActivatePreCreateTask(cst.S_OP_CODE);
                     }*/
                }
                else
                {
                    WMSHelper.addAlarmRecord("流程异常", "低", $"没有查询到读码的任务,任务号:{request.taskNo}");
                }
            }
            else
            {
                WMSHelper.addAlarmRecord("流程异常", "中", $"读码位:{request.loc},没有在WMS系统中录入");
                throw new BusinessException($"读码位:{request.loc},没有在WMS系统中录入");
            }
            return responseResult;
        }
        /// <summary>
        /// 满料下线流程
        /// 1.判断RFID是否读取成功,读取不成功,记录异常(读取失败后,临时生成一个托盘码)
        /// 2.根据RFID查询中间表,不存在,记录异常
        /// 3.判断满料接驳位对应的空工装缓存位状态(查询线体光电)
        ///
        /// 直连
        /// 4.需要补,则生成空工装出库任务(胎面、胎侧直连提高优先级)
        /// 5.下发满料搬运任务(帘布直连提高优先级)
        ///
        /// 非直连
        /// 4.需要补空工装,则空工装出库任务(完成后,生成满料搬运任务,并提高优先级99)
        /// 5.不需要补空工装,则生成满料搬运任务
        ///
        /// 6.读任务中间表
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult offLineProcess(OffLineRequest model) {
            ResponseResult responseResult = new ResponseResult();
            // 查询起点货位是否存在已存在任务,防止任务重复发起
            var existWmsTask = WMSHelper.GetWmsTaskByStart(model.loc);
            if (existWmsTask == null)
            {
                // 查询对应机台的物料下线配置信息
                var logicConfig = WMSHelper.getLogicConfigByJtCode(model.jtNo);
                if (logicConfig != null)
                {
                    Container container = ContainerHelper.GetCntr(model.cntrNo);
                    if (container == null || !model.isNormal)
                    {
                        ContainerHelper.AddCntr(model.cntrNo);
                        ContainerHelper.UpdateCntrState(model.cntrNo, 1);
                        WMSHelper.addRfidAnomalyRecord(model.cntrNo, 1, model.loc, null);
                    }
                    // 根据物料下线配置信息,判断任务类型是直连下线还是非直连下线
                    if (logicConfig.S_TASK_TYPE == "1" || logicConfig.S_TASK_TYPE == "2")
                    {
                        triggerItemOffLineFlow(model.loc, model.cntrNo, logicConfig);
                    }
                    else
                    {
                        // 满料下线(非直连)
                        triggerItemOffLineFlow4(model.loc, model.cntrNo, logicConfig);
                    }
                }
                else
                {
                    WMSHelper.addAlarmRecord("流程异常", "高", $"机台号{model.jtNo},没有可用的逻辑线路,请联系管理人员");
                    throw new BusinessException($"机台号{model.jtNo},没有可用的逻辑线路,请联系管理人员");
                }
            }
            else
            {
                WMSHelper.addAlarmRecord("流程异常", "低", $"下线货位:{model.loc}已有任务,请勿重复下发任务");
                throw new BusinessException($"下线货位:{model.loc}已有任务,请勿重复下发任务");
            }
            return responseResult;
        }
        /// <summary>
        /// 满料下线(非直连)
        /// 1.创建满料下线作业
        /// 2.判断是否需要补空工装,需要则创建空工装补缓存位任务
        /// 3.判断容器是否是异常工装,是,如异常区有空货位则创建异常工装入线边异常区任务;否,则创建满料工装入库任务(如需要补空工装,则将任务状态改为预创建,等待补空工装任务完成后触发)
        /// 4.作业创建完成后,读取中间表,更新中间表状态
        /// </summary>
        /// <param name="offLineLoc"></param>
        /// <param name="logicConfig"></param>
        /// <param name="cntrNo"></param>
        /// <returns></returns>
        public static bool triggerItemOffLineFlow4(string offLineLoc,string cntrNo, LogicConfig logicConfig ,LjMesTask mesTask = null)
        {
            bool result = true;
            try
            {
                if (mesTask == null)
                {
                    mesTask = WMSHelper.getLjMesTaskByCntr(cntrNo);
                }
                if (mesTask != null)
                {
                    // 2.判断是否需要补空工装,需要,则创建空工装出库任务
                    bool photoStatus = false;
                    var hcLoc = LocationHelper.GetLoc(logicConfig.S_LKBKHCLOC);
                    if (hcLoc != null)
                    {
                        if (hcLoc.N_CURRENT_NUM != 0 && hcLoc.N_LOCK_STATE == 0)
                        {
                            hcLoc = LocationHelper.GetEmptyLoc(hcLoc.S_AREA_CODE);
                        }
                        if (hcLoc != null)
                        {
                            var bufferLocConfig = Settings.GetBufferLocConfig(hcLoc.S_CODE);  // 缓存位关联属性
                            if (bufferLocConfig != null || hcLoc.N_CURRENT_NUM == 0)
                            {
                                photoStatus = true;
                                // 方案1,如果非直连的缓存位有光电信号,则查询设备状态判断是否需要补空工装
                                /*   var deviceStatusDatas = WCSDispatch.getDeviceStatus(new List<string>() { bufferLocConfig.deviceNo });
                                   if (deviceStatusDatas != null && deviceStatusDatas.Count > 0)
                                   {
                                       var deviceStatus = deviceStatusDatas[0];
                                       if (deviceStatus.workStatus == 1 && deviceStatus.manualStatus == 0)
                                       {
                                           photoStatus = deviceStatus.photoStatus == 1;
                                       }
                                       else
                                       {
                                           WMSHelper.addAlarmRecord("流程异常", "高", $"设备号:{bufferLocConfig.deviceNo},设备当前处于不可用状态,请联系管理人员调整设备状态");
                                           throw new BusinessException($"设备号:{bufferLocConfig.deviceNo},设备当前处于不可用状态,请联系管理人员调整设备状态");
                                       }
                                   }
                                   else
                                   {
                                       WMSHelper.addAlarmRecord("流程异常", "高", $"设备号:{bufferLocConfig.deviceNo},查询设备状态失败,请联系工作人员查看设备是否正常");
                                       throw new BusinessException($"设备号:{bufferLocConfig.deviceNo},查询设备状态失败,请联系工作人员查看设备是否正常");
                                   }*/
                            }
                            else
                            {
                                WMSHelper.addAlarmRecord("流程异常", "高", $"缓存位:{logicConfig.S_LKBKHCLOC},没有配置属性信息,请联系管理人员配置");
                                throw new BusinessException($"缓存位:{logicConfig.S_LKBKHCLOC},没有配置属性信息,请联系管理人员配置");
                            }
                        }
                    }
                    else
                    {
                        WMSHelper.addAlarmRecord("流程异常", "高", $"缓存位:{logicConfig.S_LKBKHCLOC},没有WMS系统中录入");
                        throw new BusinessException($"缓存位:{logicConfig.S_LKBKHCLOC},没有WMS系统中录入");
                    }
                    // 空工装出库判断条件
                    Location kgzStartLoc = null;
                    Location kgzEndLoc = null;
                    string kgzCntrCode = null;
                    if (photoStatus)
                    {
                        kgzStartLoc = LocationHelper.GetLoc(logicConfig.S_LKKTJBLOC);
                        kgzEndLoc = LocationHelper.GetLoc(logicConfig.S_LKBKHCLOC);
                        if (kgzStartLoc == null)
                        {
                            WMSHelper.addAlarmRecord("流程异常", "高", $"库区:{logicConfig.S_AREA_CODE},没有可用的空工装");
                            photoStatus = false;
                        }
                        if (kgzEndLoc == null)
                        {
                            WMSHelper.addAlarmRecord("流程异常", "中", $"空工装缓存位:{logicConfig.S_LKBKHCLOC},没有在WMS系统中录入");
                            photoStatus = false;
                        }
                        var locCntrRels = LocationHelper.GetLocCntr(kgzStartLoc.S_CODE);
                        if (locCntrRels.Count > 0)
                        {
                            kgzCntrCode = locCntrRels[0].S_CNTR_CODE;
                        }
                        else
                        {
                            WMSHelper.addAlarmRecord("流程异常", "中", $"空工装出库站台:{logicConfig.S_LKKTJBLOC},没有空工装");
                            photoStatus = false;
                        }
                    }
                    string cntrCode = mesTask.PALLET_ID;
                    Location startLoc = LocationHelper.GetLoc(offLineLoc);
                    if (startLoc != 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 = "虚拟货位",
                            S_END_AREA = "虚拟库区",
                            S_TYPE = "满料/异常工装入库任务(非直连)",
                            S_OP_DEF_NAME = "满料/异常工装入库任务(非直连)",
                            S_OP_DEF_CODE = mesTask.ID.ToString(),
                            T_START_TIME = DateTime.Now,
                        };
                        if (WMSHelper.CreateWmsTask(wmsTask))
                        {
                            int priority = 10;
                            // 2.判断是否需要补空工装,需要则创建空工装补缓存位任务
                            if (photoStatus)
                            {
                                WCSTask kgzWcsTask = new WCSTask()
                                {
                                    S_OP_NAME = wmsTask.S_OP_DEF_NAME,
                                    S_OP_CODE = wmsTask.S_CODE,
                                    S_CODE = WCSHelper.GenerateTaskNo(),
                                    S_CNTR_CODE = kgzCntrCode,
                                    S_TYPE = "空工装出库任务",
                                    S_START_LOC = kgzStartLoc.S_CODE,
                                    S_START_AREA = kgzStartLoc.S_AREA_CODE,
                                    S_END_LOC = kgzEndLoc.S_CODE,
                                    S_END_AREA = kgzEndLoc.S_AREA_CODE,
                                    S_SCHEDULE_TYPE = "AGV",
                                    N_PRIORITY = priority,
                                    T_START_TIME = DateTime.Now,
                                };
                                if (WCSHelper.CreateTask(kgzWcsTask))
                                {
                                    // 起点、终点加锁
                                    LocationHelper.LockLoc(kgzWcsTask.S_START_LOC, 2);
                                    LocationHelper.LockLoc(kgzWcsTask.S_END_LOC, 1);
                                }
                            }
                            // 3.创建满料工装入库任务(如需要补空工装,则将任务状态改为预创建,等待补空工装任务完成后触发)
                            WCSTask wcsTask = new WCSTask()
                            {
                                S_OP_NAME = wmsTask.S_OP_DEF_NAME,
                                S_OP_CODE = wmsTask.S_CODE,
                                S_TYPE = "满料工装入库任务(非直连)",
                                S_CODE = WCSHelper.GenerateTaskNo(),
                                S_CNTR_CODE = wmsTask.S_CNTR_CODE,
                                S_START_LOC = startLoc.S_CODE,
                                S_START_AREA = startLoc.S_AREA_CODE,
                                S_END_LOC = wmsTask.S_END_LOC,
                                S_END_AREA = wmsTask.S_END_AREA,
                                S_SCHEDULE_TYPE = "AGV",
                                N_PRIORITY = 99,
                                T_START_TIME = DateTime.Now,
                            };
                            if (photoStatus)
                            {
                                wcsTask.N_B_STATE = -1;
                                wcsTask.S_B_STATE = "预创建";
                            }
                            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);
                                // 4.作业创建完成后,读取中间表,更新中间表状态
                                WMSHelper.readLjMesOffItemTask(wmsTask.S_CODE, mesTask.ID);
                            }
                        }
                    }
                    else
                    {
                        WMSHelper.addAlarmRecord("流程异常", "中", $"下线位:{offLineLoc},没有在WMS系统中录入");
                        throw new BusinessException($"下线位:{offLineLoc},没有在WMS系统中录入");
                    }
                }
                else
                {
                    WMSHelper.addAlarmRecord("流程异常", "中", $"非直连下线货位:{offLineLoc}触发下线请求,未查询到MES任务");
                    throw new BusinessException($"非直连下线货位:{offLineLoc}触发下线请求,未查询到MES任务");
                }
            }
            catch (BusinessException be)
            {
                throw be;
            }
            catch (Exception ex)
            {
                WMSHelper.addAlarmRecord("系统错误", "高", ex.Message);
                LogHelper.Error("WMS内部错误:触发满料下线(非直连)作业错误 ; ERROR_MGS:" + ex.Message, ex, "WMS");
                result = false;
            }
            return result;
        }
        /// <summary>
        /// 满料下线(直连)
        /// 1.创建满料下线作业
        /// 2.判断是否需要补空工装,需要,则创建空工装出库任务
        /// 3.创建满料入库任务
        /// 4.判断直连模式,如是胎侧直连模式,则提高空工装出库任务优先级;如是帘布直连模式则,提高满料入库优先级
        /// 5.作业创建完成后,读取中间表,更新中间表状态
        /// </summary>
        /// <param name="offLineLoc">下线货位</param>
        /// <param name="cntrNo">下线容器编码</param>
        /// <param name="logicConfig">逻辑配置</param>
        /// <returns></returns>
        public static bool triggerItemOffLineFlow(string offLineLoc, string cntrNo, LogicConfig logicConfig ) {
            bool result = true;
            try
            {
                // 2.判断是否需要补空工装,需要,则创建空工装出库任务
                bool photoStatus = false;
                var hcLoc = LocationHelper.GetLoc(logicConfig.S_LKBKHCLOC);
                if (hcLoc != null)
                {
                    var bufferLocConfig = Settings.GetBufferLocConfig(hcLoc.S_CODE);
                    if (bufferLocConfig != null)
                    {
                        // 测试代码
                        photoStatus = true;
                       /* // 业务代码,勿删
                        var deviceStatusDatas = WCSDispatch.getDeviceStatus(new List<string>() { bufferLocConfig.deviceNo });
                        if (deviceStatusDatas != null && deviceStatusDatas.Count > 0)
                        {
                            var deviceStatus = deviceStatusDatas[0];
                            if (deviceStatus.workStatus == 1 && deviceStatus.manualStatus == 0)
                            {
                                photoStatus = deviceStatus.photoStatus == 1;
                            }
                            else
                            {
                                WMSHelper.addAlarmRecord("流程异常", "高", $"设备号:{bufferLocConfig.deviceNo},设备当前处于不可用状态,请联系管理人员调整设备状态");
                                throw new BusinessException($"设备号:{bufferLocConfig.deviceNo},设备当前处于不可用状态,请联系管理人员调整设备状态");
                            }
                        }
                        else
                        {
                            WMSHelper.addAlarmRecord("流程异常", "高", $"设备号:{bufferLocConfig.deviceNo},查询设备状态失败,请联系工作人员查看设备是否正常");
                            throw new BusinessException($"设备号:{bufferLocConfig.deviceNo},查询设备状态失败,请联系工作人员查看设备是否正常");
                        }*/
                    }
                    else
                    {
                        WMSHelper.addAlarmRecord("流程异常", "高", $"缓存位:{logicConfig.S_LKBKHCLOC},没有配置属性信息,请联系管理人员配置");
                        throw new BusinessException($"缓存位:{logicConfig.S_LKBKHCLOC},没有配置属性信息,请联系管理人员配置");
                    }
                }
                else
                {
                    WMSHelper.addAlarmRecord("流程异常", "高", $"缓存位:{logicConfig.S_LKBKHCLOC},没有在WMS系统中录入");
                    throw new BusinessException($"缓存位:{logicConfig.S_LKBKHCLOC},没有在WMS系统中录入");
                }
                Location startLoc = LocationHelper.GetLoc(offLineLoc);
                if (startLoc == null)
                {
                    WMSHelper.addAlarmRecord("流程异常", "中", $"下线位:{offLineLoc},没有在WMS系统中录入");
                    throw new BusinessException($"下线位:{offLineLoc},没有在WMS系统中录入");
                }
                Location endLoc = WMSHelper.getInStockEndLoc(logicConfig.S_AREA_CODE, 1);
                if (endLoc == null)
                {
                    WMSHelper.addAlarmRecord("流程异常", "高", $"库内没有空余货位");
                    throw new BusinessException($"库内没有空余货位");
                }
                LjMesTask mesTask = WMSHelper.getLjMesTaskByCntr(cntrNo);
                // 1.创建满料下线作业
                var wmsTask = new WMSTask()
                {
                    S_CNTR_CODE = cntrNo,
                    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_NAME = "满料/异常工装入库任务(直连)",
                    S_OP_DEF_CODE = mesTask != null ? mesTask.ID.ToString() : null,
                    T_START_TIME = DateTime.Now,
                };
                if (WMSHelper.CreateWmsTask(wmsTask))
                {
                    int priority = 10;
                    Dictionary<int, WCSTask> taskDic = new Dictionary<int, WCSTask>();
                    // 是否创建空工装出口任务
                    if (photoStatus || true )
                    {
                        Location kgzStartLoc = WMSHelper.getOutStockStartLoc(logicConfig.S_AREA_CODE, null);
                        Location kgzEndLoc = LocationHelper.GetLoc(logicConfig.S_LKBKHCLOC);
                        if (kgzStartLoc == null)
                        {
                            WMSHelper.DeleteWmsTask(wmsTask.S_CODE);
                            WMSHelper.addAlarmRecord("流程异常", "高", $"库区:{logicConfig.S_AREA_CODE},没有可用的空工装");
                            throw new BusinessException($"库区:{logicConfig.S_AREA_CODE},没有可用的空工装");
                        }
                        if (kgzEndLoc == null)
                        {
                            WMSHelper.DeleteWmsTask(wmsTask.S_CODE);
                            WMSHelper.addAlarmRecord("流程异常", "中", $"空工装缓存位:{logicConfig.S_LKBKHCLOC},没有在WMS系统中录入");
                            throw new BusinessException($"空工装缓存位:{logicConfig.S_LKBKHCLOC},没有在WMS系统中录入");
                        }
                        var locCntrRels = LocationHelper.GetLocCntr(kgzStartLoc.S_CODE);
                        if (locCntrRels.Count > 0)
                        {
                            string kgzCntrCode = locCntrRels[0].S_CNTR_CODE;
                            // 如是胎侧直连模式,则提高空工装出库任务优先级
                            if (logicConfig.S_TASK_TYPE == "1")
                            {
                                priority = 99;
                            }
                            WCSTask kgzWcsTask = new WCSTask()
                            {
                                S_OP_NAME = wmsTask.S_OP_DEF_NAME,
                                S_OP_CODE = wmsTask.S_CODE,
                                S_CODE = WCSHelper.GenerateTaskNo(),
                                S_CNTR_CODE = kgzCntrCode,
                                S_TYPE = "空工装出库任务",
                                S_START_LOC = kgzStartLoc.S_CODE,
                                S_START_AREA = kgzStartLoc.S_AREA_CODE,
                                S_END_LOC = kgzEndLoc.S_CODE,
                                S_END_AREA = kgzEndLoc.S_AREA_CODE,
                                S_SCHEDULE_TYPE = "WCS",
                                N_PRIORITY = priority,
                                T_START_TIME = DateTime.Now,
                            };
                            taskDic.Add(priority, kgzWcsTask);
                        }
                        else
                        {
                            WMSHelper.DeleteWmsTask(wmsTask.S_CODE);
                            WMSHelper.addAlarmRecord("流程异常", "高", $"查询空工装货位错误,货位:{kgzStartLoc.S_CODE}没有空工装");
                            throw new BusinessException($"查询空工装货位错误,货位:{kgzStartLoc.S_CODE}没有空工装");
                        }
                    }
                    // 如是帘布直连模式则,提高满料入库优先级
                    if (logicConfig.S_TASK_TYPE == "2")
                    {
                        priority = 99;
                    }
                    else
                    {
                        priority = 10;
                    }
                    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 = "WCS",
                        N_PRIORITY = priority,
                        T_START_TIME = DateTime.Now,
                    };
                    taskDic.Add(priority, wcsTask);
                    var tasks = taskDic.OrderByDescending(a => a.Key).Select(a => a.Value).ToList();
                    foreach (var task in tasks)
                    {
                        if (WCSHelper.CreateTask(task))
                        {
                            // 起点、终点加锁
                            LocationHelper.LockLoc(task.S_START_LOC, 2);
                            LocationHelper.LockLoc(task.S_END_LOC, 1);
                        }
                    }
                    // 更新作业任务状态
                    wmsTask.N_B_STATE = 1;
                    WMSHelper.UpdateTaskState(wmsTask);
                    // 5.作业创建完成后,读取中间表,更新中间表状态
                    if (mesTask != null)
                    {
                        WMSHelper.readLjMesOffItemTask(wmsTask.S_CODE, mesTask.ID);
                    }
                    else
                    {
                        ContainerHelper.UpdateCntrState(cntrNo, 1);
                        WMSHelper.addRfidAnomalyRecord(cntrNo, 3, offLineLoc, null);
                    }
                }
            }
            catch (BusinessException be)
            {
                throw be;
            }
            catch (Exception ex)
            {
                // 报警:WMS内部错误:触发满料工装下线作业错误
                WMSHelper.addAlarmRecord("系统错误", "高", ex.Message);
                LogHelper.Info($"WMS内部错误:触发满料工装下线作业错误 ; 错误原因:{ex.Message}", "WMS");
                result = false;
            }
            return result;
        }
        /// <summary>
        /// 叫料请求
        /// 1.查询中间表,判断是否是环带物料
        /// 2.查询库区物料信息,并过滤故障的堆垛机立库
        /// 3.无库存写入中间表异常和异常原因
        /// 4.计算出库货位,生成出库任务
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult callMaterialProcess(CallMaterialRequest model)
        {
            ResponseResult responseResult = new ResponseResult();
            var mesTask = WMSHelper.getLjMesTaskByLoc(model.loc);
            if (mesTask != null)
            {
                Location endLoc = LocationHelper.GetLoc(model.loc);
                Location startLoc = null;
                Location middleLoc = null;
                string scheduleType = "";
                if (mesTask.PALLET_TYPE == "环带")
                {
                    scheduleType = "HDK";
                    // 查询环带库该物料库存情况,并比较与中转库的库存进行比较,先入先出
                }
                else
                {
                    scheduleType = "WCS";
                    // 查询库区物料信息,根据先入先出原则计算,物料起点
                    startLoc = WMSHelper.getOutStockStartLoc(null, mesTask.MATERIAL_CODE);
                }
                if (startLoc == null)
                {
                    // 无库存写入中间表异常和异常原因
                    mesTask.RETURN_CODE = "6";
                    mesTask.RECEIVE_MSG = "没有库存或设备故障无法出库";
                    WMSHelper.updateLjMesTask(mesTask);
                    WMSHelper.addAlarmRecord("流程异常", "低", $"MES叫料任务{mesTask.ID},没有库存或设备故障无法出库");
                    responseResult.code = 1;
                    responseResult.msg = "没有库存或设备故障无法出库";
                    return responseResult;
                }
                middleLoc = WMSHelper.GetMinTaskTransfeLoc(startLoc.S_AREA_CODE, 2 , 2);
                if (middleLoc == null) {
                    WMSHelper.addAlarmRecord("流程异常", "高", $"MES叫料任务{mesTask.ID},立库接驳位可能处于锁定或禁用状态,请查看");
                    responseResult.code = 1;
                    responseResult.msg = "立库接驳位可能处于锁定或禁用状态";
                    return responseResult;
                }
                String cntrCode = "";
                var locCntrs = LocationHelper.GetLocCntr(startLoc.S_CODE);
                if (locCntrs != null && locCntrs.Count > 0)
                {
                    cntrCode = locCntrs[0].S_CNTR_CODE;
                }
                var wmsTask = new WMSTask()
                {
                    S_CNTR_CODE = "",
                    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 = "满料出库任务",
                    N_PRIORITY = 10,
                    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 = scheduleType,
                        N_PRIORITY = wmsTask.N_PRIORITY,
                        T_START_TIME = DateTime.Now,
                    };
                    if (WCSHelper.CreateTask(wcsTask))
                    {
                        // 起点、终点加锁
                        LocationHelper.LockLoc(wcsTask.S_START_LOC, 2);
                        LocationHelper.LockLoc(wcsTask.S_END_LOC, 1);
                        LocationHelper.LockLoc(wmsTask.S_END_LOC, 1);
                        // 更新作业任务状态
                        wmsTask.N_B_STATE = 1;
                        WMSHelper.UpdateTaskState(wmsTask);
                        WMSHelper.updateMesTaskStatus("", "2");
                        // 任务创建成功读取MES任务
                        WMSHelper.readLjMesCallItemTask("", mesTask.ID);
                    }
                }
            }
            else
            {
                WMSHelper.addAlarmRecord("流程异常", "高", $"MES叫料任务{mesTask.ID},MES中间表没有该线边货位的叫料任务,请查看");
                responseResult.code = 1;
                responseResult.msg = "MES中间表没有该线边货位的叫料任务";
            }
            return responseResult;
        }
        /// <summary>
        /// WCS任务状态回报
        /// 任务状态 1:开始/执行中;完成;3:准备取货;4:取货完成;5:准备卸货;6:卸货完成;7:异常取消;8:强制完成
        /// 1.根据任务状态回报更新货位状态、任务状态
        /// 2.更新任务中间表状态
        /// 4.更新出库任务中间表状态
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult taskStatusFeedback(TaskStatusFeedbackModel model)
        {
            ResponseResult responseResult = new ResponseResult();
            WCSTask cst = WCSHelper.GetTask(model.taskNo);
            if (cst != null)
            {
                WMSTask mst = WMSHelper.GetWmsTask(cst.S_OP_CODE);
                if (mst != null)
                {
                    switch (model.status)
                    {
                        case 1:
                            WCSHelper.Begin(cst);
                            WMSHelper.updateMesTaskStatus(mst.S_CODE, "2");
                            if (cst.S_TYPE.Contains("出库"))
                            {
                                WMSHelper.addLotOutTask(mst.S_START_LOC);
                            }
                            break;
                        case 2:
                            WCSHelper.End(cst);
                            break;
                        case 3:
                            WCSHelper.UpdateStatus(cst, "准备取货");
                            break;
                        case 4:
                            WCSHelper.UpdateStatus(cst, "取货完成");
                            TaskProcess.OperateStatus(cst, 4);
                            break;
                        case 5:
                            WCSHelper.UpdateStatus(cst, "准备卸货");
                            break;
                        case 6:
                            WCSHelper.UpdateStatus(cst, "卸货完成");
                            TaskProcess.OperateStatus(cst, 6);
                            break;
                        case 7:
                            WCSHelper.UpdateStatus(cst, "异常取消");
                            TaskProcess.OperateStatus(cst, 7);
                            mst.N_B_STATE = 3;
                            WMSHelper.UpdateTaskState(mst);
                            WMSHelper.updateMesTaskStatus(mst.S_CODE, "5", "WCS异常取消任务");
                            WMSHelper.addAlarmRecord("流程异常", "高", $"WCS异常取消任务,任务号:{cst.S_CODE}");
                            break;
                        case 8:
                            WCSHelper.UpdateStatus(cst, "强制完成");
                            break;
                    }
                    // 添加WCS动作记录
                    WCSHelper.AddActionRecord(model.taskNo, model.status, model.deviceNo, model.loc);
                    if (model.status == 2 || model.status == 8)
                    {
                        if (cst.S_TYPE.Contains("入库"))
                        {
                            var cntrItemRels = ContainerHelper.GetCntrItemRel(cst.S_CNTR_CODE);
                            if (cntrItemRels != null && cntrItemRels.Count > 0)
                            {
                                foreach (var cntrItem in cntrItemRels)
                                {
                                    cntrItem.T_INBOUND_TIME = DateTime.Now;
                                    ContainerHelper.updateCntrItemRel(cntrItem);
                                }
                            }
                        }
                        if (cst.S_TYPE.Contains("【异常】"))
                        {
                            WCSHelper.ActivatePreCreateTask(mst.S_CODE, 1);
                        }
                        else
                        {
                            WCSHelper.ActivatePreCreateTask(mst.S_CODE);
                        }
                        if (WMSHelper.isFinishTask(mst.S_CODE))
                        {
                            // 更新作业任务状态
                            mst.N_B_STATE = 2;
                            mst.T_END_TIME = DateTime.Now;
                            WMSHelper.UpdateTaskState(mst);
                            // 更新任务中间表状态
                            WMSHelper.updateMesTaskStatus(mst.S_CODE, "3");
                            if (cst.S_TYPE.Contains("出库"))
                            {
                                // 更新出库任务中间表状态
                                WMSHelper.updateLotOutTask(cst.S_CNTR_CODE, "2");
                            }
                        }
                    }
                }
            }
            return responseResult;
        }
        /// <summary>
        /// WCS申请终点
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult applyDest(ApplyDestinationModel model) {
            ResponseResult result = new ResponseResult();
            ApplyDest applyDest = new ApplyDest();
            WCSTask cst = WCSHelper.GetTask(model.taskNo);
            if (cst != null && cst.N_B_STATE < 3)
            {
                WMSTask mst = WMSHelper.GetWmsTask(cst.S_OP_CODE);
                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) {
                        emptyFlag = 1;
                    }
                    // 1:堆垛机放货异常申请新终点
                    if (model.applyType == 1) {
                        // 报警:流程异常
                        WMSHelper.addAlarmRecord("流程异常", "低", $"堆垛机放货异常,异常货位:{cst.S_END_LOC}");
                        // 1.将异常货位上锁,并报警
                        LocationHelper.LockLoc(cst.S_END_LOC, 3);
                        // 2.查询新的入库终点
                        Location endLoc = WMSHelper.getInStockEndLoc(cst.S_END_AREA, emptyFlag);
                        cst.S_END_LOC = endLoc.S_CODE;
                        WCSHelper.UpdateEndLoc(cst);
                        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;
            return result;
        }
        /// <summary>
        /// AGV申请终点
        /// 顺序 RFID验证 -> RFID与任务号验证 -> 物料合格状态验证 -> 虚拟终点
        /// 申请类型: 1.虚拟终点 2.RFID与任务不匹配 3.物料状态不合格
        /// 入库策略:先计算库区的容积率,再计算库区对应的入库站台的任务数,都取最小的
        ///
        /// 1.确定任务是否在执行中
        /// 2.判断申请类型
        ///     1).虚拟终点,计算入库站台,同时预先生成入库站台-立库终点的搬运任务
        ///     2).RFID验证失败,记录异常,并计算异常区的空货位
        ///     3).RFID与任务不匹配,记录异常并报警,并计算异常区的空货位
        ///     4).物料状态不合格,记录异常,计算入库站台,同时预先生成入库站台-立库终点的搬运任务 ;最后重新生成新的出库任务
        ///
        /// 3.  2)\3) 异常区没有空货位,计算入库站台,同时预先生成入库站台-立库终点的搬运任务
        ///
        /// 4.余料/空工装回库任务
        ///     1).根据RFID查询中间表,判断物料类型,如为空工装,正常入库(计算入库站台,生成预创建搬运任务)
        ///     2).如是余料,查询是否有余料有关的叫料任务,且未执行,则取消叫料任务,修改终点为该叫料终点
        ///     3).如没有相关叫料任务,则正常入库
        ///
        /// 5.空工装出库和成型机叫料任务,当申请类型为2,3,4是,需要重新生成任务
        /// </summary>
        /// <param name="taskNo"></param>
        /// <param name="loc"></param>
        /// <param name="trayCode"></param>
        /// <param name="applyType">1.正常 2.异常</param>
        /// <returns></returns>
        public static string AGVApplyDest(string taskNo ,string loc ,string trayCode,string applyType)
        {
            LogHelper.Info($"AGV申请终点,任务号:{taskNo},当前位置:{loc},申请类型:{applyType}", "HosttoagvTask");
            string applyDest = null;
            try
            {
                WCSTask cst = WCSHelper.GetTask(taskNo);
                if (cst != null && cst.N_B_STATE < 3)
                {
                    WMSTask mst = WMSHelper.GetWmsTask(cst.S_OP_CODE);
                    if (mst != null && mst.N_B_STATE < 2)
                    {
                        // 防止重复申请
                        if ((applyType != "1" && !cst.S_TYPE.Contains("【异常】")) || (applyType == "1" && cst.S_END_LOC.Contains("虚拟货位")))
                        {
                            // 斜裁立库
                            if (mst.S_OP_DEF_NAME.Contains("斜裁"))
                            {
                                applyDest = applyAgvDestXC(applyType, mst, cst);
                            }
                            else
                            {
                                applyDest = applyAgvDest(applyType, loc, mst, cst);
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                WMSHelper.addAlarmRecord("系统错误","高", $"AGV申请终点,WMS内部错误,错误原因:{ex.Message}", "AGV");
            }
            return null;
        }
        /// <summary>
        /// 斜裁立库任务,AGV申请终点
        ///   1).根据RFID查询中间表,判断物料类型,如为空工装,正常入库(计算入库站台,生成预创建搬运任务)
        ///   2).如是余料,查询是否有余料有关的叫料任务,且未执行,则取消叫料任务,修改终点为该叫料终点
        /// </summary>
        /// <param name="applyType"></param>
        /// <param name="mst"></param>
        /// <param name="cst"></param>
        /// <returns></returns>
        public static string applyAgvDestXC(string applyType, WMSTask mst, WCSTask cst)
        {
            string destLoc = null;
            Location agvEndLoc = null;
            Location wmsEndLoc = null;
            if (applyType == "1")
            {
                if (mst.S_TYPE == "余料/空工装入库")
                {
                    var mesTask = WMSHelper.GetLjMesTaskById(int.Parse(mst.S_OP_DEF_CODE));
                    if (mesTask.QTY != 0)
                    {
                        var awaitTask = WMSHelper.GetAwaitWmsTaskByMaterialCode(mesTask.MATERIAL_CODE);
                        if (awaitTask != null)
                        {
                            // 取消任务
                            ApiHelper.cancelTask(awaitTask.S_CODE);
                            // 修改终点
                            agvEndLoc = LocationHelper.GetLoc(awaitTask.S_END_LOC);
                            wmsEndLoc = agvEndLoc;
                            mst.S_TYPE = "叫料出库任务";
                        }
                    }
                }
            }
            if (agvEndLoc == null)
            {
                string msg = "";
                if (applyType == "2" || applyType == "3" || applyType == "4")
                {
                    cst.S_TYPE = cst.S_TYPE + "【异常】";
                    msg = "工装异常";
                }
                // TODO 反馈斜裁立库异常,请求斜裁入库终点
                agvEndLoc = null;
            }
            if (agvEndLoc != null)
            {
                destLoc = agvEndLoc.S_CODE;
                cst.S_END_LOC = agvEndLoc.S_CODE;
                cst.S_END_AREA = agvEndLoc.S_AREA_CODE;
                WCSHelper.UpdateEndLoc(cst);
            }
            if (wmsEndLoc != null)
            {
                mst.S_END_LOC = wmsEndLoc.S_CODE;
                mst.S_END_AREA = wmsEndLoc.S_AREA_CODE;
                WMSHelper.UpdateTaskEnd(mst);
            }
            return destLoc;
        }
        /// <summary>
        /// AGV申请终点
        /// 场景:1.余料/空工装入库任务(成型机) 2.满料/空工装入库(机台) 3.满料/空工装出库异常 4.满料/空工装入库异常
        /// </summary>
        /// <param name="applyType">1.正常 2.RFID与任务RFID不匹配 3.物料状态不合格</param>
        /// <param name="loc"></param>
        /// <param name="mst"></param>
        /// <param name="cst"></param>
        /// <returns></returns>
        public static string applyAgvDest(string applyType,string loc, WMSTask mst, WCSTask cst)
        {
            LogHelper.Info($"开始申请AGV终点", "AGV");
            string destLoc = null;
            Location agvEndLoc = null;
            Location wmsEndLoc = null;
            Location currentLoc = LocationHelper.GetLoc(loc);
            // RFID 检测正常
            if (applyType == "1")
            {
                // 场景:1.余料/空工装入库任务
                // 1).根据RFID查询中间表,判断物料类型,如为空工装,正常入库(计算入库站台,生成预创建搬运任务)
                // 2).如是余料,查询是否有余料有关的叫料任务,且未执行,则取消叫料任务,修改终点为该叫料终点
                if (cst.S_TYPE.Contains("余料/空工装入库"))
                {
                    LogHelper.Info($"余料/空工装入库任务,判断是否回库或发往叫料点", "AGV");
                    var mesTask = WMSHelper.GetLjMesTaskById(int.Parse(mst.S_OP_DEF_CODE));
                    if (mesTask.QTY != 0)
                    {
                        var awaitTask = WMSHelper.GetAwaitWmsTaskByMaterialCode(mesTask.MATERIAL_CODE);
                        if (awaitTask != null)
                        {
                            LogHelper.Info($"余料/空工装入库任务,存在等待的叫料任务,发往叫料点", "AGV");
                            // 取消任务
                            ApiHelper.cancelTask(awaitTask.S_CODE);
                            // 修改终点
                            agvEndLoc = LocationHelper.GetLoc(awaitTask.S_END_LOC);
                            cst.S_TYPE = "叫料出库任务";
                            mst.S_TYPE = mst.S_TYPE + "【叫料】";
                        }
                    }
                }
                // 场景:1.满料/空工装入库 2.余料/空工装入库
                if (agvEndLoc == null && cst.S_TYPE.Contains("入库"))
                {
                    LogHelper.Info($"如没有满足条件的agv终点货位,则发往立库", "AGV");
                    Container container = ContainerHelper.GetCntr(cst.S_CNTR_CODE);
                    if (container != null)
                    {
                        wmsEndLoc = WMSHelper.getInStockEndLoc(null, container.N_DETAIL_COUNT == 0 ? 0 : 1, container.N_TYPE);
                        if (wmsEndLoc != null)
                        {
                            agvEndLoc = WMSHelper.GetMinTaskTransfeLoc(wmsEndLoc.S_AREA_CODE, 1, 2);  // 1.立库接驳位 1.入库 2.非直连
                            if (agvEndLoc != null)
                            {
                                LogHelper.Info($"创建立库站台到立库的预创建任务,agv终点货位:{agvEndLoc.S_CODE},立库终点货位:{wmsEndLoc.S_CODE}", "AGV");
                                // 预先生成入库站台-立库终点的搬运任务
                                WCSTask wcsTask = new WCSTask()
                                {
                                    S_OP_NAME = mst.S_OP_DEF_NAME,
                                    S_OP_CODE = mst.S_CODE,
                                    S_CODE = WCSHelper.GenerateTaskNo(),
                                    S_CNTR_CODE = cst.S_CNTR_CODE,
                                    S_TYPE = mst.S_TYPE,
                                    S_START_LOC = agvEndLoc.S_CODE,
                                    S_START_AREA = agvEndLoc.S_AREA_CODE,
                                    S_END_LOC = wmsEndLoc.S_CODE,
                                    S_END_AREA = wmsEndLoc.S_AREA_CODE,
                                    S_SCHEDULE_TYPE = "WCS",
                                    N_PRIORITY = 10,
                                    N_B_STATE = -1,
                                    T_START_TIME = DateTime.Now,
                                };
                                if (WCSHelper.CreateTask(wcsTask))
                                {
                                    // 起点、终点加锁
                                    LocationHelper.LockLoc(wcsTask.S_START_LOC, 1);
                                    LocationHelper.LockLoc(wcsTask.S_END_LOC, 1);
                                }
                            }
                            else
                            {
                                WMSHelper.addAlarmRecord("流程异常", "高", $"AGV申请终点失败,未查询到立库接驳位");
                                return null;
                            }
                        }
                        else
                        {
                            WMSHelper.addAlarmRecord("流程异常", "高", $"AGV申请终点失败,未查询到空余立库货位");
                            return null;
                        }
                    }
                    else
                    {
                        WMSHelper.addAlarmRecord("流程异常", "高", $"AGV申请终点失败,未查询到容器编码:{cst.S_CNTR_CODE}的容器");
                        return null;
                    }
                }
            }
            // 场景:1.满料/空工装出库异常 2.满料/空工装入库异常(空工装出库异常 、满料入库异常)
            if (applyType == "2" )
            {
                WCSHelper.CancelPreCreateTask(mst.S_CODE);
                mst.S_TYPE = mst.S_TYPE + "【异常】";
                // 1.异常工装优先发往异常区
                LogHelper.Info($"异常工装优先发往异常区", "AGV");
                agvEndLoc = WMSHelper.getAbnormalAreaLoc(currentLoc.S_AREA_CODE);
                if (agvEndLoc != null)
                {
                    wmsEndLoc = agvEndLoc;
                }
                else
                {
                    LogHelper.Info($"异常区没有空货位,发往立库", "AGV");
                }
                // 2.异常区没有空货位,则发往立库
                if (agvEndLoc == null)
                {
                    LogHelper.Info($"如没有满足条件的agv终点货位,则发往立库", "AGV");
                    Container container = ContainerHelper.GetCntr(cst.S_CNTR_CODE);
                    if (container != null)
                    {
                        wmsEndLoc = WMSHelper.getInStockEndLoc(null, container.N_DETAIL_COUNT == 0 ? 0 : 1, container.N_TYPE);
                        if (wmsEndLoc != null)
                        {
                            agvEndLoc = WMSHelper.GetMinTaskTransfeLoc(wmsEndLoc.S_AREA_CODE, 1, 2);  // 1.立库接驳位 1.入库 2.非直连
                            if (agvEndLoc != null)
                            {
                                LogHelper.Info($"创建立库站台到立库的预创建任务,agv终点货位:{agvEndLoc.S_CODE},立库终点货位:{wmsEndLoc.S_CODE}", "AGV");
                                // 预先生成入库站台-立库终点的搬运任务
                                WCSTask wcsTask = new WCSTask()
                                {
                                    S_OP_NAME = mst.S_OP_DEF_NAME,
                                    S_OP_CODE = mst.S_CODE,
                                    S_CODE = WCSHelper.GenerateTaskNo(),
                                    S_CNTR_CODE = cst.S_CNTR_CODE,
                                    S_TYPE = cst.S_TYPE + "【异常】",
                                    S_START_LOC = agvEndLoc.S_CODE,
                                    S_START_AREA = agvEndLoc.S_AREA_CODE,
                                    S_END_LOC = wmsEndLoc.S_CODE,
                                    S_END_AREA = wmsEndLoc.S_AREA_CODE,
                                    S_SCHEDULE_TYPE = "WCS",
                                    N_PRIORITY = 10,
                                    N_B_STATE = -1,
                                    S_B_STATE = "预创建",
                                    T_START_TIME = DateTime.Now,
                                };
                                if (WCSHelper.CreateTask(wcsTask))
                                {
                                    // 起点、终点加锁
                                    LocationHelper.LockLoc(wcsTask.S_START_LOC, 1);
                                    LocationHelper.LockLoc(wcsTask.S_END_LOC, 1);
                                    cst.S_TYPE = cst.S_TYPE + "【异常】";
                                }
                            }
                            else
                            {
                                WMSHelper.addAlarmRecord("流程异常", "高", $"AGV申请终点失败,未查询到立库接驳位");
                                return null;
                            }
                        }
                        else
                        {
                            WMSHelper.addAlarmRecord("流程异常", "高", $"AGV申请终点失败,未查询到空余立库货位");
                            return null;
                        }
                    }
                    else
                    {
                        WMSHelper.addAlarmRecord("流程异常", "高", $"AGV申请终点失败,未查询到容器编码:{cst.S_CNTR_CODE}的容器");
                        return null;
                    }
                }
            }
            if (agvEndLoc != null && wmsEndLoc != null)
            {
                destLoc = agvEndLoc.S_CODE;
                cst.S_END_LOC = agvEndLoc.S_CODE;
                cst.S_END_AREA = agvEndLoc.S_AREA_CODE;
                WCSHelper.UpdateEndLoc(cst);
                mst.S_END_LOC = wmsEndLoc.S_CODE;
                mst.S_END_AREA = wmsEndLoc.S_AREA_CODE;
                WMSHelper.UpdateTaskEnd(mst);
            }
            // 重新发起新任务
            if (applyType != "1")
            {
                var mesTask = WMSHelper.GetLjMesTaskByAgvorderId(mst.S_CODE);
                if (mesTask != null)
                {
                    if (mst.S_TYPE.Contains("叫料出库任务"))
                    {
                        LogHelper.Info($"叫料出库任务异常,再次发起叫料出库任务", "AGV");
                        callMaterial(mesTask.MATERIAL_CODE, mesTask.POSITION_ID, mesTask.ID);
                    }
                    // 满料下线(非直连)
                    if (mst.S_TYPE.Contains("满料/异常工装入库任务") && cst.S_TYPE.Contains("空工装出库任务"))
                    {
                        LogHelper.Info($"满料/异常工装入库任务异常,再次发起满料/异常工装入库任务", "AGV");
                        var logicConfig = WMSHelper.getLogicConfigByJtCode(mesTask.EQP);
                        if (logicConfig != null)
                        {
                            triggerItemOffLineFlow4(mesTask.POSITION_ID, mst.S_CNTR_CODE, logicConfig ,mesTask);
                        }
                        else
                        {
                            WMSHelper.addAlarmRecord("流程异常", "高", $"MES任务{mesTask.ID},机台号:{mesTask.EQP},未查询到逻辑线路", "AGV");
                        }
                    }
                }
            }
            return destLoc;
        }
        /// <summary>
        /// 成新机叫料
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="endLocCode"></param>
        /// <param name="mesTaskId"></param>
        public static void callMaterial(string materialCode, string endLocCode, int mesTaskId)
        {
            var oldWmsTask = WMSHelper.GetWmsTaskByEnd(endLocCode);
            if (oldWmsTask == null) {
                string cntrCode = "";
                Location endLoc = LocationHelper.GetLoc(endLocCode);
                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
                    {
                        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.创建成新机叫料作业
                        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 + "-WCS",
                                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}未查询到可用的接驳位");
                    }
                }
            }
        }
        /// <summary>
        /// 成新机叫料(环带库)
        /// 1.查询环带库物料库存
        /// 2.查询中转库库存,根据入库时间 进行先入先出
        /// 3.如果为环带库物料,则将mes任务写入环带库任务中间表
        /// </summary>
        /// <param name="materialCode"></param>
        /// <param name="endLocCode"></param>
        /// <param name="mesTaskId"></param>
        public static void callMaterialHDK(string materialCode, string endLocCode, int mesTaskId)
        {
            // 1.查询环带库物料库存
            // 2.查询中转库库存,根据入库时间 进行先入先出
            // 3.将MES任务写入环带库任务中间表
            WMSHelper.addLjXcTask(mesTaskId);
        }
        /// <summary>
        /// 余料/空托回库
        ///
        /// 1.查询成型机叫料终点对应的 余料/空托返回位
        /// 2.查询mes任务中间表是否存在返料任务
        /// 3.创建余料回库作业,创建agv搬运任务,虚拟终点
        /// </summary>
        /// <param name="locCode">成型机叫料终点</param>
        public static void returnMaterialOrEmptyTray(string locCode)
        {
            if (locCode != null)
            {
                // 2.查询mes任务中间表
                var mesTask = WMSHelper.getLjMesTaskByLoc(locCode);
                if (mesTask != null)
                {
                    createReturnTask(locCode, mesTask);
                }
            }
        }
        /// <summary>
        /// 创建余料/空工装返回任务
        /// </summary>
        /// <param name="locCode"></param>
        /// <param name="mesTask"></param>
        public static void createReturnTask(string locCode ,LjMesTask mesTask) {
            Location startLoc = LocationHelper.GetLoc(locCode);
            Location endLoc = new Location() { S_CODE = "虚拟货位", S_AREA_CODE = "虚拟库区" };
            string suffix = "";
            if (mesTask.PALLET_TYPE == "5" || mesTask.PALLET_TYPE == "6") {
                suffix = "(斜裁)";
            }
            var wmsTask = new WMSTask()
            {
                S_CNTR_CODE = mesTask.PALLET_ID,
                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 = "余料/空工装入库任务" + suffix,
                S_OP_DEF_CODE = mesTask.ID.ToString(),
                S_OP_DEF_NAME = "余料/空工装入库" + suffix,
                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 = endLoc.S_CODE,
                    S_END_AREA = endLoc.S_AREA_CODE,
                    S_SCHEDULE_TYPE = "AGV",
                    N_PRIORITY = 99,
                    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);
                    WMSHelper.readLjMesOffItemTask(wmsTask.S_CODE, mesTask.ID);
                }
            }
        }
        /// <summary>
        /// 不合格品回库
        /// 1.创建回库任务
        /// 2.重新发起新的叫料任务
        /// </summary>
        /// <param name="mst"></param>
        /// <param name="cst"></param>
        /// <returns></returns>
        public static bool rejectReturnStock(WMSTask mst, WCSTask cst)
        {
            bool result = true;
            Location startLoc = LocationHelper.GetLoc(cst.S_END_LOC);
            Location agvEndLoc = null;
            Location wmsEndLoc = null;
            // 斜裁立库
            if (mst.S_OP_DEF_NAME.Contains("斜裁"))
            {
                // TODO 反馈斜裁立库异常,请求斜裁入库终点
                agvEndLoc = null;
                wmsEndLoc = agvEndLoc;
                if (agvEndLoc != null)
                {
                    // 预先生成入库站台-立库终点的搬运任务
                    WCSTask wcsTask = new WCSTask()
                    {
                        S_OP_NAME = mst.S_OP_DEF_NAME,
                        S_OP_CODE = mst.S_CODE,
                        S_CODE = WCSHelper.GenerateTaskNo(),
                        S_CNTR_CODE = cst.S_CNTR_CODE,
                        S_TYPE = "不合格品回库",
                        S_START_LOC = startLoc.S_CODE,
                        S_START_AREA = startLoc.S_AREA_CODE,
                        S_END_LOC = agvEndLoc.S_CODE,
                        S_END_AREA = agvEndLoc.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, 1);
                        LocationHelper.LockLoc(wcsTask.S_END_LOC, 1);
                    }
                }
            }
            else
            {
                Container container = ContainerHelper.GetCntr(cst.S_CNTR_CODE);
                wmsEndLoc = WMSHelper.getInStockEndLoc(null, container.N_DETAIL_COUNT == 0 ? 0 : 1, container.N_TYPE);
                if (wmsEndLoc != null)
                {
                    agvEndLoc = WMSHelper.GetMinTaskTransfeLoc(wmsEndLoc.S_AREA_CODE, 1, 2);  // 1.立库接驳位 1.入库 2.非直连
                    if (agvEndLoc != null)
                    {
                        // 预先生成入库站台-立库终点的搬运任务
                        WCSTask oneWcsTask = new WCSTask()
                        {
                            S_OP_NAME = mst.S_OP_DEF_NAME,
                            S_OP_CODE = mst.S_CODE,
                            S_CODE = WCSHelper.GenerateTaskNo(),
                            S_CNTR_CODE = cst.S_CNTR_CODE,
                            S_TYPE = "不合格品回库",
                            S_START_LOC = startLoc.S_CODE,
                            S_START_AREA = startLoc.S_AREA_CODE,
                            S_END_LOC = agvEndLoc.S_CODE,
                            S_END_AREA = agvEndLoc.S_AREA_CODE,
                            S_SCHEDULE_TYPE = "AGV",
                            N_PRIORITY = 10,
                            T_START_TIME = DateTime.Now,
                        };
                        if (WCSHelper.CreateTask(oneWcsTask))
                        {
                            // 起点、接驳点、终点加锁
                            LocationHelper.LockLoc(oneWcsTask.S_START_LOC, 1);
                            LocationHelper.LockLoc(oneWcsTask.S_END_LOC, 1);
                        }
                        // 预先生成入库站台-立库终点的搬运任务
                        WCSTask twoWcsTask = new WCSTask()
                        {
                            S_OP_NAME = mst.S_OP_DEF_NAME,
                            S_OP_CODE = mst.S_CODE,
                            S_CODE = WCSHelper.GenerateTaskNo(),
                            S_CNTR_CODE = cst.S_CNTR_CODE,
                            S_TYPE = "不合格品回库",
                            S_START_LOC = agvEndLoc.S_CODE,
                            S_START_AREA = agvEndLoc.S_AREA_CODE,
                            S_END_LOC = wmsEndLoc.S_CODE,
                            S_END_AREA = wmsEndLoc.S_AREA_CODE,
                            S_SCHEDULE_TYPE = "WCS",
                            N_PRIORITY = 10,
                            N_B_STATE = -1,
                            T_START_TIME = DateTime.Now,
                        };
                        if (WCSHelper.CreateTask(twoWcsTask))
                        {
                            // 起点、接驳点、终点加锁
                            LocationHelper.LockLoc(twoWcsTask.S_START_LOC, 1);
                            LocationHelper.LockLoc(twoWcsTask.S_END_LOC, 1);
                        }
                    }
                }
                if (cst.S_TYPE == "叫料出库任务")
                {
                    var mesTask = WMSHelper.GetLjMesTaskByAgvorderId(mst.S_CODE);
                    callMaterial( mesTask.MATERIAL_CODE, mesTask.POSITION_ID, mesTask.ID);
                }
            }
            return result;
        }
        /// <summary>
        /// 查询容器物料信息(中间表)
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult findTrayItemInfo(FindTrayItemInfoModel model) {
            ResponseResult responseResult = new ResponseResult();
            var cntrItemRels = ContainerHelper.GetCntrItemRel(model.cntrNo);
            if (cntrItemRels != null && cntrItemRels.Count > 0) {
                TrayItemInfo trayItemInfo = new TrayItemInfo()
                {
                    S_SERIAL_NO = cntrItemRels[0].S_SERIAL_NO,
                    S_ITEM_CODE = cntrItemRels[0].S_ITEM_CODE,
                    S_ITEM_NAME = cntrItemRels[0].S_ITEM_NAME,
                    S_ITEM_SPEC = cntrItemRels[0].S_ITEM_SPEC,
                    S_ITEM_STATE = cntrItemRels[0].S_ITEM_STATE,
                    N_ITEM_STATE = cntrItemRels[0].N_ITEM_STATE,
                    S_BATCH_NO = cntrItemRels[0].S_BATCH_NO,
                    F_QTY = cntrItemRels[0].F_QTY,
                    S_UOM = cntrItemRels[0].S_UOM,
                    S_CNTR_CODE = cntrItemRels[0].S_CNTR_CODE,
                    D_PRD_DATE = cntrItemRels[0].D_PRD_DATE,
                    D_EXP_DATE = cntrItemRels[0].D_EXP_DATE,
                    D_EXP_DATE1 = cntrItemRels[0].D_EXP_DATE1,
                };
                responseResult.data = trayItemInfo;
            }
            return responseResult;
        }
        /// <summary>
        /// 设备报警反馈
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult notifyAlarm(DeviceAlertorFeedbackModel model) {
            ResponseResult responseResult = new ResponseResult();
            WMSHelper.addAlarmRecord("设备故障", "高", $"设备号{model.deviceNo},错误信息:"+model.errMsg);
            return responseResult;
        }
        /// <summary>
        /// 人工手动入库
        /// 2.根据容器号查询入库任务
        /// 3.如果没有入库任务,记录异常
        /// 4.进行入库
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult manualStorage(ManualStorageModel model)
        {
            ResponseResult responseResult = new ResponseResult();
            // 查询中间表
            var ljMesTask = WMSHelper.getLjMesTaskByCntr( model.cntrNo);
            if (ljMesTask == null)
            {
                responseResult.code = 1;
                responseResult.msg = "未查询到MES下发的入库任务";
                return responseResult;
            }
            string taskType = "";
            if (ljMesTask.QTY == 0)
            {
                taskType = "空工装人工入库";
            }
            else {
                taskType = "满料工装人工入库";
            }
            var startLoc = LocationHelper.GetLoc(model.from);
            var transfeRele = WMSHelper.GetTransfeRelevance(model.from); // 接驳位属性
            if (transfeRele != null)
            {
                var endLoc = WMSHelper.getInStockEndLoc(transfeRele.S_RELE_AREA, ljMesTask.QTY);
                if (startLoc == null)
                {
                    responseResult.code = 1;
                    responseResult.msg = "接驳位不存在,请检查起点货位编码是否有误";
                    return responseResult;
                }
                if (endLoc == null)
                {
                    responseResult.code = 1;
                    responseResult.msg = "立库空余库位不足";
                    return responseResult;
                }
                var wmsTask = new WMSTask()
                {
                    S_CNTR_CODE = model.cntrNo,
                    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 = taskType,
                    S_OP_DEF_CODE = ljMesTask.ID.ToString(),
                    S_OP_DEF_NAME = "人工入库任务",
                    N_PRIORITY = 1,
                    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 + "-WCS",
                        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 = "WCS",
                        N_PRIORITY = wmsTask.N_PRIORITY,
                        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);
                        WMSHelper.readLjMesOffItemTask(wmsTask.S_CODE ,ljMesTask.ID);
                    }
                }
            }
            else
            {
                WMSHelper.addAlarmRecord("流程异常", "中", $"接驳位:{model.from},缺少属性配置项,请联系管理进行配置");
                responseResult.code = 1;
                responseResult.msg = $"接驳位缺少属性配置项,请联系管理进行配置";
            }
            return responseResult;
        }
        /// <summary>
        /// 人工出库
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult manualDelivery(ManualDeliveryModel model) {
            ResponseResult responseResult = new ResponseResult();
            // 查询中间表
            var ljMesTask = WMSHelper.getLjMesTaskByLoc(model.to);
            if (ljMesTask == null)
            {
                responseResult.code = 1;
                responseResult.msg = "未查询到MES任务表数据";
                return responseResult;
            }
            string taskType = "";
            if (ljMesTask.QTY == 0)
            {
                taskType = "空工装人工出库";
            }
            else
            {
                taskType = "满料工装人工出库";
            }
            var endLoc = LocationHelper.GetLoc(model.to);
            var transfeRele = WMSHelper.GetTransfeRelevance(model.to);  // 接驳位属性
            if (transfeRele != null)
            {
                var startLoc = WMSHelper.getOutStockStartLoc(transfeRele.S_RELE_AREA, model.materialCode,model.trayStatus, model.cntrNo);
                if (endLoc == null)
                {
                    responseResult.code = 1;
                    responseResult.msg = "接驳位不存在,请检查起点货位编码是否有误";
                    return responseResult;
                }
                if (startLoc == null)
                {
                    responseResult.code = 1;
                    responseResult.msg = "立库库存不足";
                    return responseResult;
                }
                var wmsTask = new WMSTask()
                {
                    S_CNTR_CODE = model.cntrNo,
                    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 = taskType,
                    S_OP_DEF_NAME = "人工出库任务",
                    N_PRIORITY = 1,
                    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 + "-WCS",
                        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 = "WCS",
                        N_PRIORITY = wmsTask.N_PRIORITY,
                        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);
                        WMSHelper.readLjMesOffItemTask(wmsTask.S_CODE, ljMesTask.ID);
                    }
                }
            }
            else {
                WMSHelper.addAlarmRecord("流程异常", "中", $"接驳位:{model.to},缺少属性配置项,请联系管理进行配置");
                responseResult.code = 1;
                responseResult.msg = $"接驳位缺少属性配置项,请联系管理进行配置";
            }
            return responseResult;
        }
        /// <summary>
        /// 取消任务
        /// </summary>
        /// <param name="taskNo"></param>
        public static ResponseResult cancelTask(string taskNo) {
            ResponseResult responseResult = new ResponseResult();
            WMSTask wmsTask = WMSHelper.GetWmsTask(taskNo);
            if (wmsTask != null && wmsTask.N_B_STATE == 0)
            {
                var wcsTaskList = WCSHelper.GetTaskListBySrcNo(wmsTask.S_CODE);
                foreach (var wcsTask in wcsTaskList)
                {
                    if (wcsTask != null && wcsTask.N_B_STATE < 3)
                    {
                        WCSHelper.Fail(wcsTask);
                        LocationHelper.UnLockLoc(wcsTask.S_START_LOC);
                        LocationHelper.UnLockLoc(wcsTask.S_END_LOC);
                    }
                }
                wmsTask.N_B_STATE = 3;
                wmsTask.S_B_STATE = "取消";
                wmsTask.T_END_TIME = DateTime.Now;
                WMSHelper.UpdateTaskState(wmsTask);
            }
            return responseResult;
        }
        /// <summary>
        /// 切换站台属性
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static ResponseResult switchStationAttribute(SwitchStationAttributeModel model)
        {
            ResponseResult responseResult = new ResponseResult();
            var task = WCSHelper.GetTaskByStartOrEnd(model.locCode);
            if (task == null)
            {
                var transfeRelevance = WMSHelper.GetTransfeRelevance(model.locCode);  // 接驳位属性
                LogHelper.Info($"原站台属性:{JsonConvert.SerializeObject(transfeRelevance)}", "WMS");
                if (transfeRelevance != null && transfeRelevance.N_PROPERTY == 2)
                {
                    if (model.signalType == "1")
                    {
                         WMSHelper.updateTransfeLocProperty(model.locCode, 0);
                    }
                    if (model.signalType == "2")
                    {
                        WMSHelper.updateTransfeLocProperty(model.locCode, 1);
                    }
                }
            }
            else
            {
                responseResult.code = 1;
                responseResult.msg = "接驳位存在未完成的任务,无法切换站台属性";
            }
            return responseResult;
        }
        /// <summary>
        /// 货位状态反馈
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public static bool locStateFeedBack(LocStateFeedBackModel model)
        {
            bool result = false;
            if (model.type == "1")
            {
               var task  = WCSHelper.GetTask(model.req_no);
                if (task != null)
                {
                    TaskAction taskAction = null;
                    if (model.type == "1")
                    {
                        taskAction = WCSHelper.getActionRecord(task.S_CODE, 1101);
                    }
                    if (model.type == "2")
                    {
                        taskAction = WCSHelper.getActionRecord(task.S_CODE, 1102);
                    }
                    if (taskAction != null)
                    {
                        taskAction.N_S_STATUS = 1;
                        result = WCSHelper.updateActionRecord(taskAction);
                    }
                }
            }
            return result;
        }
        //----------------------------------------------------------------------------------------------------------------------------
        public class LocModel
        {
            public string locCode { get; set; }
        }
        public class ApplyDest {
            public string destLoc { get; set; } // 终点货位编码
        }
        public class TrayItemInfo
        {
            public string S_SERIAL_NO { get; set; } // 原材料批次号
            public string S_ITEM_CODE { get; set; } // 物料编码
            public string S_ITEM_NAME { get; set; } // 物料编码
            public string S_ITEM_SPEC { get; set; } // 规格
            public string S_ITEM_STATE { get; set; } = "0"; // 检验状态 0:未检验 1:合格,2:不合格
            /// <summary>
            /// 1:合格 2:不合格
            /// </summary>
            public int N_ITEM_STATE { get; set; } // 物料状态
            public string S_BATCH_NO { get; set; }   // 批次条码
            public float F_QTY { get; set; }  // 数量
            public string S_UOM { get; set; } = "";  // 单位
            public string S_CNTR_CODE { get; set; } // 容器
            public string D_PRD_DATE { get; set; } // 生产日期
            public string D_EXP_DATE { get; set; } // 最小停放日期
            public string D_EXP_DATE1 { get; set; } // 最大停放日期
        }
        /// <summary>
        /// 人工出库模型
        /// </summary>
        public class ManualDeliveryModel {
            public string to { get; set; } // 接驳货位编码
            public string cntrNo { get; set; } // 容器号
            public int trayStatus { get; set; } // 托盘状态 0.正常 1.异常
            public string materialCode { get; set; } // 物料编号  物料编码为空,表示空工装
        }
        /// <summary>
        /// 人工入库模型
        /// </summary>
        public class ManualStorageModel {
            public string from { get; set; } // 起点
            public string cntrNo { get; set; } // 容器号
        }
        /// <summary>
        /// 设备报警反馈模型
        /// </summary>
        public class DeviceAlertorFeedbackModel {
            public string reqId { get; set; }
            public string reqTime { get; set; }
            public string deviceNo { get; set; } // 设备号
            public string errCode { get; set; } // 错误码
            public string errMsg { get; set; } // 错误信息
        }
        /// <summary>
        /// 获取托盘物料信息模型
        /// </summary>
        public class FindTrayItemInfoModel {
            public string reqId { get; set; }
            public string reqTime { get; set; }
            public string cntrNo { get; set; } // 托盘号
        }
        /// <summary>
        /// 申请终点模型
        /// </summary>
        public class ApplyDestinationModel {
            public string reqId { get; set; }
            public string reqTime { get; set; }
            public string taskNo { get; set; } // 任务号
            public string loc { get; set; } // 当前货位
            public int applyType { get; set; } // 申请类型 1:堆垛机放货异常申请新终点;2:输送线到达接驳位申请终点;3:
        }
        public class AGVApplyDestModel{
            public string taskNo { get; set; } // 任务号
            public string loc { get; set; } // 当前货位
            public string trayCode { get; set; } // 托盘码(RFID)
            public string applyType { get; set; } // 1.虚拟终点 2.RFID验证失败 3.RFID与任务不匹配 4.物料状态不合格
        }
        /// <summary>
        /// 任务状态反馈模型
        /// </summary>
        public class TaskStatusFeedbackModel {
            public string reqId { get; set; }
            public string reqTime { get; set; }
            public string taskNo { get; set; } // 任务号
            public string subTaskNo { get; set; } // 子任务号
            public int status { get; set; } // 任务状态 1:开始/执行中;2:完成;3:准备取货;4:取货完成;5:准备卸货;6:卸货完成;7:异常取消;8:强制完成
            public string deviceNo { get; set; } // 设备号
            public string errCode { get; set; } // 异常代码  0.无异常 1.设备故障码、2.rfid校验失败、3.取货无货、4.放货有货
            public string loc { get; set; } // 当前货位
        }
        /// <summary>
        /// 设备信号反馈模型
        /// </summary>
        public class DeviceSignalFeedbackModel
        {
            public string reqId { get; set; }
            public string reqTime { get; set; }
            public string taskNo { get; set; } // 托盘号
            public string loc { get; set; } // 货位 上料点、下料点、读码位、称重位(必填)
            public string cntrNo { get; set; } // 托盘号
            public int signalType { get; set; } //请求类型 1:下线请求 2:叫料请求 3:读码请求(必填)
            public string deviceNo { get; set; } //设备号
            public object extData { get; set; }
        }
        /// <summary>
        /// 叫料请求
        /// </summary>
        public class CallMaterialRequest
        {
            public string loc { get; set; } // 货位 上料点、下料点、读码位、称重位(必填)
        }
        /// <summary>
        /// 下线请求
        /// </summary>
        public class OffLineRequest
        {
            public string loc { get; set; } // 货位 上料点、下料点、读码位、称重位(必填)
            public string cntrNo { get; set; } // 托盘号
            public string jtNo { get; set; } // 机台号
            public bool isNormal { get; set; } //是否异常
        }
        /// <summary>
        /// 读码请求
        /// </summary>
        public class ReadCodeRequest
        {
            public string loc { get; set; } // 货位 上料点、下料点、读码位、称重位(必填)
            public string cntrNo { get; set; } // 托盘号
            public string taskNo { get; set; } // 任务号
        }
        public class AddTaskModel {
            public string From { get; set; }
            public string To { get; set; }
            public string No { get; set; }
        }
        public class TN_LocationModel {
            public string TN_Location { get; set; }
        }
        public class CodeInfo {
            /// <summary>
            /// 生产订单内码
            /// </summary>
            public string FInterID { get; set; }
            /// <summary>
            /// 生产订单编号
            /// </summary>
            public string FSourceNo { get; set; }
            /// <summary>
            /// 批号
            /// </summary>
            public string FGMPBatchNo { get; set; }
            public string FState { get; set; }
            /// <summary>
            /// 物料编码(内码就是编码)
            /// </summary>
            public string Fitemid_XK { get; set; }
            /// <summary>
            /// 分录id
            /// </summary>
            public string Fentryid { get; set; }
        }
        public class NoteInfo : CodeInfo {
            public string WmsBillNo { get; set; }
        }
    }
}